diff --git a/cmd/root.go b/cmd/root.go index fb82adb6..616ab129 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -46,7 +46,9 @@ GitHub: https://github.com/httprunner/httprunner Copyright © 2017-present debugtalk. Apache-2.0 License.`, PersistentPreRun: func(cmd *cobra.Command, args []string) { - hrp.InitLogger(logLevel, logJSON) + // For report command, don't create log files to avoid creating directories + enableLogFile := cmd.Name() != "report" + hrp.InitLogger(logLevel, logJSON, enableLogFile) }, Version: version.GetVersionInfo(), TraverseChildren: true, // parses flags on all parents before executing child command diff --git a/internal/config/config.go b/internal/config/config.go index e7b7d3b3..89a42a11 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -21,12 +21,13 @@ const ( type Config struct { RootDir string ResultsDir string - ResultsPath string - DownloadsPath string - ScreenShotsPath string + resultsPath string + downloadsPath string + screenShotsPath string StartTime time.Time ActionLogFilePath string DeviceActionLogFilePath string + mu sync.Mutex } var ( @@ -48,25 +49,58 @@ func GetConfig() *Config { startTimeStr := cfg.StartTime.Format("20060102150405") cfg.ResultsDir = filepath.Join(ResultsDirName, startTimeStr) - cfg.ResultsPath = filepath.Join(cfg.RootDir, cfg.ResultsDir) - cfg.DownloadsPath = filepath.Join(cfg.RootDir, filepath.Join(DownloadsDirName, startTimeStr)) - cfg.ScreenShotsPath = filepath.Join(cfg.ResultsPath, ScreenshotsDirName) + cfg.resultsPath = filepath.Join(cfg.RootDir, cfg.ResultsDir) + cfg.downloadsPath = filepath.Join(cfg.RootDir, filepath.Join(DownloadsDirName, startTimeStr)) + cfg.screenShotsPath = filepath.Join(cfg.resultsPath, ScreenshotsDirName) cfg.ActionLogFilePath = filepath.Join(cfg.ResultsDir, ActionLogDirName) cfg.DeviceActionLogFilePath = "/sdcard/Android/data/io.appium.uiautomator2.server/files/hodor" - // create results directory - if err := builtin.EnsureFolderExists(cfg.ResultsPath); err != nil { - log.Fatal().Err(err).Msg("create results directory failed") - } - if err := builtin.EnsureFolderExists(cfg.DownloadsPath); err != nil { - log.Fatal().Err(err).Msg("create downloads directory failed") - } - if err := builtin.EnsureFolderExists(cfg.ScreenShotsPath); err != nil { - log.Fatal().Err(err).Msg("create screenshots directory failed") - } - globalConfig = cfg }) return globalConfig } + +// ResultsPath returns the results path and creates the directory if it doesn't exist +func (c *Config) ResultsPath() string { + c.mu.Lock() + defer c.mu.Unlock() + + // Check if directory exists, create if it doesn't + if _, err := os.Stat(c.resultsPath); os.IsNotExist(err) { + if err := builtin.EnsureFolderExists(c.resultsPath); err != nil { + log.Error().Err(err).Str("path", c.resultsPath).Msg("failed to create results directory") + } else { + log.Info().Str("path", c.resultsPath).Msg("create folder") + } + } + return c.resultsPath +} + +// DownloadsPath returns the downloads path and creates the directory if it doesn't exist +func (c *Config) DownloadsPath() string { + c.mu.Lock() + defer c.mu.Unlock() + + // Check if directory exists, create if it doesn't + if _, err := os.Stat(c.downloadsPath); os.IsNotExist(err) { + if err := builtin.EnsureFolderExists(c.downloadsPath); err != nil { + log.Error().Err(err).Str("path", c.downloadsPath).Msg("failed to create downloads directory") + } + } + return c.downloadsPath +} + +// ScreenShotsPath returns the screenshots path and creates the directory if it doesn't exist +func (c *Config) ScreenShotsPath() string { + c.mu.Lock() + defer c.mu.Unlock() + + // Check if directory exists, create if it doesn't + if _, err := os.Stat(c.screenShotsPath); os.IsNotExist(err) { + if err := builtin.EnsureFolderExists(c.screenShotsPath); err != nil { + log.Error().Err(err).Str("path", c.screenShotsPath).Msg("failed to create screenshots directory") + } + } + return c.screenShotsPath +} diff --git a/internal/version/VERSION b/internal/version/VERSION index e32256f6..dc63b88e 100644 --- a/internal/version/VERSION +++ b/internal/version/VERSION @@ -1 +1 @@ -v5.0.0-beta-2506101103 +v5.0.0-beta-2506101206 diff --git a/logger.go b/logger.go index 5855c404..fbaa21cd 100644 --- a/logger.go +++ b/logger.go @@ -15,7 +15,7 @@ import ( "github.com/httprunner/httprunner/v5/internal/config" ) -func InitLogger(logLevel string, logJSON bool) { +func InitLogger(logLevel string, logJSON bool, logFile bool) { // Error Logging with Stacktrace zerolog.ErrorStackMarshaler = pkgerrors.MarshalStack @@ -39,40 +39,52 @@ func InitLogger(logLevel string, logJSON bool) { TimeFormat: time.RFC3339Nano, NoColor: noColor, } - msg = "log with colorized console and file output" + if logFile { + msg = "log with colorized console and file output" + } else { + msg = "log with colorized console output only" + } } else { // default logger consoleWriter = os.Stderr - msg = "log with json console and file output" + if logFile { + msg = "log with json console and file output" + } else { + msg = "log with json console output only" + } } // parse console log level consoleLevel := parseLogLevel(logLevel) + // If logFile is false, use console-only logger + if !logFile { + log.Logger = zerolog.New(consoleWriter).With().Timestamp().Logger().Level(consoleLevel) + log.Info().Msg(msg) + return + } + // file writer - write to results/taskID/hrp.log cfg := config.GetConfig() - logFilePath := filepath.Join(cfg.ResultsPath, "hrp.log") + logFilePath := filepath.Join(cfg.ResultsPath(), "hrp.log") // create or open log file - logFile, err := os.OpenFile(logFilePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0o666) + logFileWriter, err := os.OpenFile(logFilePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0o666) if err != nil { // if file creation failed, use console logger only log.Logger = zerolog.New(consoleWriter).With().Timestamp().Logger().Level(consoleLevel) - log.Error().Err(err).Str("logFilePath", logFilePath).Msg("create log file failed") + log.Error().Err(err).Str("logFilePath", logFilePath).Msg(msg) } else { // create a custom writer that applies different log levels multiWriter := &leveledMultiWriter{ consoleWriter: consoleWriter, consoleLevel: consoleLevel, - fileWriter: logFile, + fileWriter: logFileWriter, fileLevel: zerolog.DebugLevel, } log.Logger = zerolog.New(multiWriter).With().Timestamp().Logger() - log.Info().Str("logFilePath", logFilePath).Msg("log file created successfully") + log.Info().Str("logFilePath", logFilePath).Msg(msg) } - - log.Info().Msg(msg) - log.Info().Str("console_log_level", strings.ToUpper(logLevel)).Str("file_log_level", "DEBUG").Msg("logger initialized with different levels") } // parseLogLevel converts string log level to zerolog.Level diff --git a/uixt/android_driver_adb.go b/uixt/android_driver_adb.go index 6fb17ab6..e3df2d33 100644 --- a/uixt/android_driver_adb.go +++ b/uixt/android_driver_adb.go @@ -807,7 +807,7 @@ func (ad *ADBDriver) ScreenRecord(opts ...option.ActionOption) (videoPath string filePath = options.ScreenRecordPath } else { timestamp := time.Now().Format("20060102_150405") + fmt.Sprintf("_%03d", time.Now().UnixNano()/1e6%1000) - filePath = filepath.Join(config.GetConfig().ScreenShotsPath, fmt.Sprintf("%s.mp4", timestamp)) + filePath = filepath.Join(config.GetConfig().ScreenShotsPath(), fmt.Sprintf("%s.mp4", timestamp)) } var ctx context.Context diff --git a/uixt/driver_ext_screenshot.go b/uixt/driver_ext_screenshot.go index 5d874cf6..fe96f16c 100644 --- a/uixt/driver_ext_screenshot.go +++ b/uixt/driver_ext_screenshot.go @@ -70,7 +70,7 @@ func (dExt *XTDriver) GetScreenResult(opts ...option.ActionOption) (screenResult fileName = builtin.GenNameWithTimestamp("%d_screenshot") } imagePath := filepath.Join( - config.GetConfig().ScreenShotsPath, + config.GetConfig().ScreenShotsPath(), fmt.Sprintf("%s.%s", fileName, "jpeg"), ) go func() { @@ -436,7 +436,7 @@ func MarkUIOperation(driver IDriver, actionType option.ActionName, actionCoordin // create screenshot save path timestamp := builtin.GenNameWithTimestamp("%d") imagePath := filepath.Join( - config.GetConfig().ScreenShotsPath, + config.GetConfig().ScreenShotsPath(), fmt.Sprintf("action_%s_pre_%s.png", timestamp, actionType), ) diff --git a/uixt/driver_handler.go b/uixt/driver_handler.go index e2c25961..0fc7fe56 100644 --- a/uixt/driver_handler.go +++ b/uixt/driver_handler.go @@ -141,7 +141,7 @@ func postHandler(driver IDriver, actionType option.ActionName, options *option.A // save compressed screenshot to file timestamp := builtin.GenNameWithTimestamp("%d") imagePath := filepath.Join( - config.GetConfig().ScreenShotsPath, + config.GetConfig().ScreenShotsPath(), fmt.Sprintf("action_%s_post_%s.png", timestamp, actionType), ) diff --git a/uixt/driver_utils.go b/uixt/driver_utils.go index b5c007bf..1818d746 100644 --- a/uixt/driver_utils.go +++ b/uixt/driver_utils.go @@ -305,7 +305,7 @@ var ( func DownloadFileByUrl(fileUrl string) (filePath string, err error) { hash := md5.Sum([]byte(fileUrl)) fileName := fmt.Sprintf("%x", hash) - filePath = filepath.Join(config.GetConfig().DownloadsPath, fileName) + filePath = filepath.Join(config.GetConfig().DownloadsPath(), fileName) // get or create file lock lockI, _ := fileLocks.LoadOrStore(filePath, &sync.Mutex{}) diff --git a/uixt/ios_driver_wda.go b/uixt/ios_driver_wda.go index 81576015..3c07c516 100644 --- a/uixt/ios_driver_wda.go +++ b/uixt/ios_driver_wda.go @@ -910,7 +910,7 @@ func (wd *WDADriver) triggerWDALog(data map[string]interface{}) (rawResp []byte, func (wd *WDADriver) ScreenRecord(opts ...option.ActionOption) (videoPath string, err error) { log.Info().Msg("WDADriver.ScreenRecord") timestamp := time.Now().Format("20060102_150405") + fmt.Sprintf("_%03d", time.Now().UnixNano()/1e6%1000) - fileName := filepath.Join(config.GetConfig().ScreenShotsPath, fmt.Sprintf("%s.mp4", timestamp)) + fileName := filepath.Join(config.GetConfig().ScreenShotsPath(), fmt.Sprintf("%s.mp4", timestamp)) options := option.NewActionOptions(opts...) duration := time.Duration(options.Duration * float64(time.Second))