diff --git a/README.md b/README.md index c92056f..cd81878 100644 --- a/README.md +++ b/README.md @@ -57,39 +57,43 @@ go-watch-logs --file-path=my.log --match='HTTP/1.1" 50' --every=60 ## Help ```sh - -db-path string - path to store db file (default "/Users/pulkit.kathuria/.go-watch-logs.db") -every uint run every n seconds (0 to run once) -f string - (short for --file-path) full path to the log file + (short for --file-path) full path to the file to watch -file-path string - full path to the log file + full path to the file to watch -file-paths-cap int max number of file paths to watch (default 100) - -health-check-every uint - run health check every n seconds (0 to disable) + -file-recent-secs uint + only files modified in the last n seconds, 0 to disable (default 86400) -ignore string regex for ignoring errors (empty to ignore none) + -log-file string + full path to output log file. Empty will log to stdout -log-level int log level (0=info, -4=debug, 4=warn, 8=error) -match string regex for matching errors (empty to match all lines) + -mbf int + max buffer in MB, default is 0 (not provided) for go's default 64KB -mem-limit int - memory limit in MB (0 to disable) (default 100) + memory limit in MB (0 to disable) (default 128) -min int on minimum num of matches, it should notify (default 1) -ms-teams-hook string ms teams webhook - -post-min string + -post-cmd string run this shell command after every scan when min errors are found -proxy string http proxy for webhooks + -streak int + on minimum num of streak matches, it should notify (default 1) -test Quickly test paths or regex - # will test if the input matches the regex + # will test if the input matches the regex echo test123 | go-watch-logs --match=123 --test - # will test if the file paths are found and list them + # will test if the file paths are found and list them go-watch-logs --file-path=./ssl_access.*log --test -version diff --git a/main.go b/main.go index cec0a7f..52b29c3 100644 --- a/main.go +++ b/main.go @@ -99,7 +99,7 @@ func cronWatch() { func syncFilePaths() { slog.Info("Syncing files") - var err error + fpCrawled, err := pkg.FilesByPattern(f.FilePath, f.FileRecentSecs) if err != nil { slog.Error("Error finding files", "error", err.Error()) @@ -111,24 +111,25 @@ func syncFilePaths() { return } + // Filter and cap file paths filePathsMutex.Lock() - fpCrawled = pkg.Capped(f.FilePathsCap, fpCrawled) + defer filePathsMutex.Unlock() - fpFiltered := make([]string, 0, len(fpCrawled)) + filePaths = filterTextFiles(pkg.Capped(f.FilePathsCap, fpCrawled)) - for _, filePath := range fpCrawled { - isText, err := pkg.IsTextFile(filePath) - if err != nil || !isText { - continue + syncCaches() + slog.Info("Files synced", "fileCount", len(filePaths), "cacheCount", len(caches)) +} + +// filterTextFiles filters file paths to include only text files. +func filterTextFiles(paths []string) []string { + filtered := make([]string, 0, len(paths)) + for _, path := range paths { + if isText, err := pkg.IsTextFile(path); err == nil && isText { + filtered = append(filtered, path) } - fpFiltered = append(fpFiltered, filePath) } - filePaths = fpFiltered - - filePathsMutex.Unlock() - syncCaches() - slog.Info("Files found", "count", len(filePaths)) - slog.Info("Caches set", "count", len(caches)) + return filtered } func validate() { @@ -137,7 +138,7 @@ func validate() { } if f.FilePath == "" { slog.Error("file-path is required") - os.Exit(1) + return } } @@ -174,8 +175,8 @@ func reportResult(result *pkg.ScanResult) { slog.Info("History", "max streak", f.Streak, "current streaks", result.Streak, "symbols", pkg.StreakSymbols(result.Streak, f.Streak, f.Min)) slog.Info("Scan", "count", result.ScanCount) - // is first scan, cache isn't ready, so skip the notification - if result.ScanCount == 1 { + if result.IsFirstScan() { + slog.Info("First scan, skipping notification") return } diff --git a/pkg/log.go b/pkg/log.go index e278af1..cd963b3 100644 --- a/pkg/log.go +++ b/pkg/log.go @@ -13,6 +13,7 @@ import ( const ( AppLogLevelDebug = -4 + SlogErrorLabel = "ERROR" ) // GlobalHandler is a custom handler that catches all logs @@ -23,7 +24,7 @@ type GlobalHandler struct { } func (h *GlobalHandler) Handle(ctx context.Context, r slog.Record) error { - if r.Level.String() == "ERROR" { + if r.Level.String() == SlogErrorLabel { err := fmt.Errorf("global log capture - Level: %s, Message: %s", r.Level.String(), r.Message) NotifyOwnError(err, r, h.msTeamsHook, h.proxy) } diff --git a/pkg/notify.go b/pkg/notify.go index 552e974..9df7d83 100644 --- a/pkg/notify.go +++ b/pkg/notify.go @@ -10,6 +10,7 @@ import ( ) func NotifyOwnError(e error, r slog.Record, msTeamsHook, proxy string) { + slog.Info("Sending own error to MS Teams") hostname, _ := os.Hostname() details := []gmt.Details{ { @@ -41,7 +42,7 @@ func NotifyOwnError(e error, r slog.Record, msTeamsHook, proxy string) { } func Notify(result *ScanResult, f Flags, version string) { - slog.Info("Sending to MS Teams") + slog.Info("Sending scan results to MS Teams") details := []gmt.Details{ { Label: "go-watch-log version", diff --git a/pkg/watcher.go b/pkg/watcher.go index 93a4ff0..4b22fe4 100644 --- a/pkg/watcher.go +++ b/pkg/watcher.go @@ -72,6 +72,10 @@ type ScanResult struct { ScanCount int // Total number of scans performed } +func (r *ScanResult) IsFirstScan() bool { + return r.ScanCount == 1 +} + func (w *Watcher) Scan() (*ScanResult, error) { matchCounts := 0 firstLine := ""