Skip to content

Commit

Permalink
feat: notify own any error
Browse files Browse the repository at this point in the history
  • Loading branch information
kevincobain2000 committed Jan 14, 2025
1 parent 6442f97 commit 4223ca6
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 88 deletions.
17 changes: 1 addition & 16 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ var filePathsMutex sync.Mutex

func main() {
pkg.Parseflags(&f)
pkg.SetupLoggingStdout(f.LogLevel, f.LogFile) // nolint: errcheck
pkg.SetupLoggingStdout(f) // nolint: errcheck
flag.VisitAll(func(f *flag.Flag) {
slog.Info(f.Name, slog.String("value", f.Value.String()))
})
Expand All @@ -38,12 +38,10 @@ func main() {
var err error
newFilePaths, err := pkg.FilesByPattern(f.FilePath, f.NotifyOnlyRecent)
if err != nil {
pkg.NotifyOwnError(fmt.Errorf("error finding files: %s", err.Error()), f)
slog.Error("Error finding files", "error", err.Error())
return
}
if len(newFilePaths) == 0 {
pkg.NotifyOwnError(fmt.Errorf("no files found"), f)
slog.Error("No files found", "filePath", f.FilePath)
slog.Warn("Keep watching for new files")
}
Expand All @@ -57,12 +55,10 @@ func main() {
for _, filePath := range filePaths {
isText, err := pkg.IsTextFile(filePath)
if err != nil {
pkg.NotifyOwnError(fmt.Errorf("error checking if file is text: %s", err.Error()), f)
slog.Error("Error checking if file is text", "error", err.Error(), "filePath", filePath)
return
}
if !isText {
pkg.NotifyOwnError(fmt.Errorf("file is not a text file"), f)
slog.Error("File is not a text file", "filePath", filePath)
return
}
Expand All @@ -78,25 +74,21 @@ func main() {

func startCron() {
if err := gocron.Every(1).Second().Do(pkg.PrintMemUsage, &f); err != nil {
pkg.NotifyOwnError(fmt.Errorf("error scheduling memory usage: %s", err.Error()), f)
slog.Error("Error scheduling memory usage", "error", err.Error())
return
}
if err := gocron.Every(f.Every).Second().Do(syncFilePaths); err != nil {
pkg.NotifyOwnError(fmt.Errorf("error scheduling syncFilePaths: %s", err.Error()), f)
slog.Error("Error scheduling syncFilePaths", "error", err.Error())
return
}
if f.HealthCheckEvery > 0 {
if err := gocron.Every(f.HealthCheckEvery).Second().Do(sendHealthCheck); err != nil {
pkg.NotifyOwnError(fmt.Errorf("error scheduling health check: %s", err.Error()), f)
slog.Error("Error scheduling health check", "error", err.Error())
return
}
}

if err := gocron.Every(f.Every).Second().Do(cron); err != nil {
pkg.NotifyOwnError(fmt.Errorf("error scheduling cron: %s", err.Error()), f)
slog.Error("Error scheduling cron", "error", err.Error())
return
}
Expand All @@ -112,7 +104,6 @@ func cron() {
}
if f.PostAlways != "" {
if _, err := pkg.ExecShell(f.PostAlways); err != nil {
pkg.NotifyOwnError(fmt.Errorf("error running post always command: %s", err.Error()), f)
slog.Error("Error running post command", "error", err.Error())
}
}
Expand All @@ -122,12 +113,10 @@ func syncFilePaths() {
var err error
newFilePaths, err := pkg.FilesByPattern(f.FilePath, f.NotifyOnlyRecent)
if err != nil {
pkg.NotifyOwnError(fmt.Errorf("error finding files: %s", err.Error()), f)
slog.Error("Error finding files", "error", err.Error())
return
}
if len(newFilePaths) == 0 {
pkg.NotifyOwnError(fmt.Errorf("no files found"), f)
slog.Error("No files found", "filePath", f.FilePath)
slog.Warn("Keep watching for new files")
return
Expand Down Expand Up @@ -170,7 +159,6 @@ func sendHealthCheck() {

func validate() {
if f.FilePath == "" {
pkg.NotifyOwnError(fmt.Errorf("file-path is required"), f)
slog.Error("file-path is required")
os.Exit(1)
}
Expand All @@ -180,7 +168,6 @@ func watch(filePath string) {
watcher, err := pkg.NewWatcher(filePath, f)

if err != nil {
pkg.NotifyOwnError(fmt.Errorf("error creating watcher: %s", err.Error()), f)
slog.Error("Error creating watcher", "error", err.Error(), "filePath", filePath)
return
}
Expand All @@ -190,7 +177,6 @@ func watch(filePath string) {

result, err := watcher.Scan()
if err != nil {
pkg.NotifyOwnError(fmt.Errorf("error scanning file: %s", err.Error()), f)
slog.Error("Error scanning file", "error", err.Error(), "filePath", filePath)
return
}
Expand All @@ -216,7 +202,6 @@ func watch(filePath string) {
}
if f.PostCommand != "" {
if _, err := pkg.ExecShell(f.PostCommand); err != nil {
pkg.NotifyOwnError(fmt.Errorf("error running post command: %s", err.Error()), f)
slog.Error("Error running post command", "error", err.Error())
}
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func Parseflags(f *Flags) {
sends health check ping to ms teams webhook
`)
flag.IntVar(&f.LogLevel, "log-level", 0, "log level (0=info, -4=debug, 4=warn, 8=error)")
flag.IntVar(&f.MemLimit, "mem-limit", 300, "memory limit in MB (0 to disable)")
flag.IntVar(&f.MemLimit, "mem-limit", 256, "memory limit in MB (0 to disable)")
flag.IntVar(&f.FilePathsCap, "file-paths-cap", 100, "max number of file paths to watch")
flag.IntVar(&f.Min, "min", 1, "on minimum num of matches, it should notify")
flag.BoolVar(&f.NotifyOnlyRecent, "notify-only-recent", true, "Notify on latest file only by timestamp based on --every")
Expand Down
67 changes: 53 additions & 14 deletions pkg/log.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package pkg

import (
"context"
"fmt"
"log/slog"
"os"
Expand All @@ -10,25 +11,63 @@ import (
"github.com/natefinch/lumberjack"
)

func SetupLoggingStdout(logLevel int, logFile string) error {
// GlobalHandler is a custom handler that catches all logs
type GlobalHandler struct {
next slog.Handler
msTeamsHook string
proxy string
}

func (h *GlobalHandler) Handle(ctx context.Context, r slog.Record) error {
if r.Level.String() == "ERROR" {
err := fmt.Errorf("global log capture - Level: %s, Message: %s", r.Level.String(), r.Message)
NotifyOwnError(err, r, h.msTeamsHook, h.proxy)
}

return h.next.Handle(ctx, r)
}

func (h *GlobalHandler) Enabled(ctx context.Context, level slog.Level) bool {
return h.next.Enabled(ctx, level)
}

func (h *GlobalHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
return &GlobalHandler{next: h.next.WithAttrs(attrs)}
}

func (h *GlobalHandler) WithGroup(name string) slog.Handler {
return &GlobalHandler{next: h.next.WithGroup(name)}
}

func SetupLoggingStdout(f Flags) error {
opts := &slogcolor.Options{
Level: slog.Level(logLevel),
Level: slog.Level(f.LogLevel),
TimeFormat: "2006-01-02 15:04:05",
NoColor: !isatty.IsTerminal(os.Stderr.Fd()),
SrcFileMode: slogcolor.ShortFile,
}
if logFile == "" {
slog.SetDefault(slog.New(slogcolor.NewHandler(os.Stderr, opts)))
return nil

var handler slog.Handler
if f.LogFile == "" {
handler = slogcolor.NewHandler(os.Stdout, opts)
} else {
handler = slogcolor.NewHandler(&lumberjack.Logger{
Filename: f.LogFile,
MaxSize: 10, // megabytes
MaxBackups: 3,
MaxAge: 3, // days
LocalTime: true,
Compress: true,
}, opts)
fmt.Println("logging to file", f.LogFile)
}

// Wrap the handler with the GlobalHandler
globalHandler := &GlobalHandler{
next: handler,
msTeamsHook: f.MSTeamsHook,
proxy: f.Proxy,
}
slog.SetDefault(slog.New(slogcolor.NewHandler(&lumberjack.Logger{
Filename: logFile,
MaxSize: 10, // megabytes
MaxBackups: 3,
MaxAge: 3, // days
LocalTime: true,
Compress: true,
}, opts)))
fmt.Println("logging to file", logFile)
slog.SetDefault(slog.New(globalHandler))
return nil
}
44 changes: 13 additions & 31 deletions pkg/notify.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,11 @@ import (
"fmt"
"log/slog"
"os"
"runtime"

gmt "github.com/kevincobain2000/go-msteams/src"
)

func NotifyOwnError(e error, f Flags) {
func NotifyOwnError(e error, r slog.Record, msTeamsHook, proxy string) {
hostname, _ := os.Hostname()
details := []gmt.Details{
{
Expand All @@ -21,7 +20,18 @@ func NotifyOwnError(e error, f Flags) {
Message: e.Error(),
},
}
err := gmt.Send(hostname, details, f.MSTeamsHook, f.Proxy)
r.Attrs(func(attr slog.Attr) bool {
details = append(details, gmt.Details{
Label: attr.Key,
Message: fmt.Sprintf("%v", attr.Value),
})
return true
})
if msTeamsHook == "" {
slog.Warn("MS Teams hook not set")
return
}
err := gmt.Send(hostname, details, msTeamsHook, proxy)
if err != nil {
slog.Error("Error sending to Teams", "error", err.Error())
} else {
Expand Down Expand Up @@ -54,34 +64,6 @@ func Notify(result *ScanResult, f Flags, version string) {
}
}

func GetPanicDetails(f *Flags, m *runtime.MemStats) []gmt.Details {
return []gmt.Details{
{
Label: "File Path",
Message: f.FilePath,
},
{
Label: "Match Pattern",
Message: f.Match,
},
{
Label: "Ignore Pattern",
Message: f.Ignore,
},
{
Label: "Panic Message",
Message: "go-watch-logs has panicked",
},
{
Label: "Mem Limit",
Message: fmt.Sprintf("%d(MB)", f.MemLimit),
},
{
Label: "Alloc",
Message: fmt.Sprintf("%d(MB)", BToMb(m.Alloc)),
},
}
}
func GetHealthCheckDetails(f *Flags, version string) []gmt.Details {
return []gmt.Details{
{
Expand Down
27 changes: 1 addition & 26 deletions pkg/system.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import (
"os"
"os/exec"
"runtime"

gmt "github.com/kevincobain2000/go-msteams/src"
)

func SystemProxy() string {
Expand All @@ -33,7 +31,7 @@ func PrintMemUsage(f *Flags) {
"HeapSys (Bytes)", m.HeapSys,
)
if f.MemLimit > 0 && m.Alloc > uint64(f.MemLimit)*1024*1024 {
sendPanicCheck(f, &m)
slog.Error("Memory Limit Exceeded", "limit", f.MemLimit, "current", BToMb(m.Alloc))
panic("Memory Limit Exceeded")
}
}
Expand All @@ -48,29 +46,6 @@ func ExecShell(command string) (string, error) {
return string(out), err
}

func sendPanicCheck(f *Flags, m *runtime.MemStats) {
details := GetPanicDetails(f, m)
var logDetails []interface{} // nolint: prealloc
for _, detail := range details {
logDetails = append(logDetails, detail.Label, detail.Message)
}
slog.Warn("Sending Panic Check", logDetails...)

if f.MSTeamsHook == "" {
slog.Warn("MS Teams hook not set")
return
}

hostname, _ := os.Hostname()

err := gmt.Send(hostname, details, f.MSTeamsHook, f.Proxy)
if err != nil {
slog.Error("Error sending to Teams", "error", err.Error())
} else {
slog.Info("Successfully sent to MS Teams")
}
}

func ReadFromPipeInput() string {
fi, _ := os.Stdin.Stat()
if (fi.Mode() & os.ModeCharDevice) == 0 {
Expand Down

0 comments on commit 4223ca6

Please sign in to comment.