/* Copyright © 2026 Craig Williams This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package log import ( "log/slog" "os" "reflect" "unsafe" "github.com/lmittmann/tint" ) var logLevel slog.LevelVar // Set up the logger using defaults func Init() { logLevel.Set(slog.LevelWarn) opts := &slog.HandlerOptions{ Level: &logLevel, } handler := slog.NewTextHandler(os.Stdout, opts) logger := slog.New(handler) slog.SetDefault(logger) } // Enable info level logging func EnableInfo() { if logLevel.Level() > slog.LevelInfo { logLevel.Set(slog.LevelInfo) slog.Info("Info logging enabled") } } // Enable debug level logging func EnableDebug() { if logLevel.Level() > slog.LevelDebug { logLevel.Set(slog.LevelDebug) slog.Debug("Debug logging enabled") } } func LogToTerminal() { opts := &tint.Options{ Level: &logLevel, TimeFormat: "*", } handler := tint.NewTextHandler(os.Stdout, opts) logger := slog.New(handler) slog.SetDefault(logger) } func IsJSONHandler(h slog.Handler) bool { val := reflect.ValueOf(h) // Ensure we are working with a pointer to a struct (*JSONHandler or *TextHandler or derived) if val.Kind() != reflect.Pointer || val.Elem().Kind() != reflect.Struct { return false } // Both JSONHandler and TextHandler wrap an unexported field named 'commonHandler' commonHandlerField := val.Elem().FieldByName("commonHandler") if !commonHandlerField.IsValid() { return false } // Get the underlying *commonHandler struct pointer // commonHandlerField is unexported, so we must use unsafe to bypass Go's safety checks ptr := reflect.NewAt( commonHandlerField.Type().Elem(), unsafe.Pointer(commonHandlerField.Pointer()), ) // Find the unexported 'json' boolean field inside commonHandler jsonField := ptr.Elem().FieldByName("json") if !jsonField.IsValid() { return false } // Read the boolean value using unsafe return *(*bool)(unsafe.Pointer(jsonField.UnsafeAddr())) }