diff --git a/go.mod b/go.mod index 38cd071dce..96118af4bb 100644 --- a/go.mod +++ b/go.mod @@ -45,7 +45,6 @@ require ( github.com/package-url/packageurl-go v0.1.5 github.com/parnurzeal/gorequest v0.3.0 github.com/pkg/errors v0.9.1 - github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d github.com/samber/lo v1.52.0 github.com/sirupsen/logrus v1.9.4 diff --git a/go.sum b/go.sum index 07b6bc21c8..7b32e85d5b 100644 --- a/go.sum +++ b/go.sum @@ -770,8 +770,6 @@ github.com/redis/rueidis v1.0.70 h1:O01v0Mt27/qXV9mKU/zahgxHdC8piHzIepqW4Nyzn/I= github.com/redis/rueidis v1.0.70/go.mod h1:lfdcZzJ1oKGKL37vh9fO3ymwt+0TdjkkUCJxbgpmcgQ= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= -github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 h1:mZHayPoR0lNmnHyvtYjDeq0zlVHn9K/ZXoy17ylucdo= -github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5/go.mod h1:GEXHk5HgEKCvEIIrSpFI3ozzG5xOKA2DVlEX/gGnewM= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= diff --git a/logging/filehook_test.go b/logging/filehook_test.go new file mode 100644 index 0000000000..b04cb28c60 --- /dev/null +++ b/logging/filehook_test.go @@ -0,0 +1,131 @@ +package logging + +import ( + "os" + "strings" + "testing" + + "github.com/sirupsen/logrus" +) + +func TestFileHookLevels(t *testing.T) { + h := &fileHook{ + path: os.DevNull, + formatter: &logrus.TextFormatter{}, + } + got := h.Levels() + if len(got) != len(logrus.AllLevels) { + t.Errorf("Levels() returned %d levels, want %d", len(got), len(logrus.AllLevels)) + } + for i, l := range logrus.AllLevels { + if got[i] != l { + t.Errorf("Levels()[%d] = %v, want %v", i, got[i], l) + } + } +} + +func TestFileHookFire(t *testing.T) { + tmpFile, err := os.CreateTemp(t.TempDir(), "filehook-*.log") + if err != nil { + t.Fatalf("failed to create temp file: %v", err) + } + if err := tmpFile.Close(); err != nil { + t.Fatalf("failed to close temp file: %v", err) + } + + h := &fileHook{ + path: tmpFile.Name(), + formatter: &logrus.TextFormatter{DisableColors: true, DisableTimestamp: true}, + } + + entry := &logrus.Entry{ + Logger: logrus.New(), + Level: logrus.InfoLevel, + Message: "hello from fire", + Data: logrus.Fields{}, + } + + if err := h.Fire(entry); err != nil { + t.Fatalf("Fire() returned error: %v", err) + } + + content, err := os.ReadFile(tmpFile.Name()) + if err != nil { + t.Fatalf("failed to read log file: %v", err) + } + if !strings.Contains(string(content), "hello from fire") { + t.Errorf("log file does not contain expected message, got: %q", string(content)) + } +} + +func TestFileHookFireAppends(t *testing.T) { + tmpFile, err := os.CreateTemp(t.TempDir(), "filehook-*.log") + if err != nil { + t.Fatalf("failed to create temp file: %v", err) + } + if err := tmpFile.Close(); err != nil { + t.Fatalf("failed to close temp file: %v", err) + } + + h := &fileHook{ + path: tmpFile.Name(), + formatter: &logrus.TextFormatter{DisableColors: true, DisableTimestamp: true}, + } + + for i, msg := range []string{"first message", "second message", "third message"} { + entry := &logrus.Entry{ + Logger: logrus.New(), + Level: logrus.InfoLevel, + Message: msg, + Data: logrus.Fields{}, + } + if err := h.Fire(entry); err != nil { + t.Fatalf("Fire() call %d returned error: %v", i, err) + } + } + + content, err := os.ReadFile(tmpFile.Name()) + if err != nil { + t.Fatalf("failed to read log file: %v", err) + } + s := string(content) + for _, msg := range []string{"first message", "second message", "third message"} { + if !strings.Contains(s, msg) { + t.Errorf("log file missing %q, got: %q", msg, s) + } + } +} + +func TestFileHookIntegration(t *testing.T) { + tmpFile, err := os.CreateTemp(t.TempDir(), "filehook-*.log") + if err != nil { + t.Fatalf("failed to create temp file: %v", err) + } + if err := tmpFile.Close(); err != nil { + t.Fatalf("failed to close temp file: %v", err) + } + + logger := logrus.New() + logger.Out = os.Stderr + logger.Level = logrus.DebugLevel + + logger.Hooks.Add(&fileHook{ + path: tmpFile.Name(), + formatter: &logrus.TextFormatter{DisableColors: true, DisableTimestamp: true}, + }) + + logger.Info("integration info message") + logger.Warn("integration warn message") + + content, err := os.ReadFile(tmpFile.Name()) + if err != nil { + t.Fatalf("failed to read log file: %v", err) + } + s := string(content) + if !strings.Contains(s, "integration info message") { + t.Errorf("log file missing info message, got: %q", s) + } + if !strings.Contains(s, "integration warn message") { + t.Errorf("log file missing warn message, got: %q", s) + } +} diff --git a/logging/logutil.go b/logging/logutil.go index 22752f65b9..e4a90edd1a 100644 --- a/logging/logutil.go +++ b/logging/logutil.go @@ -9,12 +9,35 @@ import ( "runtime" "github.com/k0kubun/pp" - "github.com/rifflock/lfshook" "github.com/sirupsen/logrus" formatter "github.com/kotakanbe/logrus-prefixed-formatter" ) +type fileHook struct { + path string + formatter logrus.Formatter +} + +func (h *fileHook) Levels() []logrus.Level { + return logrus.AllLevels +} + +func (h *fileHook) Fire(entry *logrus.Entry) error { + f, err := os.OpenFile(h.path, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600) + if err != nil { + return err + } + defer f.Close() + + b, err := h.formatter.Format(entry) + if err != nil { + return err + } + _, err = f.Write(b) + return err +} + // LogOpts has options for logging type LogOpts struct { Debug bool `json:"debug,omitempty"` @@ -84,7 +107,7 @@ func NewCustomLogger(debug, quiet, logToFile bool, logDir, logMsgAnsiColor, serv } logFile := dir + "/vuls.log" - if file, err := os.OpenFile(logFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644); err == nil { + if file, err := os.OpenFile(logFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600); err == nil { log.Out = io.MultiWriter(os.Stderr, file) } else { log.Out = os.Stderr @@ -93,15 +116,12 @@ func NewCustomLogger(debug, quiet, logToFile bool, logDir, logMsgAnsiColor, serv if _, err := os.Stat(dir); err == nil { path := filepath.Join(dir, fmt.Sprintf("%s.log", whereami)) - if _, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644); err == nil { - log.Hooks.Add(lfshook.NewHook(lfshook.PathMap{ - logrus.DebugLevel: path, - logrus.InfoLevel: path, - logrus.WarnLevel: path, - logrus.ErrorLevel: path, - logrus.FatalLevel: path, - logrus.PanicLevel: path, - }, nil)) + if checkFile, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600); err == nil { + checkFile.Close() + log.Hooks.Add(&fileHook{ + path: path, + formatter: &logrus.TextFormatter{DisableColors: true}, + }) } else { log.Errorf("Failed to create log file. path: %s, err: %+v", path, err) }