1package log
2
3import (
4 "fmt"
5 "log/slog"
6 "os"
7 "runtime/debug"
8 "sync"
9 "sync/atomic"
10 "time"
11
12 "gopkg.in/natefinch/lumberjack.v2"
13)
14
15var (
16 initOnce sync.Once
17 initialized atomic.Bool
18)
19
20func Setup(logFile string, debug bool) {
21 initOnce.Do(func() {
22 logRotator := &lumberjack.Logger{
23 Filename: logFile,
24 MaxSize: 10, // Max size in MB
25 MaxBackups: 0, // Number of backups
26 MaxAge: 30, // Days
27 Compress: false, // Enable compression
28 }
29
30 level := slog.LevelInfo
31 if debug {
32 level = slog.LevelDebug
33 }
34
35 logger := slog.NewJSONHandler(logRotator, &slog.HandlerOptions{
36 Level: level,
37 AddSource: true,
38 })
39
40 slog.SetDefault(slog.New(logger))
41 initialized.Store(true)
42 })
43}
44
45func Initialized() bool {
46 return initialized.Load()
47}
48
49func RecoverPanic(name string, cleanup func()) {
50 if r := recover(); r != nil {
51 // Create a timestamped panic log file
52 timestamp := time.Now().Format("20060102-150405")
53 filename := fmt.Sprintf("crush-panic-%s-%s.log", name, timestamp)
54
55 file, err := os.Create(filename)
56 if err == nil {
57 defer file.Close()
58
59 // Write panic information and stack trace
60 fmt.Fprintf(file, "Panic in %s: %v\n\n", name, r)
61 fmt.Fprintf(file, "Time: %s\n\n", time.Now().Format(time.RFC3339))
62 fmt.Fprintf(file, "Stack Trace:\n%s\n", debug.Stack())
63
64 // Execute cleanup function if provided
65 if cleanup != nil {
66 cleanup()
67 }
68 }
69 }
70}