Ver Fonte

refactor: central logger (#1692)

Richard Gomez há 1 ano atrás
pai
commit
ab38a46986

+ 12 - 12
cmd/detect.go

@@ -22,9 +22,9 @@ import (
 	"os"
 	"time"
 
-	"github.com/rs/zerolog/log"
 	"github.com/spf13/cobra"
 
+	"github.com/zricethezav/gitleaks/v8/logging"
 	"github.com/zricethezav/gitleaks/v8/report"
 	"github.com/zricethezav/gitleaks/v8/sources"
 )
@@ -48,7 +48,7 @@ var detectCmd = &cobra.Command{
 func runDetect(cmd *cobra.Command, args []string) {
 	source, err := cmd.Flags().GetString("source")
 	if err != nil {
-		log.Fatal().Err(err).Msg("could not get source")
+		logging.Fatal().Err(err).Msg("could not get source")
 	}
 	initConfig(source)
 
@@ -64,12 +64,12 @@ func runDetect(cmd *cobra.Command, args []string) {
 
 	// set follow symlinks flag
 	if detector.FollowSymlinks, err = cmd.Flags().GetBool("follow-symlinks"); err != nil {
-		log.Fatal().Err(err).Msg("")
+		logging.Fatal().Err(err).Msg("")
 	}
 	// set exit code
 	exitCode, err := cmd.Flags().GetInt("exit-code")
 	if err != nil {
-		log.Fatal().Err(err).Msg("could not get exit code")
+		logging.Fatal().Err(err).Msg("could not get exit code")
 	}
 
 	// determine what type of scan:
@@ -77,11 +77,11 @@ func runDetect(cmd *cobra.Command, args []string) {
 	// - no-git: scan files by treating the repo as a plain directory
 	noGit, err := cmd.Flags().GetBool("no-git")
 	if err != nil {
-		log.Fatal().Err(err).Msg("could not call GetBool() for no-git")
+		logging.Fatal().Err(err).Msg("could not call GetBool() for no-git")
 	}
 	fromPipe, err := cmd.Flags().GetBool("pipe")
 	if err != nil {
-		log.Fatal().Err(err).Msg("could not call GetBool() for pipe")
+		logging.Fatal().Err(err).Msg("could not call GetBool() for pipe")
 	}
 
 	// start the detector scan
@@ -94,20 +94,20 @@ func runDetect(cmd *cobra.Command, args []string) {
 			detector.Config.Allowlist.PathAllowed,
 		)
 		if err != nil {
-			log.Fatal().Err(err)
+			logging.Fatal().Err(err)
 		}
 
 		findings, err = detector.DetectFiles(paths)
 		if err != nil {
 			// don't exit on error, just log it
-			log.Error().Err(err).Msg("failed scan directory")
+			logging.Error().Err(err).Msg("failed scan directory")
 		}
 	} else if fromPipe {
 		findings, err = detector.DetectReader(os.Stdin, 10)
 		if err != nil {
 			// log fatal to exit, no need to continue since a report
 			// will not be generated when scanning from a pipe...for now
-			log.Fatal().Err(err).Msg("failed scan input from stdin")
+			logging.Fatal().Err(err).Msg("failed scan input from stdin")
 		}
 	} else {
 		var (
@@ -116,16 +116,16 @@ func runDetect(cmd *cobra.Command, args []string) {
 		)
 		logOpts, err = cmd.Flags().GetString("log-opts")
 		if err != nil {
-			log.Fatal().Err(err).Msg("could not call GetString() for log-opts")
+			logging.Fatal().Err(err).Msg("could not call GetString() for log-opts")
 		}
 		gitCmd, err = sources.NewGitLogCmd(source, logOpts)
 		if err != nil {
-			log.Fatal().Err(err).Msg("could not create Git cmd")
+			logging.Fatal().Err(err).Msg("could not create Git cmd")
 		}
 		findings, err = detector.DetectGit(gitCmd)
 		if err != nil {
 			// don't exit on error, just log it
-			log.Error().Err(err).Msg("failed to scan Git repository")
+			logging.Error().Err(err).Msg("failed to scan Git repository")
 		}
 	}
 

+ 5 - 5
cmd/directory.go

@@ -3,9 +3,9 @@ package cmd
 import (
 	"time"
 
-	"github.com/rs/zerolog/log"
 	"github.com/spf13/cobra"
 
+	"github.com/zricethezav/gitleaks/v8/logging"
 	"github.com/zricethezav/gitleaks/v8/report"
 	"github.com/zricethezav/gitleaks/v8/sources"
 )
@@ -47,12 +47,12 @@ func runDirectory(cmd *cobra.Command, args []string) {
 
 	// set follow symlinks flag
 	if detector.FollowSymlinks, err = cmd.Flags().GetBool("follow-symlinks"); err != nil {
-		log.Fatal().Err(err).Msg("")
+		logging.Fatal().Err(err).Msg("")
 	}
 	// set exit code
 	exitCode, err := cmd.Flags().GetInt("exit-code")
 	if err != nil {
-		log.Fatal().Err(err).Msg("could not get exit code")
+		logging.Fatal().Err(err).Msg("could not get exit code")
 	}
 
 	var paths <-chan sources.ScanTarget
@@ -63,13 +63,13 @@ func runDirectory(cmd *cobra.Command, args []string) {
 		detector.Config.Allowlist.PathAllowed,
 	)
 	if err != nil {
-		log.Fatal().Err(err)
+		logging.Fatal().Err(err)
 	}
 
 	findings, err = detector.DetectFiles(paths)
 	if err != nil {
 		// don't exit on error, just log it
-		log.Error().Err(err).Msg("failed scan directory")
+		logging.Error().Err(err).Msg("failed scan directory")
 	}
 
 	findingSummaryAndExit(detector, findings, exitCode, start, err)

+ 5 - 7
cmd/generate/config/main.go

@@ -4,11 +4,10 @@ import (
 	"os"
 	"text/template"
 
-	"github.com/rs/zerolog/log"
-
 	"github.com/zricethezav/gitleaks/v8/cmd/generate/config/base"
 	"github.com/zricethezav/gitleaks/v8/cmd/generate/config/rules"
 	"github.com/zricethezav/gitleaks/v8/config"
+	"github.com/zricethezav/gitleaks/v8/logging"
 )
 
 const (
@@ -236,7 +235,7 @@ func main() {
 	for _, rule := range configRules {
 		// check if rule is in ruleLookUp
 		if _, ok := ruleLookUp[rule.RuleID]; ok {
-			log.Fatal().Msgf("rule id %s is not unique", rule.RuleID)
+			logging.Fatal().Msgf("rule id %s is not unique", rule.RuleID)
 		}
 		// TODO: eventually change all the signatures to get ride of this
 		// nasty dereferencing.
@@ -245,18 +244,17 @@ func main() {
 
 	tmpl, err := template.ParseFiles(templatePath)
 	if err != nil {
-		log.Fatal().Err(err).Msg("Failed to parse template")
+		logging.Fatal().Err(err).Msg("Failed to parse template")
 	}
 
 	f, err := os.Create(gitleaksConfigPath)
 	if err != nil {
-		log.Fatal().Err(err).Msg("Failed to create rules.toml")
+		logging.Fatal().Err(err).Msg("Failed to create rules.toml")
 	}
 
 	cfg := base.CreateGlobalConfig()
 	cfg.Rules = ruleLookUp
 	if err = tmpl.Execute(f, cfg); err != nil {
-		log.Fatal().Err(err).Msg("could not execute template")
+		logging.Fatal().Err(err).Msg("could not execute template")
 	}
-
 }

+ 5 - 6
cmd/generate/config/utils/validate.go

@@ -7,11 +7,10 @@ package utils
 import (
 	"strings"
 
-	"github.com/rs/zerolog/log"
-
 	"github.com/zricethezav/gitleaks/v8/cmd/generate/config/base"
 	"github.com/zricethezav/gitleaks/v8/config"
 	"github.com/zricethezav/gitleaks/v8/detect"
+	"github.com/zricethezav/gitleaks/v8/logging"
 )
 
 func Validate(rule config.Rule, truePositives []string, falsePositives []string) *config.Rule {
@@ -19,7 +18,7 @@ func Validate(rule config.Rule, truePositives []string, falsePositives []string)
 	d := createSingleRuleDetector(r)
 	for _, tp := range truePositives {
 		if len(d.DetectString(tp)) < 1 {
-			log.Fatal().
+			logging.Fatal().
 				Str("rule", r.RuleID).
 				Str("value", tp).
 				Str("regex", r.Regex.String()).
@@ -29,7 +28,7 @@ func Validate(rule config.Rule, truePositives []string, falsePositives []string)
 	for _, fp := range falsePositives {
 		findings := d.DetectString(fp)
 		if len(findings) != 0 {
-			log.Fatal().
+			logging.Fatal().
 				Str("rule", r.RuleID).
 				Str("value", fp).
 				Str("regex", r.Regex.String()).
@@ -45,7 +44,7 @@ func ValidateWithPaths(rule config.Rule, truePositives map[string]string, falseP
 	for path, tp := range truePositives {
 		f := detect.Fragment{Raw: tp, FilePath: path}
 		if len(d.Detect(f)) != 1 {
-			log.Fatal().
+			logging.Fatal().
 				Str("rule", r.RuleID).
 				Str("value", tp).
 				Str("regex", r.Regex.String()).
@@ -56,7 +55,7 @@ func ValidateWithPaths(rule config.Rule, truePositives map[string]string, falseP
 	for path, fp := range falsePositives {
 		f := detect.Fragment{Raw: fp, FilePath: path}
 		if len(d.Detect(f)) != 0 {
-			log.Fatal().
+			logging.Fatal().
 				Str("rule", r.RuleID).
 				Str("value", fp).
 				Str("regex", r.Regex.String()).

+ 8 - 8
cmd/git.go

@@ -3,9 +3,9 @@ package cmd
 import (
 	"time"
 
-	"github.com/rs/zerolog/log"
 	"github.com/spf13/cobra"
 
+	"github.com/zricethezav/gitleaks/v8/logging"
 	"github.com/zricethezav/gitleaks/v8/report"
 	"github.com/zricethezav/gitleaks/v8/sources"
 )
@@ -53,7 +53,7 @@ func runGit(cmd *cobra.Command, args []string) {
 	// set exit code
 	exitCode, err := cmd.Flags().GetInt("exit-code")
 	if err != nil {
-		log.Fatal().Err(err).Msg("could not get exit code")
+		logging.Fatal().Err(err).Msg("could not get exit code")
 	}
 
 	var (
@@ -64,33 +64,33 @@ func runGit(cmd *cobra.Command, args []string) {
 	)
 	logOpts, err = cmd.Flags().GetString("log-opts")
 	if err != nil {
-		log.Fatal().Err(err).Msg("could not call GetString() for log-opts")
+		logging.Fatal().Err(err).Msg("could not call GetString() for log-opts")
 	}
 	staged, err = cmd.Flags().GetBool("staged")
 	if err != nil {
-		log.Fatal().Err(err).Msg("could not call GetBool() for staged")
+		logging.Fatal().Err(err).Msg("could not call GetBool() for staged")
 	}
 	preCommit, err = cmd.Flags().GetBool("pre-commit")
 	if err != nil {
-		log.Fatal().Err(err).Msg("could not call GetBool() for pre-commit")
+		logging.Fatal().Err(err).Msg("could not call GetBool() for pre-commit")
 	}
 
 	if preCommit || staged {
 		gitCmd, err = sources.NewGitDiffCmd(source, staged)
 		if err != nil {
-			log.Fatal().Err(err).Msg("could not create Git diff cmd")
+			logging.Fatal().Err(err).Msg("could not create Git diff cmd")
 		}
 	} else {
 		gitCmd, err = sources.NewGitLogCmd(source, logOpts)
 		if err != nil {
-			log.Fatal().Err(err).Msg("could not create Git log cmd")
+			logging.Fatal().Err(err).Msg("could not create Git log cmd")
 		}
 	}
 
 	findings, err = detector.DetectGit(gitCmd)
 	if err != nil {
 		// don't exit on error, just log it
-		log.Error().Err(err).Msg("failed to scan Git repository")
+		logging.Error().Err(err).Msg("failed to scan Git repository")
 	}
 
 	findingSummaryAndExit(detector, findings, exitCode, start, err)

+ 3 - 3
cmd/protect.go

@@ -3,9 +3,9 @@ package cmd
 import (
 	"time"
 
-	"github.com/rs/zerolog/log"
 	"github.com/spf13/cobra"
 
+	"github.com/zricethezav/gitleaks/v8/logging"
 	"github.com/zricethezav/gitleaks/v8/report"
 	"github.com/zricethezav/gitleaks/v8/sources"
 )
@@ -27,7 +27,7 @@ var protectCmd = &cobra.Command{
 func runProtect(cmd *cobra.Command, args []string) {
 	source, err := cmd.Flags().GetString("source")
 	if err != nil {
-		log.Fatal().Err(err).Msg("could not get source")
+		logging.Fatal().Err(err).Msg("could not get source")
 	}
 	initConfig(source)
 
@@ -43,7 +43,7 @@ func runProtect(cmd *cobra.Command, args []string) {
 	var findings []report.Finding
 	gitCmd, err := sources.NewGitDiffCmd(source, staged)
 	if err != nil {
-		log.Fatal().Err(err).Msg("")
+		logging.Fatal().Err(err).Msg("")
 	}
 	findings, err = detector.DetectGit(gitCmd)
 

+ 57 - 53
cmd/root.go

@@ -16,6 +16,7 @@ import (
 
 	"github.com/zricethezav/gitleaks/v8/config"
 	"github.com/zricethezav/gitleaks/v8/detect"
+	"github.com/zricethezav/gitleaks/v8/logging"
 	"github.com/zricethezav/gitleaks/v8/report"
 )
 
@@ -70,38 +71,41 @@ func init() {
 
 	err := viper.BindPFlag("config", rootCmd.PersistentFlags().Lookup("config"))
 	if err != nil {
-		log.Fatal().Msgf("err binding config %s", err.Error())
+		logging.Fatal().Msgf("err binding config %s", err.Error())
 	}
 }
 
+var logLevel = zerolog.InfoLevel
+
 func initLog() {
-	zerolog.SetGlobalLevel(zerolog.InfoLevel)
 	ll, err := rootCmd.Flags().GetString("log-level")
 	if err != nil {
-		log.Fatal().Msg(err.Error())
+		logging.Fatal().Msg(err.Error())
 	}
+
 	switch strings.ToLower(ll) {
 	case "trace":
-		zerolog.SetGlobalLevel(zerolog.TraceLevel)
+		logLevel = zerolog.TraceLevel
 	case "debug":
-		zerolog.SetGlobalLevel(zerolog.DebugLevel)
+		logLevel = zerolog.DebugLevel
 	case "info":
-		zerolog.SetGlobalLevel(zerolog.InfoLevel)
+		logLevel = zerolog.InfoLevel
 	case "warn":
-		zerolog.SetGlobalLevel(zerolog.WarnLevel)
+		logLevel = zerolog.WarnLevel
 	case "err", "error":
-		zerolog.SetGlobalLevel(zerolog.ErrorLevel)
+		logLevel = zerolog.ErrorLevel
 	case "fatal":
-		zerolog.SetGlobalLevel(zerolog.FatalLevel)
+		logLevel = zerolog.FatalLevel
 	default:
-		zerolog.SetGlobalLevel(zerolog.InfoLevel)
+		logging.Warn().Msgf("unknown log level: %s", ll)
 	}
+	logging.Logger = logging.Logger.Level(logLevel)
 }
 
 func initConfig(source string) {
 	hideBanner, err := rootCmd.Flags().GetBool("no-banner")
 	if err != nil {
-		log.Fatal().Msg(err.Error())
+		logging.Fatal().Msg(err.Error())
 	}
 	if !hideBanner {
 		_, _ = fmt.Fprint(os.Stderr, banner)
@@ -109,40 +113,40 @@ func initConfig(source string) {
 
 	cfgPath, err := rootCmd.Flags().GetString("config")
 	if err != nil {
-		log.Fatal().Msg(err.Error())
+		logging.Fatal().Msg(err.Error())
 	}
 	if cfgPath != "" {
 		viper.SetConfigFile(cfgPath)
-		log.Debug().Msgf("using gitleaks config %s from `--config`", cfgPath)
+		logging.Debug().Msgf("using gitleaks config %s from `--config`", cfgPath)
 	} else if os.Getenv("GITLEAKS_CONFIG") != "" {
 		envPath := os.Getenv("GITLEAKS_CONFIG")
 		viper.SetConfigFile(envPath)
-		log.Debug().Msgf("using gitleaks config from GITLEAKS_CONFIG env var: %s", envPath)
+		logging.Debug().Msgf("using gitleaks config from GITLEAKS_CONFIG env var: %s", envPath)
 	} else {
 		fileInfo, err := os.Stat(source)
 		if err != nil {
-			log.Fatal().Msg(err.Error())
+			logging.Fatal().Msg(err.Error())
 		}
 
 		if !fileInfo.IsDir() {
-			log.Debug().Msgf("unable to load gitleaks config from %s since --source=%s is a file, using default config",
+			logging.Debug().Msgf("unable to load gitleaks config from %s since --source=%s is a file, using default config",
 				filepath.Join(source, ".gitleaks.toml"), source)
 			viper.SetConfigType("toml")
 			if err = viper.ReadConfig(strings.NewReader(config.DefaultConfig)); err != nil {
-				log.Fatal().Msgf("err reading toml %s", err.Error())
+				logging.Fatal().Msgf("err reading toml %s", err.Error())
 			}
 			return
 		}
 
 		if _, err := os.Stat(filepath.Join(source, ".gitleaks.toml")); os.IsNotExist(err) {
-			log.Debug().Msgf("no gitleaks config found in path %s, using default gitleaks config", filepath.Join(source, ".gitleaks.toml"))
+			logging.Debug().Msgf("no gitleaks config found in path %s, using default gitleaks config", filepath.Join(source, ".gitleaks.toml"))
 			viper.SetConfigType("toml")
 			if err = viper.ReadConfig(strings.NewReader(config.DefaultConfig)); err != nil {
-				log.Fatal().Msgf("err reading default config toml %s", err.Error())
+				logging.Fatal().Msgf("err reading default config toml %s", err.Error())
 			}
 			return
 		} else {
-			log.Debug().Msgf("using existing gitleaks config %s from `(--source)/.gitleaks.toml`", filepath.Join(source, ".gitleaks.toml"))
+			logging.Debug().Msgf("using existing gitleaks config %s from `(--source)/.gitleaks.toml`", filepath.Join(source, ".gitleaks.toml"))
 		}
 
 		viper.AddConfigPath(source)
@@ -150,7 +154,7 @@ func initConfig(source string) {
 		viper.SetConfigType("toml")
 	}
 	if err := viper.ReadInConfig(); err != nil {
-		log.Fatal().Msgf("unable to load gitleaks config, err: %s", err)
+		logging.Fatal().Msgf("unable to load gitleaks config, err: %s", err)
 	}
 }
 
@@ -160,18 +164,18 @@ func Execute() {
 			// exit code 126: Command invoked cannot execute
 			os.Exit(126)
 		}
-		log.Fatal().Msg(err.Error())
+		logging.Fatal().Msg(err.Error())
 	}
 }
 
 func Config(cmd *cobra.Command) config.Config {
 	var vc config.ViperConfig
 	if err := viper.Unmarshal(&vc); err != nil {
-		log.Fatal().Err(err).Msg("Failed to load config")
+		logging.Fatal().Err(err).Msg("Failed to load config")
 	}
 	cfg, err := vc.Translate()
 	if err != nil {
-		log.Fatal().Err(err).Msg("Failed to load config")
+		logging.Fatal().Err(err).Msg("Failed to load config")
 	}
 	cfg.Path, _ = cmd.Flags().GetString("config")
 
@@ -185,23 +189,23 @@ func Detector(cmd *cobra.Command, cfg config.Config, source string) *detect.Dete
 	detector := detect.NewDetector(cfg)
 
 	if detector.MaxDecodeDepth, err = cmd.Flags().GetInt("max-decode-depth"); err != nil {
-		log.Fatal().Err(err).Msg("")
+		logging.Fatal().Err(err).Msg("")
 	}
 
 	// set color flag at first
 	if detector.NoColor, err = cmd.Flags().GetBool("no-color"); err != nil {
-		log.Fatal().Err(err).Msg("")
+		logging.Fatal().Err(err).Msg("")
 	}
 	// also init logger again without color
 	if detector.NoColor {
-		log.Logger = log.Output(zerolog.ConsoleWriter{
+		logging.Logger = log.Output(zerolog.ConsoleWriter{
 			Out:     os.Stderr,
 			NoColor: detector.NoColor,
-		})
+		}).Level(logLevel)
 	}
 	detector.Config.Path, err = cmd.Flags().GetString("config")
 	if err != nil {
-		log.Fatal().Err(err).Msg("")
+		logging.Fatal().Err(err).Msg("")
 	}
 
 	// if config path is not set, then use the {source}/.gitleaks.toml path.
@@ -211,40 +215,40 @@ func Detector(cmd *cobra.Command, cfg config.Config, source string) *detect.Dete
 	}
 	// set verbose flag
 	if detector.Verbose, err = cmd.Flags().GetBool("verbose"); err != nil {
-		log.Fatal().Err(err).Msg("")
+		logging.Fatal().Err(err).Msg("")
 	}
 	// set redact flag
 	if detector.Redact, err = cmd.Flags().GetUint("redact"); err != nil {
-		log.Fatal().Err(err).Msg("")
+		logging.Fatal().Err(err).Msg("")
 	}
 	if detector.MaxTargetMegaBytes, err = cmd.Flags().GetInt("max-target-megabytes"); err != nil {
-		log.Fatal().Err(err).Msg("")
+		logging.Fatal().Err(err).Msg("")
 	}
 	// set ignore gitleaks:allow flag
 	if detector.IgnoreGitleaksAllow, err = cmd.Flags().GetBool("ignore-gitleaks-allow"); err != nil {
-		log.Fatal().Err(err).Msg("")
+		logging.Fatal().Err(err).Msg("")
 	}
 
 	gitleaksIgnorePath, err := cmd.Flags().GetString("gitleaks-ignore-path")
 	if err != nil {
-		log.Fatal().Err(err).Msg("could not get .gitleaksignore path")
+		logging.Fatal().Err(err).Msg("could not get .gitleaksignore path")
 	}
 
 	if fileExists(gitleaksIgnorePath) {
 		if err = detector.AddGitleaksIgnore(gitleaksIgnorePath); err != nil {
-			log.Fatal().Err(err).Msg("could not call AddGitleaksIgnore")
+			logging.Fatal().Err(err).Msg("could not call AddGitleaksIgnore")
 		}
 	}
 
 	if fileExists(filepath.Join(gitleaksIgnorePath, ".gitleaksignore")) {
 		if err = detector.AddGitleaksIgnore(filepath.Join(gitleaksIgnorePath, ".gitleaksignore")); err != nil {
-			log.Fatal().Err(err).Msg("could not call AddGitleaksIgnore")
+			logging.Fatal().Err(err).Msg("could not call AddGitleaksIgnore")
 		}
 	}
 
 	if fileExists(filepath.Join(source, ".gitleaksignore")) {
 		if err = detector.AddGitleaksIgnore(filepath.Join(source, ".gitleaksignore")); err != nil {
-			log.Fatal().Err(err).Msg("could not call AddGitleaksIgnore")
+			logging.Fatal().Err(err).Msg("could not call AddGitleaksIgnore")
 		}
 	}
 
@@ -253,20 +257,20 @@ func Detector(cmd *cobra.Command, cfg config.Config, source string) *detect.Dete
 	if baselinePath != "" {
 		err = detector.AddBaseline(baselinePath, source)
 		if err != nil {
-			log.Error().Msgf("Could not load baseline. The path must point of a gitleaks report generated using the default format: %s", err)
+			logging.Error().Msgf("Could not load baseline. The path must point of a gitleaks report generated using the default format: %s", err)
 		}
 	}
 
 	// If set, only apply rules that are defined in the flag
 	rules, _ := cmd.Flags().GetStringSlice("enable-rule")
 	if len(rules) > 0 {
-		log.Info().Msg("Overriding enabled rules: " + strings.Join(rules, ", "))
+		logging.Info().Msg("Overriding enabled rules: " + strings.Join(rules, ", "))
 		ruleOverride := make(map[string]config.Rule)
 		for _, ruleName := range rules {
 			if r, ok := cfg.Rules[ruleName]; ok {
 				ruleOverride[ruleName] = r
 			} else {
-				log.Fatal().Msgf("Requested rule %s not found in rules", ruleName)
+				logging.Fatal().Msgf("Requested rule %s not found in rules", ruleName)
 			}
 		}
 		detector.Config.Rules = ruleOverride
@@ -278,7 +282,7 @@ func Detector(cmd *cobra.Command, cfg config.Config, source string) *detect.Dete
 		if reportPath != report.StdoutReportPath {
 			// Ensure the path is writable.
 			if f, err := os.Create(reportPath); err != nil {
-				log.Fatal().Err(err).Msgf("Report path is not writable: %s", reportPath)
+				logging.Fatal().Err(err).Msgf("Report path is not writable: %s", reportPath)
 			} else {
 				_ = f.Close()
 				_ = os.Remove(reportPath)
@@ -304,15 +308,15 @@ func Detector(cmd *cobra.Command, cfg config.Config, source string) *detect.Dete
 			}
 		case "template":
 			if reporter, err = report.NewTemplateReporter(reportTemplate); err != nil {
-				log.Fatal().Err(err).Msg("Invalid report template")
+				logging.Fatal().Err(err).Msg("Invalid report template")
 			}
 		default:
-			log.Fatal().Msgf("unknown report format %s", reportFormat)
+			logging.Fatal().Msgf("unknown report format %s", reportFormat)
 		}
 
 		// Sanity check.
 		if reportTemplate != "" && reportFormat != "template" {
-			log.Fatal().Msgf("Report format must be 'template' if --report-template is specified")
+			logging.Fatal().Msgf("Report format must be 'template' if --report-template is specified")
 		}
 
 		detector.ReportPath = reportPath
@@ -325,7 +329,7 @@ func Detector(cmd *cobra.Command, cfg config.Config, source string) *detect.Dete
 func mustGetStringFlag(name string) string {
 	reportPath, err := rootCmd.Flags().GetString(name)
 	if err != nil {
-		log.Fatal().Msg(err.Error())
+		logging.Fatal().Msg(err.Error())
 	}
 	return reportPath
 }
@@ -361,19 +365,19 @@ func findingSummaryAndExit(detector *detect.Detector, findings []report.Finding,
 	totalBytes := atomic.LoadUint64(&detector.TotalBytes)
 	bytesMsg := fmt.Sprintf("scanned ~%d bytes (%s)", totalBytes, bytesConvert(totalBytes))
 	if err == nil {
-		log.Info().Msgf("%s in %s", bytesMsg, FormatDuration(time.Since(start)))
+		logging.Info().Msgf("%s in %s", bytesMsg, FormatDuration(time.Since(start)))
 		if len(findings) != 0 {
-			log.Warn().Msgf("leaks found: %d", len(findings))
+			logging.Warn().Msgf("leaks found: %d", len(findings))
 		} else {
-			log.Info().Msg("no leaks found")
+			logging.Info().Msg("no leaks found")
 		}
 	} else {
-		log.Warn().Msg(bytesMsg)
-		log.Warn().Msgf("partial scan completed in %s", FormatDuration(time.Since(start)))
+		logging.Warn().Msg(bytesMsg)
+		logging.Warn().Msgf("partial scan completed in %s", FormatDuration(time.Since(start)))
 		if len(findings) != 0 {
-			log.Warn().Msgf("%d leaks found in partial scan", len(findings))
+			logging.Warn().Msgf("%d leaks found in partial scan", len(findings))
 		} else {
-			log.Warn().Msg("no leaks found in partial scan")
+			logging.Warn().Msg("no leaks found in partial scan")
 		}
 	}
 
@@ -403,7 +407,7 @@ func findingSummaryAndExit(detector *detect.Detector, findings []report.Finding,
 
 	ReportEnd:
 		if reportErr != nil {
-			log.Fatal().Err(reportErr).Msg("failed to write report")
+			logging.Fatal().Err(reportErr).Msg("failed to write report")
 		}
 	}
 

+ 3 - 3
cmd/stdin.go

@@ -4,9 +4,9 @@ import (
 	"os"
 	"time"
 
-	"github.com/rs/zerolog/log"
 	"github.com/spf13/cobra"
 
+	"github.com/zricethezav/gitleaks/v8/logging"
 	"github.com/zricethezav/gitleaks/v8/report"
 )
 
@@ -37,14 +37,14 @@ func runStdIn(cmd *cobra.Command, args []string) {
 	// set exit code
 	exitCode, err := cmd.Flags().GetInt("exit-code")
 	if err != nil {
-		log.Fatal().Err(err).Msg("could not get exit code")
+		logging.Fatal().Err(err).Msg("could not get exit code")
 	}
 
 	findings, err = detector.DetectReader(os.Stdin, 10)
 	if err != nil {
 		// log fatal to exit, no need to continue since a report
 		// will not be generated when scanning from a pipe...for now
-		log.Fatal().Err(err).Msg("failed scan input from stdin")
+		logging.Fatal().Err(err).Msg("failed scan input from stdin")
 	}
 
 	findingSummaryAndExit(detector, findings, exitCode, start, err)

+ 11 - 10
config/config.go

@@ -6,9 +6,10 @@ import (
 	"sort"
 	"strings"
 
-	"github.com/rs/zerolog/log"
 	"github.com/spf13/viper"
 	regexp "github.com/wasilibs/go-re2"
+
+	"github.com/zricethezav/gitleaks/v8/logging"
 )
 
 //go:embed gitleaks.toml
@@ -204,7 +205,7 @@ func (vc *ViperConfig) Translate() (Config, error) {
 	if maxExtendDepth != extendDepth {
 		// disallow both usedefault and path from being set
 		if c.Extend.Path != "" && c.Extend.UseDefault {
-			log.Fatal().Msg("unable to load config due to extend.path and extend.useDefault being set")
+			logging.Fatal().Msg("unable to load config due to extend.path and extend.useDefault being set")
 		}
 		if c.Extend.UseDefault {
 			c.extendDefault()
@@ -239,20 +240,20 @@ func (c *Config) extendDefault() {
 	extendDepth++
 	viper.SetConfigType("toml")
 	if err := viper.ReadConfig(strings.NewReader(DefaultConfig)); err != nil {
-		log.Fatal().Msgf("failed to load extended config, err: %s", err)
+		logging.Fatal().Msgf("failed to load extended config, err: %s", err)
 		return
 	}
 	defaultViperConfig := ViperConfig{}
 	if err := viper.Unmarshal(&defaultViperConfig); err != nil {
-		log.Fatal().Msgf("failed to load extended config, err: %s", err)
+		logging.Fatal().Msgf("failed to load extended config, err: %s", err)
 		return
 	}
 	cfg, err := defaultViperConfig.Translate()
 	if err != nil {
-		log.Fatal().Msgf("failed to load extended config, err: %s", err)
+		logging.Fatal().Msgf("failed to load extended config, err: %s", err)
 		return
 	}
-	log.Debug().Msg("extending config with default config")
+	logging.Debug().Msg("extending config with default config")
 	c.extend(cfg)
 
 }
@@ -261,20 +262,20 @@ func (c *Config) extendPath() {
 	extendDepth++
 	viper.SetConfigFile(c.Extend.Path)
 	if err := viper.ReadInConfig(); err != nil {
-		log.Fatal().Msgf("failed to load extended config, err: %s", err)
+		logging.Fatal().Msgf("failed to load extended config, err: %s", err)
 		return
 	}
 	extensionViperConfig := ViperConfig{}
 	if err := viper.Unmarshal(&extensionViperConfig); err != nil {
-		log.Fatal().Msgf("failed to load extended config, err: %s", err)
+		logging.Fatal().Msgf("failed to load extended config, err: %s", err)
 		return
 	}
 	cfg, err := extensionViperConfig.Translate()
 	if err != nil {
-		log.Fatal().Msgf("failed to load extended config, err: %s", err)
+		logging.Fatal().Msgf("failed to load extended config, err: %s", err)
 		return
 	}
-	log.Debug().Msgf("extending config with %s", c.Extend.Path)
+	logging.Debug().Msgf("extending config with %s", c.Extend.Path)
 	c.extend(cfg)
 }
 

+ 2 - 2
detect/decoder.go

@@ -7,7 +7,7 @@ import (
 	"regexp"
 	"unicode"
 
-	"github.com/rs/zerolog/log"
+	"github.com/zricethezav/gitleaks/v8/logging"
 )
 
 var b64LikelyChars [128]byte
@@ -227,7 +227,7 @@ func (d *Decoder) findEncodedSegments(data string, parentSegments []EncodedSegme
 			}
 		}
 
-		log.Debug().Msgf("segment found: %#v", segment)
+		logging.Debug().Msgf("segment found: %#v", segment)
 		segments = append(segments, segment)
 	}
 

+ 8 - 8
detect/detect.go

@@ -11,12 +11,12 @@ import (
 	"sync/atomic"
 
 	"github.com/zricethezav/gitleaks/v8/config"
+	"github.com/zricethezav/gitleaks/v8/logging"
 	"github.com/zricethezav/gitleaks/v8/report"
 
 	ahocorasick "github.com/BobuSumisu/aho-corasick"
 	"github.com/fatih/semgroup"
 	"github.com/rs/zerolog"
-	"github.com/rs/zerolog/log"
 	"github.com/spf13/viper"
 	"golang.org/x/exp/maps"
 )
@@ -144,7 +144,7 @@ func NewDetectorDefaultConfig() (*Detector, error) {
 }
 
 func (d *Detector) AddGitleaksIgnore(gitleaksIgnorePath string) error {
-	log.Debug().Msgf("found .gitleaksignore file: %s", gitleaksIgnorePath)
+	logging.Debug().Msgf("found .gitleaksignore file: %s", gitleaksIgnorePath)
 	file, err := os.Open(gitleaksIgnorePath)
 
 	if err != nil {
@@ -154,7 +154,7 @@ func (d *Detector) AddGitleaksIgnore(gitleaksIgnorePath string) error {
 	// https://github.com/securego/gosec/issues/512
 	defer func() {
 		if err := file.Close(); err != nil {
-			log.Warn().Msgf("Error closing .gitleaksignore file: %s\n", err)
+			logging.Warn().Msgf("Error closing .gitleaksignore file: %s\n", err)
 		}
 	}()
 	scanner := bufio.NewScanner(file)
@@ -256,7 +256,7 @@ func (d *Detector) detectRule(fragment Fragment, currentRaw string, r config.Rul
 	var (
 		findings []report.Finding
 		logger   = func() zerolog.Logger {
-			l := log.With().Str("rule-id", r.RuleID)
+			l := logging.With().Str("rule-id", r.RuleID)
 			if fragment.CommitSHA != "" {
 				l = l.Str("commit", fragment.CommitSHA)
 			}
@@ -335,7 +335,7 @@ func (d *Detector) detectRule(fragment Fragment, currentRaw string, r config.Rul
 	if d.MaxTargetMegaBytes > 0 {
 		rawLength := len(currentRaw) / 1000000
 		if rawLength > d.MaxTargetMegaBytes {
-			log.Debug().Msgf("skipping file: %s scan due to size: %d", fragment.FilePath, rawLength)
+			logging.Debug().Msgf("skipping file: %s scan due to size: %d", fragment.FilePath, rawLength)
 			return findings
 		}
 	}
@@ -540,20 +540,20 @@ func (d *Detector) addFinding(finding report.Finding) {
 
 	// check if we should ignore this finding
 	if _, ok := d.gitleaksIgnore[globalFingerprint]; ok {
-		log.Debug().Msgf("ignoring finding with global Fingerprint %s",
+		logging.Debug().Msgf("ignoring finding with global Fingerprint %s",
 			finding.Fingerprint)
 		return
 	} else if finding.Commit != "" {
 		// Awkward nested if because I'm not sure how to chain these two conditions.
 		if _, ok := d.gitleaksIgnore[finding.Fingerprint]; ok {
-			log.Debug().Msgf("ignoring finding with Fingerprint %s",
+			logging.Debug().Msgf("ignoring finding with Fingerprint %s",
 				finding.Fingerprint)
 			return
 		}
 	}
 
 	if d.baseline != nil && !IsNew(finding, d.baseline) {
-		log.Debug().Msgf("baseline duplicate -- ignoring finding with Fingerprint %s", finding.Fingerprint)
+		logging.Debug().Msgf("baseline duplicate -- ignoring finding with Fingerprint %s", finding.Fingerprint)
 		return
 	}
 

+ 2 - 2
detect/directory.go

@@ -8,8 +8,8 @@ import (
 	"strings"
 
 	"github.com/h2non/filetype"
-	"github.com/rs/zerolog/log"
 
+	"github.com/zricethezav/gitleaks/v8/logging"
 	"github.com/zricethezav/gitleaks/v8/report"
 	"github.com/zricethezav/gitleaks/v8/sources"
 )
@@ -19,7 +19,7 @@ const maxPeekSize = 25 * 1_000 // 10kb
 func (d *Detector) DetectFiles(paths <-chan sources.ScanTarget) ([]report.Finding, error) {
 	for pa := range paths {
 		d.Sema.Go(func() error {
-			logger := log.With().Str("path", pa.Path).Logger()
+			logger := logging.With().Str("path", pa.Path).Logger()
 			logger.Trace().Msg("Scanning path")
 
 			f, err := os.Open(pa.Path)

+ 4 - 3
detect/git.go

@@ -2,7 +2,8 @@ package detect
 
 import (
 	"github.com/gitleaks/go-gitdiff/gitdiff"
-	"github.com/rs/zerolog/log"
+
+	"github.com/zricethezav/gitleaks/v8/logging"
 	"github.com/zricethezav/gitleaks/v8/report"
 	"github.com/zricethezav/gitleaks/v8/sources"
 )
@@ -67,7 +68,7 @@ func (d *Detector) DetectGit(gitCmd *sources.GitCmd) ([]report.Finding, error) {
 	if err := d.Sema.Wait(); err != nil {
 		return d.findings, err
 	}
-	log.Info().Msgf("%d commits scanned.", len(d.commitMap))
-	log.Debug().Msg("Note: this number might be smaller than expected due to commits with no additions")
+	logging.Info().Msgf("%d commits scanned.", len(d.commitMap))
+	logging.Debug().Msg("Note: this number might be smaller than expected due to commits with no additions")
 	return d.findings, nil
 }

+ 2 - 2
detect/utils.go

@@ -9,10 +9,10 @@ import (
 
 	"github.com/charmbracelet/lipgloss"
 
+	"github.com/zricethezav/gitleaks/v8/logging"
 	"github.com/zricethezav/gitleaks/v8/report"
 
 	"github.com/gitleaks/go-gitdiff/gitdiff"
-	"github.com/rs/zerolog/log"
 )
 
 // augmentGitFinding updates the start and end line numbers of a finding to include the
@@ -74,7 +74,7 @@ func filter(findings []report.Finding, redact uint) []report.Finding {
 
 					genericMatch := strings.Replace(f.Match, f.Secret, "REDACTED", -1)
 					betterMatch := strings.Replace(fPrime.Match, fPrime.Secret, "REDACTED", -1)
-					log.Trace().Msgf("skipping %s finding (%s), %s rule takes precedence (%s)", f.RuleID, genericMatch, fPrime.RuleID, betterMatch)
+					logging.Trace().Msgf("skipping %s finding (%s), %s rule takes precedence (%s)", f.RuleID, genericMatch, fPrime.RuleID, betterMatch)
 					include = false
 					break
 				}

+ 52 - 0
logging/log.go

@@ -0,0 +1,52 @@
+package logging
+
+import (
+	"os"
+
+	"github.com/rs/zerolog"
+)
+
+// TODO: Should this be a pointer?
+// https://github.com/rs/zerolog/issues/1
+var Logger zerolog.Logger
+
+func init() {
+	// send all logs to stdout
+	Logger = zerolog.New(zerolog.ConsoleWriter{Out: os.Stderr}).
+		Level(zerolog.InfoLevel).
+		With().Timestamp().Logger()
+}
+
+func With() zerolog.Context {
+	return Logger.With()
+}
+
+func Trace() *zerolog.Event {
+	return Logger.Trace()
+}
+
+func Debug() *zerolog.Event {
+	return Logger.Debug()
+}
+func Info() *zerolog.Event {
+	return Logger.Info()
+}
+func Warn() *zerolog.Event {
+	return Logger.Warn()
+}
+
+func Error() *zerolog.Event {
+	return Logger.Error()
+}
+
+func Err(err error) *zerolog.Event {
+	return Logger.Err(err)
+}
+
+func Fatal() *zerolog.Event {
+	return Logger.Fatal()
+}
+
+func Panic() *zerolog.Event {
+	return Logger.Panic()
+}

+ 2 - 6
main.go

@@ -4,15 +4,11 @@ import (
 	"os"
 	"os/signal"
 
-	"github.com/rs/zerolog"
-	"github.com/rs/zerolog/log"
 	"github.com/zricethezav/gitleaks/v8/cmd"
+	"github.com/zricethezav/gitleaks/v8/logging"
 )
 
 func main() {
-	// send all logs to stdout
-	log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
-
 	// this block sets up a go routine to listen for an interrupt signal
 	// which will immediately exit gitleaks
 	stopChan := make(chan os.Signal, 1)
@@ -24,5 +20,5 @@ func main() {
 
 func listenForInterrupt(stopScan chan os.Signal) {
 	<-stopScan
-	log.Fatal().Msg("Interrupt signal received. Exiting...")
+	logging.Fatal().Msg("Interrupt signal received. Exiting...")
 }

+ 3 - 2
sources/directory.go

@@ -6,7 +6,8 @@ import (
 	"path/filepath"
 
 	"github.com/fatih/semgroup"
-	"github.com/rs/zerolog/log"
+
+	"github.com/zricethezav/gitleaks/v8/logging"
 )
 
 type ScanTarget struct {
@@ -20,7 +21,7 @@ func DirectoryTargets(source string, s *semgroup.Group, followSymlinks bool, sho
 		defer close(paths)
 		return filepath.Walk(source,
 			func(path string, fInfo os.FileInfo, err error) error {
-				logger := log.With().Str("path", path).Logger()
+				logger := logging.With().Str("path", path).Logger()
 
 				if err != nil {
 					if os.IsPermission(err) {

+ 7 - 6
sources/git.go

@@ -10,7 +10,8 @@ import (
 	"strings"
 
 	"github.com/gitleaks/go-gitdiff/gitdiff"
-	"github.com/rs/zerolog/log"
+
+	"github.com/zricethezav/gitleaks/v8/logging"
 )
 
 var quotedOptPattern = regexp.MustCompile(`^(?:"[^"]+"|'[^']+')$`)
@@ -41,7 +42,7 @@ func NewGitLogCmd(source string, logOpts string) (*GitCmd, error) {
 			}
 		}
 		if len(quotedOpts) > 0 {
-			log.Warn().Msgf("the following `--log-opts` values may not work as expected: %v\n\tsee https://github.com/gitleaks/gitleaks/issues/1153 for more information", quotedOpts)
+			logging.Warn().Msgf("the following `--log-opts` values may not work as expected: %v\n\tsee https://github.com/gitleaks/gitleaks/issues/1153 for more information", quotedOpts)
 		}
 
 		args = append(args, userArgs...)
@@ -51,7 +52,7 @@ func NewGitLogCmd(source string, logOpts string) (*GitCmd, error) {
 			"--full-history", "--all")
 	}
 
-	log.Debug().Msgf("executing: %s", cmd.String())
+	logging.Debug().Msgf("executing: %s", cmd.String())
 
 	stdout, err := cmd.StdoutPipe()
 	if err != nil {
@@ -91,7 +92,7 @@ func NewGitDiffCmd(source string, staged bool) (*GitCmd, error) {
 		cmd = exec.Command("git", "-C", sourceClean, "diff", "-U0", "--no-ext-diff",
 			"--staged", ".")
 	}
-	log.Debug().Msgf("executing: %s", cmd.String())
+	logging.Debug().Msgf("executing: %s", cmd.String())
 
 	stdout, err := cmd.StdoutPipe()
 	if err != nil {
@@ -167,9 +168,9 @@ func listenForStdErr(stderr io.ReadCloser, errCh chan<- error) {
 				"inexact rename detection was skipped") ||
 			strings.Contains(scanner.Text(),
 				"you may want to set your diff.renameLimit") {
-			log.Warn().Msg(scanner.Text())
+			logging.Warn().Msg(scanner.Text())
 		} else {
-			log.Error().Msgf("[git] %s", scanner.Text())
+			logging.Error().Msgf("[git] %s", scanner.Text())
 			errEncountered = true
 		}
 	}