mirror of
https://github.com/httprunner/httprunner.git
synced 2026-05-06 20:32:44 +08:00
fix: optimize report command to avoid creating timestamp directories
- Implement lazy loading for directory creation in config.go - Add logFile parameter to InitLogger for better control - Use dynamic directory existence check instead of flags - Report command now uses console-only logging to prevent directory creation - Support both JSON and colorized console output formats - Maintain backward compatibility for all other commands Changes: - config.go: Convert directory paths to getter methods with lazy creation - logger.go: Add logFile parameter and improve logging control - cmd/root.go: Detect report command and disable file logging - uixt/*: Update all references to use new getter methods Fixes the issue where 'hrp report results/' would create unwanted timestamp directories
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
v5.0.0-beta-2506101103
|
||||
v5.0.0-beta-2506101206
|
||||
|
||||
34
logger.go
34
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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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),
|
||||
)
|
||||
|
||||
|
||||
@@ -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),
|
||||
)
|
||||
|
||||
|
||||
@@ -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{})
|
||||
|
||||
@@ -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))
|
||||
|
||||
Reference in New Issue
Block a user