grokkit/internal/logger/logger.go

122 lines
2.4 KiB
Go
Raw Normal View History

package logger
import (
"context"
"io"
"log/slog"
"os"
"path/filepath"
)
var (
logger *slog.Logger
level = new(slog.LevelVar) // Allows dynamic level changes
)
// Init initializes the logger with the specified log level
func Init(logLevel string) error {
home, err := os.UserHomeDir()
if err != nil {
home = "."
}
logDir := filepath.Join(home, ".config", "grokkit")
if err := os.MkdirAll(logDir, 0750); err != nil {
return err
}
logFile := filepath.Join(logDir, "grokkit.log")
file, err := os.OpenFile(logFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600)
if err != nil {
return err
}
// Parse log level
switch logLevel {
case "debug":
level.Set(slog.LevelDebug)
case "info":
level.Set(slog.LevelInfo)
case "warn":
level.Set(slog.LevelWarn)
case "error":
level.Set(slog.LevelError)
default:
level.Set(slog.LevelInfo)
}
// Create multi-writer for both file and stderr (if debug)
var w io.Writer = file
if logLevel == "debug" {
w = io.MultiWriter(file, os.Stderr)
}
// Use JSON handler for structured logging
handler := slog.NewJSONHandler(w, &slog.HandlerOptions{
Level: level,
})
logger = slog.New(handler)
slog.SetDefault(logger)
return nil
}
// SetLevel changes the log level dynamically
func SetLevel(logLevel string) {
switch logLevel {
case "debug":
level.Set(slog.LevelDebug)
case "info":
level.Set(slog.LevelInfo)
case "warn":
level.Set(slog.LevelWarn)
case "error":
level.Set(slog.LevelError)
}
}
// Debug logs at debug level with structured fields
func Debug(msg string, args ...any) {
if logger != nil {
logger.Debug(msg, args...)
}
}
// Info logs at info level with structured fields
func Info(msg string, args ...any) {
if logger != nil {
logger.Info(msg, args...)
}
}
// Warn logs at warn level with structured fields
func Warn(msg string, args ...any) {
if logger != nil {
logger.Warn(msg, args...)
}
}
// Error logs at error level with structured fields
func Error(msg string, args ...any) {
if logger != nil {
logger.Error(msg, args...)
}
}
// With returns a logger with additional context fields
func With(args ...any) *slog.Logger {
if logger != nil {
return logger.With(args...)
}
return slog.Default()
}
// WithContext returns a logger with values from context
func WithContext(ctx context.Context) *slog.Logger {
if logger != nil {
return logger.With(slog.Any("context", ctx))
}
return slog.Default()
}