Add Verbose log level between Info and Debug
Implemented full log level hierarchy: Fatal, Error, Warn, Info, Verbose, Debug. - Verbose level (-v) shows detailed operations like file changes (M/A/D) - Debug level (-vv) shows low-level tracing with caller info - Quiet mode (-q) sets level to Error, suppressing Info messages - Banner and summary output now use log levels for filtering
This commit is contained in:
@@ -140,14 +140,12 @@ func (mfa *CLIApp) checkManifestOperation(ctx *cli.Context) error {
|
||||
<-extraDone
|
||||
}
|
||||
|
||||
if !ctx.Bool("quiet") {
|
||||
elapsed := time.Since(mfa.startupTime).Seconds()
|
||||
rate := float64(chk.TotalBytes()) / elapsed / 1e6
|
||||
if failures == 0 {
|
||||
log.Infof("checked %d files (%.1f MB) in %.1fs (%.1f MB/s): all OK", chk.FileCount(), float64(chk.TotalBytes())/1e6, elapsed, rate)
|
||||
} else {
|
||||
log.Infof("checked %d files (%.1f MB) in %.1fs (%.1f MB/s): %d failed", chk.FileCount(), float64(chk.TotalBytes())/1e6, elapsed, rate, failures)
|
||||
}
|
||||
elapsed := time.Since(mfa.startupTime).Seconds()
|
||||
rate := float64(chk.TotalBytes()) / elapsed / 1e6
|
||||
if failures == 0 {
|
||||
log.Infof("checked %d files (%.1f MB) in %.1fs (%.1f MB/s): all OK", chk.FileCount(), float64(chk.TotalBytes())/1e6, elapsed, rate)
|
||||
} else {
|
||||
log.Infof("checked %d files (%.1f MB) in %.1fs (%.1f MB/s): %d failed", chk.FileCount(), float64(chk.TotalBytes())/1e6, elapsed, rate, failures)
|
||||
}
|
||||
|
||||
if failures > 0 {
|
||||
|
||||
@@ -173,10 +173,10 @@ func TestBannerOutput(t *testing.T) {
|
||||
exitCode := RunWithOptions(opts)
|
||||
assert.Equal(t, 0, exitCode)
|
||||
|
||||
// Banner ASCII art should be in stdout
|
||||
stdout := opts.Stdout.(*bytes.Buffer).String()
|
||||
assert.Contains(t, stdout, "___")
|
||||
assert.Contains(t, stdout, "\\")
|
||||
// Banner ASCII art should be in stderr (via log.Info)
|
||||
stderr := opts.Stderr.(*bytes.Buffer).String()
|
||||
assert.Contains(t, stderr, "___")
|
||||
assert.Contains(t, stderr, "\\")
|
||||
}
|
||||
|
||||
func TestUnknownCommand(t *testing.T) {
|
||||
|
||||
@@ -125,17 +125,15 @@ func (mfa *CLIApp) fetchManifestOperation(ctx *cli.Context) error {
|
||||
close(progress)
|
||||
<-done
|
||||
|
||||
// Print summary if not quiet
|
||||
if !ctx.Bool("quiet") {
|
||||
elapsed := time.Since(startTime)
|
||||
avgBytesPerSec := float64(totalBytes) / elapsed.Seconds()
|
||||
avgRate := formatBitrate(avgBytesPerSec * 8)
|
||||
log.Infof("downloaded %d files (%.1f MB) in %.1fs (%s avg)",
|
||||
len(files),
|
||||
float64(totalBytes)/1e6,
|
||||
elapsed.Seconds(),
|
||||
avgRate)
|
||||
}
|
||||
// Print summary
|
||||
elapsed := time.Since(startTime)
|
||||
avgBytesPerSec := float64(totalBytes) / elapsed.Seconds()
|
||||
avgRate := formatBitrate(avgBytesPerSec * 8)
|
||||
log.Infof("downloaded %d files (%.1f MB) in %.1fs (%s avg)",
|
||||
len(files),
|
||||
float64(totalBytes)/1e6,
|
||||
elapsed.Seconds(),
|
||||
avgRate)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -149,7 +149,7 @@ func (mfa *CLIApp) freshenManifestOperation(ctx *cli.Context) error {
|
||||
existingMtime := time.Unix(existing.Mtime.Seconds, int64(existing.Mtime.Nanos))
|
||||
if existing.Size != info.Size() || !existingMtime.Equal(info.ModTime()) {
|
||||
changed++
|
||||
log.Debugf("M %s", relPath)
|
||||
log.Verbosef("M %s", relPath)
|
||||
entries = append(entries, &freshenEntry{
|
||||
path: relPath,
|
||||
size: info.Size(),
|
||||
@@ -170,7 +170,7 @@ func (mfa *CLIApp) freshenManifestOperation(ctx *cli.Context) error {
|
||||
delete(existingByPath, relPath)
|
||||
} else {
|
||||
added++
|
||||
log.Debugf("A %s", relPath)
|
||||
log.Verbosef("A %s", relPath)
|
||||
entries = append(entries, &freshenEntry{
|
||||
path: relPath,
|
||||
size: info.Size(),
|
||||
@@ -198,7 +198,7 @@ func (mfa *CLIApp) freshenManifestOperation(ctx *cli.Context) error {
|
||||
// Remaining entries in existingByPath are removed files
|
||||
removed = int64(len(existingByPath))
|
||||
for path := range existingByPath {
|
||||
log.Debugf("D %s", path)
|
||||
log.Verbosef("D %s", path)
|
||||
}
|
||||
|
||||
scanDuration := time.Since(startScan)
|
||||
@@ -305,21 +305,19 @@ func (mfa *CLIApp) freshenManifestOperation(ctx *cli.Context) error {
|
||||
}
|
||||
|
||||
// Print summary
|
||||
if !ctx.Bool("quiet") {
|
||||
totalDuration := time.Since(mfa.startupTime)
|
||||
var hashRate float64
|
||||
if hashedBytes > 0 {
|
||||
hashDuration := time.Since(startHash)
|
||||
hashRate = float64(hashedBytes) / hashDuration.Seconds() / 1e6
|
||||
}
|
||||
log.Infof("freshen complete: %d unchanged, %d changed, %d added, %d removed",
|
||||
unchanged, changed, added, removed)
|
||||
if filesToHash > 0 {
|
||||
log.Infof("hashed %.1f MB in %.1fs (%.1f MB/s)",
|
||||
float64(hashedBytes)/1e6, totalDuration.Seconds(), hashRate)
|
||||
}
|
||||
log.Infof("wrote %d files to %s", len(entries), manifestPath)
|
||||
totalDuration := time.Since(mfa.startupTime)
|
||||
var hashRate float64
|
||||
if hashedBytes > 0 {
|
||||
hashDuration := time.Since(startHash)
|
||||
hashRate = float64(hashedBytes) / hashDuration.Seconds() / 1e6
|
||||
}
|
||||
log.Infof("freshen complete: %d unchanged, %d changed, %d added, %d removed",
|
||||
unchanged, changed, added, removed)
|
||||
if filesToHash > 0 {
|
||||
log.Infof("hashed %.1f MB in %.1fs (%.1f MB/s)",
|
||||
float64(hashedBytes)/1e6, totalDuration.Seconds(), hashRate)
|
||||
}
|
||||
log.Infof("wrote %d files to %s", len(entries), manifestPath)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -115,11 +115,9 @@ func (mfa *CLIApp) generateManifestOperation(ctx *cli.Context) error {
|
||||
return fmt.Errorf("failed to generate manifest: %w", err)
|
||||
}
|
||||
|
||||
if !ctx.Bool("quiet") {
|
||||
elapsed := time.Since(mfa.startupTime).Seconds()
|
||||
rate := float64(s.TotalBytes()) / elapsed / 1e6
|
||||
log.Infof("wrote %d files (%.1f MB) to %s in %.1fs (%.1f MB/s)", s.FileCount(), float64(s.TotalBytes())/1e6, outputPath, elapsed, rate)
|
||||
}
|
||||
elapsed := time.Since(mfa.startupTime).Seconds()
|
||||
rate := float64(s.TotalBytes()) / elapsed / 1e6
|
||||
log.Infof("wrote %d files (%.1f MB) to %s in %.1fs (%.1f MB/s)", s.FileCount(), float64(s.TotalBytes())/1e6, outputPath, elapsed, rate)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ const banner = `
|
||||
\__\/ \__\/ \__\/ \__\/`
|
||||
|
||||
func (mfa *CLIApp) printBanner() {
|
||||
_, _ = fmt.Fprintln(mfa.Stdout, banner)
|
||||
log.Info(banner)
|
||||
}
|
||||
|
||||
// VersionString returns the version and git revision formatted for display.
|
||||
@@ -49,10 +49,12 @@ func (mfa *CLIApp) VersionString() string {
|
||||
return fmt.Sprintf("%s (%s)", mfa.version, mfa.gitrev)
|
||||
}
|
||||
|
||||
func (mfa *CLIApp) setVerbosity(v int) {
|
||||
func (mfa *CLIApp) setVerbosity(quiet bool, v int) {
|
||||
_, present := os.LookupEnv("MFER_DEBUG")
|
||||
if present {
|
||||
log.EnableDebugLogging()
|
||||
} else if quiet {
|
||||
log.SetLevel(log.ErrorLevel)
|
||||
} else {
|
||||
log.SetLevelFromVerbosity(v)
|
||||
}
|
||||
@@ -98,10 +100,8 @@ func (mfa *CLIApp) run(args []string) {
|
||||
Aliases: []string{"gen"},
|
||||
Usage: "Generate manifest file",
|
||||
Action: func(c *cli.Context) error {
|
||||
if !c.Bool("quiet") {
|
||||
mfa.printBanner()
|
||||
}
|
||||
mfa.setVerbosity(verbosity)
|
||||
mfa.setVerbosity(c.Bool("quiet"), verbosity)
|
||||
mfa.printBanner()
|
||||
return mfa.generateManifestOperation(c)
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
@@ -138,10 +138,8 @@ func (mfa *CLIApp) run(args []string) {
|
||||
Usage: "Validate files using manifest file",
|
||||
ArgsUsage: "[manifest file]",
|
||||
Action: func(c *cli.Context) error {
|
||||
if !c.Bool("quiet") {
|
||||
mfa.printBanner()
|
||||
}
|
||||
mfa.setVerbosity(verbosity)
|
||||
mfa.setVerbosity(c.Bool("quiet"), verbosity)
|
||||
mfa.printBanner()
|
||||
return mfa.checkManifestOperation(c)
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
@@ -167,10 +165,8 @@ func (mfa *CLIApp) run(args []string) {
|
||||
Usage: "Update manifest with changed, new, and removed files",
|
||||
ArgsUsage: "[manifest file]",
|
||||
Action: func(c *cli.Context) error {
|
||||
if !c.Bool("quiet") {
|
||||
mfa.printBanner()
|
||||
}
|
||||
mfa.setVerbosity(verbosity)
|
||||
mfa.setVerbosity(c.Bool("quiet"), verbosity)
|
||||
mfa.printBanner()
|
||||
return mfa.freshenManifestOperation(c)
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
@@ -209,10 +205,8 @@ func (mfa *CLIApp) run(args []string) {
|
||||
Name: "fetch",
|
||||
Usage: "fetch manifest and referenced files",
|
||||
Action: func(c *cli.Context) error {
|
||||
if !c.Bool("quiet") {
|
||||
mfa.printBanner()
|
||||
}
|
||||
mfa.setVerbosity(verbosity)
|
||||
mfa.setVerbosity(c.Bool("quiet"), verbosity)
|
||||
mfa.printBanner()
|
||||
return mfa.fetchManifestOperation(c)
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user