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 Init(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 IsInitialized() 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}