package logging import ( "context" "log/slog" "os" "path/filepath" "gemserve/config" "github.com/lmittmann/tint" ) type contextKey string const CtxLoggerKey contextKey = "logger" var ( programLevel *slog.LevelVar = new(slog.LevelVar) // Info by default Logger *slog.Logger ) func WithLogger(ctx context.Context, logger *slog.Logger) context.Context { return context.WithValue(ctx, CtxLoggerKey, logger) } func WithAttr(logger *slog.Logger, attrName string, attrValue interface{}) *slog.Logger { return logger.With(attrName, attrValue) } func FromContext(ctx context.Context) *slog.Logger { if logger, ok := ctx.Value(CtxLoggerKey).(*slog.Logger); ok { return logger } // Return default logger instead of panicking return slog.Default() } func SetupLogging() { programLevel.Set(config.CONFIG.LogLevel) // With coloring (uses external package) opts := &tint.Options{ AddSource: true, Level: programLevel, ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr { if a.Key == slog.SourceKey { if source, ok := a.Value.Any().(*slog.Source); ok { source.File = filepath.Base(source.File) } } // Customize level colors: // gray for debug, blue for info, // yellow for warnings, black on red bg for errors if a.Key == slog.LevelKey && len(groups) == 0 { level, ok := a.Value.Any().(slog.Level) if ok { switch level { case slog.LevelDebug: // Use grayscale color (232-255 range) for gray/faint debug messages return tint.Attr(240, a) case slog.LevelInfo: // Use color code 12 (bright blue) for info return tint.Attr(12, a) case slog.LevelWarn: // Use color code 11 (bright yellow) for warnings return tint.Attr(11, a) case slog.LevelError: // For black on red background, we need to modify the string value directly // since tint.Attr() only supports foreground colors return slog.String(a.Key, "\033[30;41m"+a.Value.String()+"\033[0m") } } } return a }, } Logger = slog.New(tint.NewHandler(os.Stdout, opts)) }