Documentation
¶
Index ¶
- Constants
- Variables
- func ClearAllPackageLevels()
- func ClearPackageLevel(pkg string)
- func Close()
- func Debug(msg string, args ...any)
- func DebugLog() *log.Logger
- func DebugS(message string, fields ...map[string]interface{})
- func Error(msg string, args ...any)
- func ErrorLog() *log.Logger
- func ErrorS(message string, fields ...map[string]interface{})
- func FatalS(message string, fields ...map[string]interface{})
- func ForSession(sessionID string) *slog.Logger
- func GetActiveSessionLogPaths() map[string]string
- func GetConfigDir() (string, error)
- func GetGlobalLogPath() string
- func GetLogDir(cfg *LogConfig) (string, error)
- func GetLogFilePath(cfg *LogConfig) (string, error)
- func GetPackageLevels() map[string]LogLevel
- func GetSessionLogFilePath(cfg *LogConfig, sessionID string) (string, error)
- func GetTestLogDir() (string, error)
- func Info(msg string, args ...any)
- func InfoLog() *log.Logger
- func InfoS(message string, fields ...map[string]interface{})
- func Initialize(daemon bool)
- func InitializeForTests(fileLevel LogLevel, consoleLevel LogLevel)
- func InitializeWithConfig(daemon bool, externalConfig interface{})
- func IsDebugEnabled() bool
- func LoadPackageLevelsFromEnv()
- func LogForSession(sessionID, level, format string, v ...interface{})
- func LogSessionPathsToStderr()
- func PackageForPC(pc uintptr) string
- func SetDebugLogForTest(l *log.Logger) *log.Logger
- func SetErrorLogForTest(l *log.Logger) *log.Logger
- func SetInfoLogForTest(l *log.Logger) *log.Logger
- func SetPackageLevel(pkg string, level LogLevel)
- func SetRuntimeLevel(level LogLevel)
- func SetSlogDefaultForTest(l *slog.Logger) *slog.Logger
- func SetWarningLogForTest(l *log.Logger) *log.Logger
- func Warn(msg string, args ...any)
- func WarningLog() *log.Logger
- func WarningS(message string, fields ...map[string]interface{})
- type AsyncHandler
- func (h *AsyncHandler) Dropped() int64
- func (h *AsyncHandler) Enabled(ctx context.Context, level slog.Level) bool
- func (h *AsyncHandler) Flush(_ context.Context) error
- func (h *AsyncHandler) Handle(ctx context.Context, r slog.Record) error
- func (h *AsyncHandler) StartDrain()
- func (h *AsyncHandler) WithAttrs(attrs []slog.Attr) slog.Handler
- func (h *AsyncHandler) WithGroup(name string) slog.Handler
- type DropCounter
- type Every
- type LogConfig
- type LogLevel
- type LogManager
- type PackageLevelHandler
- type SessionLogger
- type SessionLoggers
- type StructuredLogEntry
- type StructuredLogger
- func (sl *StructuredLogger) Debug(message string, fields ...map[string]interface{})
- func (sl *StructuredLogger) Error(message string, fields ...map[string]interface{})
- func (sl *StructuredLogger) Fatal(message string, fields ...map[string]interface{})
- func (sl *StructuredLogger) Info(message string, fields ...map[string]interface{})
- func (sl *StructuredLogger) Log(level LogLevel, message string, fields map[string]interface{})
- func (sl *StructuredLogger) LogWithFields(level LogLevel, message string, fields map[string]interface{})
- func (sl *StructuredLogger) Warning(message string, fields ...map[string]interface{})
- type TraceIDHandler
Constants ¶
const DropLogInterval = 100
DropLogInterval is how often a rate-limited "dropped" warning is logged: only every Nth drop, to avoid flooding logs under sustained backpressure.
Variables ¶
var ( // ErrSessionLogsDisabled is returned when session logs are disabled in config ErrSessionLogsDisabled = fmt.Errorf("session logs disabled in config") )
Functions ¶
func ClearAllPackageLevels ¶ added in v1.49.0
func ClearAllPackageLevels()
ClearAllPackageLevels removes every override.
func ClearPackageLevel ¶ added in v1.49.0
func ClearPackageLevel(pkg string)
ClearPackageLevel removes a package's override, falling back to the global runtime level (or a less-specific ancestor override) for that package.
func Debug ¶ added in v1.35.0
Debug logs a debug-level message through the default slog handler. The handler drops debug records when the runtime level is above DEBUG, so this is safe to call without an IsDebugEnabled() guard.
func DebugLog ¶
DebugLog returns the current debug-level logger. Safe to call concurrently with SetDebugLogForTest or initializeWithConfig replacing it.
func ErrorLog ¶
ErrorLog returns the current error-level logger. Safe to call concurrently with SetErrorLogForTest or initializeWithConfig replacing it.
func ForSession ¶ added in v1.15.0
ForSession returns a *slog.Logger pre-populated with "session" = sessionID. All calls route through the async slog handler — no stdlib mutex serialization. Session-specific log files still receive the entry via LogForSession when needed.
func GetActiveSessionLogPaths ¶
GetActiveSessionLogPaths returns the paths to all active session log files
func GetConfigDir ¶
GetConfigDir returns the path to the application's configuration directory, honoring the same STAPLER_SQUAD_TEST_DIR / STAPLER_SQUAD_INSTANCE precedence as config.GetConfigDirForDir (Priorities 1-2 only; see that function's doc comment for the full 6-priority list — Priorities 3-6 are DB/session-state concerns with no log-directory analogue). Duplicated here rather than imported because config already imports log, and importing back would create a cycle.
func GetGlobalLogPath ¶
func GetGlobalLogPath() string
GetGlobalLogPath returns the path to the global log file
func GetLogFilePath ¶
GetLogFilePath returns the full path to the log file
func GetPackageLevels ¶ added in v1.49.0
GetPackageLevels returns a snapshot of the current overrides, keyed by package path, for display (e.g. the debug API / web UI).
func GetSessionLogFilePath ¶
GetSessionLogFilePath returns the full path to a session-specific log file
func GetTestLogDir ¶
GetTestLogDir returns the directory where test logs should be stored Test logs are isolated in a dedicated subdirectory for easy cleanup
func Info ¶ added in v1.35.0
Info logs an info-level message through the default slog handler (async, no mutex hold). args are alternating key-value pairs: log.Info("msg", "key", val, "key2", val2)
func InfoLog ¶
InfoLog returns the current info-level logger. Safe to call concurrently with SetInfoLogForTest or initializeWithConfig replacing it.
func Initialize ¶
func Initialize(daemon bool)
Initialize should be called once at the beginning of the program to set up logging. defer Close() after calling this function. It sets the go log output to the file in the configured log directory (default: ~/.stapler-squad/logs/).
Must run after config.LoadConfig() in any real entry point: GetConfigDir (used internally here) doesn't perform config.GetConfigDirForDir's legacy ~/.claude-squad migration, so calling this first would create ~/.stapler-squad ahead of migration and cause config's migration guard to skip it.
func InitializeForTests ¶
InitializeForTests sets up logging specifically for test environments with dual-stream configuration. This allows DEBUG logs to go to file while ERROR logs appear in console for immediate visibility.
Parameters:
- fileLevel: Minimum level for file logging (typically DEBUG to capture everything)
- consoleLevel: Minimum level for console logging (typically ERROR to avoid noise)
Example:
log.InitializeForTests(log.DEBUG, log.ERROR) // DEBUG→file, ERROR→console
func InitializeWithConfig ¶
func InitializeWithConfig(daemon bool, externalConfig interface{})
InitializeWithConfig sets up logging with the provided configuration.
func IsDebugEnabled ¶ added in v1.35.0
func IsDebugEnabled() bool
IsDebugEnabled returns true when the runtime level is DEBUG. Use this to gate expensive format-string construction before calling DebugLog.Printf.
func LoadPackageLevelsFromEnv ¶ added in v1.49.0
func LoadPackageLevelsFromEnv()
LoadPackageLevelsFromEnv parses STAPLER_SQUAD_LOG_LEVELS, a comma-separated list of "package=level" pairs (e.g. "session/tmux=debug,server/services=warn"), and installs them as package overrides. Call once at startup; safe to call again to re-parse. Malformed entries are skipped with a warning rather than failing startup.
func LogForSession ¶
func LogForSession(sessionID, level, format string, v ...interface{})
LogForSession logs a message to the session-specific log file
func LogSessionPathsToStderr ¶
func LogSessionPathsToStderr()
LogSessionPathsToStderr outputs session log file paths to stderr on exit
func PackageForPC ¶ added in v1.49.0
PackageForPC resolves a program counter to its module-relative package path, e.g. "session/tmux" — the same resolution PackageLevelHandler uses internally. Exposed for tests and for debug tooling that wants to preview how a given call site would be classified for STAPLER_SQUAD_LOG_LEVELS.
func SetDebugLogForTest ¶ added in v1.47.0
SetDebugLogForTest atomically replaces the debug logger and returns the previous value, so callers can restore it via t.Cleanup.
func SetErrorLogForTest ¶ added in v1.47.0
SetErrorLogForTest atomically replaces the error logger and returns the previous value, so callers can restore it via t.Cleanup.
func SetInfoLogForTest ¶ added in v1.47.0
SetInfoLogForTest atomically replaces the info logger and returns the previous value, so callers can restore it via t.Cleanup.
func SetPackageLevel ¶ added in v1.49.0
SetPackageLevel sets a minimum log level for one package (and, by prefix, its subpackages unless they have a more specific override — the same hierarchical-logger convention as Java's log4j/logback). Pass a path relative to the module root, e.g. "session/tmux" or "server/services".
func SetRuntimeLevel ¶ added in v1.35.0
func SetRuntimeLevel(level LogLevel)
SetRuntimeLevel changes the minimum log level for all output streams immediately. Safe to call from any goroutine. Takes effect on the next log call.
func SetSlogDefaultForTest ¶ added in v1.51.0
SetSlogDefaultForTest atomically replaces the slog-backed default logger (read by logAt/ForSession) and returns the previous value, so tests can restore it via t.Cleanup instead of calling slog.SetDefault() — which would also rewire stdlib log.Print process-wide and is the root cause of the server/services capture-buffer race under -race this seam removes tests from touching at all.
func SetWarningLogForTest ¶ added in v1.47.0
SetWarningLogForTest atomically replaces the warning logger and returns the previous value, so callers can restore it via t.Cleanup instead of racing a bare package-var assignment against concurrent t.Parallel() reads.
func WarningLog ¶
WarningLog returns the current warning-level logger. Safe to call concurrently with SetWarningLogForTest or initializeWithConfig replacing it.
Types ¶
type AsyncHandler ¶ added in v1.35.0
type AsyncHandler struct {
// contains filtered or unexported fields
}
AsyncHandler wraps a slog.Handler with a channel buffer. Log calls enqueue a cloned Record and return immediately; a background goroutine drains the channel. On full buffer the record is dropped and the drop counter increments. WithAttrs and WithGroup share the same underlying channel so a single goroutine drains all derived loggers.
func NewAsyncHandler ¶ added in v1.35.0
func NewAsyncHandler(next slog.Handler, bufSize int) *AsyncHandler
NewAsyncHandler wraps next with an async channel of bufSize capacity.
func (*AsyncHandler) Dropped ¶ added in v1.35.0
func (h *AsyncHandler) Dropped() int64
Dropped returns the number of records dropped due to a full buffer.
func (*AsyncHandler) Flush ¶ added in v1.35.0
func (h *AsyncHandler) Flush(_ context.Context) error
Flush closes the channel and waits for all enqueued records to be written. After Flush the handler must not be used.
func (*AsyncHandler) Handle ¶ added in v1.35.0
Handle enqueues the record for async writing. Drops and counts if buffer full. Safe to call concurrently with Flush — the RWMutex ensures close and send are mutually exclusive: Flush cannot close the channel while a send is in progress.
func (*AsyncHandler) StartDrain ¶ added in v1.35.0
func (h *AsyncHandler) StartDrain()
StartDrain launches the background drain goroutine. Must be called once before the handler is used. Call Flush to stop it and drain remaining work.
type DropCounter ¶ added in v1.49.0
type DropCounter struct {
// contains filtered or unexported fields
}
DropCounter rate-limits repeated "dropped due to backpressure" warnings: only every Nth drop is logged, with the running total attached. Shared by session/tokens and session/artifacts, whose worker-pool queues both need this exact pattern for queue-full drops.
func (*DropCounter) Hit ¶ added in v1.49.0
func (d *DropCounter) Hit() (total uint64, shouldLog bool)
Hit records one drop and reports the new running total plus whether this particular drop should be logged (every DropLogInterval-th one).
type Every ¶
type Every struct {
// contains filtered or unexported fields
}
Every is used to log at most once every timeout duration.
type LogConfig ¶
type LogConfig struct {
LogsEnabled bool
LogsDir string
LogMaxSize int
LogMaxFiles int
LogMaxAge int
LogCompress bool
UseSessionLogs bool
LogLevel LogLevel // Deprecated: Use FileLevel and ConsoleLevel instead
StructuredLogs bool
PrettyLogs bool // For development - formats JSON logs for readability
// Dual-stream logging configuration (file + console)
ConsoleEnabled bool // Enable/disable console output (default: true)
ConsoleLevel LogLevel // Minimum level for console (default: ERROR for tests, INFO for production)
FileEnabled bool // Enable/disable file output (default: true)
FileLevel LogLevel // Minimum level for file (default: DEBUG)
}
LogConfig holds logging configuration
func ConfigToLogConfig ¶
func ConfigToLogConfig(externalConfig interface{}) *LogConfig
ConfigToLogConfig converts an external config to our internal LogConfig
func DefaultLogConfig ¶
func DefaultLogConfig() *LogConfig
DefaultLogConfig returns the default logging configuration
type LogLevel ¶
type LogLevel int
LogLevel represents the severity of a log entry
func GetRuntimeLevel ¶ added in v1.35.0
func GetRuntimeLevel() LogLevel
GetRuntimeLevel returns the current minimum log level.
func ParseLogLevel ¶
ParseLogLevel parses a string into a LogLevel
type LogManager ¶ added in v1.35.0
type LogManager struct {
// contains filtered or unexported fields
}
LogManager encapsulates all log state that was previously in package-level globals. Use NewLogManager to create one; use the package-level functions (InfoLog, etc.) via the defaultManager for zero-migration compatibility.
func (*LogManager) Close ¶ added in v1.35.0
func (m *LogManager) Close()
Close drains async writers, flushes the slog handler, and closes all log files. Drain order matters: async writers must be drained before the underlying file is closed, otherwise buffered entries are lost.
func (*LogManager) CloseSession ¶ added in v1.35.0
func (m *LogManager) CloseSession(id string)
CloseSession removes session-scoped loggers and closes their file handle.
func (*LogManager) ForSession ¶ added in v1.35.0
func (m *LogManager) ForSession(id string) (*SessionLoggers, error)
ForSession returns or creates session-scoped loggers.
type PackageLevelHandler ¶ added in v1.49.0
type PackageLevelHandler struct {
// contains filtered or unexported fields
}
PackageLevelHandler wraps a slog.Handler and drops records that fall below the calling package's configured minimum level, resolved from the log call's program counter. Enabled fast-paths on the global level when no override is active; Handle does the precise per-package check otherwise.
func NewPackageLevelHandler ¶ added in v1.49.0
func NewPackageLevelHandler(next slog.Handler) *PackageLevelHandler
NewPackageLevelHandler wraps next with per-package level filtering.
func (*PackageLevelHandler) Enabled ¶ added in v1.49.0
Enabled restores slog's normal fast path (level >= global threshold) for the common no-override case, so logAt's own Enabled check can still skip runtime.Callers/NewRecord/Add for a disabled level. When a per-package override is active, it reports true unconditionally — Handle is the only place with enough information (the record's PC) to resolve the precise per-package threshold.
type SessionLogger ¶ added in v1.15.0
type SessionLogger struct {
// contains filtered or unexported fields
}
SessionLogger is a session-scoped logger that automatically injects the session ID into every log call, eliminating the need to pass the session ID manually.
Usage:
logger := log.ForSession(i.Title)
logger.Error("Failed to setup git worktree: %v", err)
func ForSessionLegacy
deprecated
added in
v1.35.0
func ForSessionLegacy(sessionID string) *SessionLogger
ForSessionLegacy returns the old SessionLogger for callers that write to per-session log files. New code should use ForSession instead.
Deprecated: use ForSession.
func (*SessionLogger) Debug ¶ added in v1.15.0
func (sl *SessionLogger) Debug(format string, v ...interface{})
func (*SessionLogger) Error ¶ added in v1.15.0
func (sl *SessionLogger) Error(format string, v ...interface{})
func (*SessionLogger) Info ¶ added in v1.15.0
func (sl *SessionLogger) Info(format string, v ...interface{})
func (*SessionLogger) Warning ¶ added in v1.15.0
func (sl *SessionLogger) Warning(format string, v ...interface{})
type SessionLoggers ¶
type SessionLoggers struct {
WarningLog *log.Logger
InfoLog *log.Logger
ErrorLog *log.Logger
DebugLog *log.Logger
LogFile io.Closer
}
SessionLoggers holds the loggers for a specific session
func GetSessionLoggers ¶
func GetSessionLoggers(sessionID string) (*SessionLoggers, error)
GetSessionLoggers creates or retrieves loggers for a specific session
type StructuredLogEntry ¶
type StructuredLogEntry struct {
Timestamp time.Time `json:"timestamp"`
Level string `json:"level"`
Message string `json:"message"`
SessionID string `json:"session_id,omitempty"`
Component string `json:"component,omitempty"`
Function string `json:"function,omitempty"`
File string `json:"file,omitempty"`
Line int `json:"line,omitempty"`
Fields map[string]interface{} `json:"fields,omitempty"`
Error string `json:"error,omitempty"`
}
StructuredLogEntry represents a structured log entry
type StructuredLogger ¶
type StructuredLogger struct {
// contains filtered or unexported fields
}
StructuredLogger provides structured logging functionality
func NewStructuredLogger ¶
func NewStructuredLogger(writer io.Writer, level LogLevel, prettyLog bool) *StructuredLogger
NewStructuredLogger creates a new structured logger
func (*StructuredLogger) Debug ¶
func (sl *StructuredLogger) Debug(message string, fields ...map[string]interface{})
Debug logs a debug message
func (*StructuredLogger) Error ¶
func (sl *StructuredLogger) Error(message string, fields ...map[string]interface{})
Error logs an error message
func (*StructuredLogger) Fatal ¶
func (sl *StructuredLogger) Fatal(message string, fields ...map[string]interface{})
Fatal logs a fatal message
func (*StructuredLogger) Info ¶
func (sl *StructuredLogger) Info(message string, fields ...map[string]interface{})
Info logs an info message
func (*StructuredLogger) Log ¶
func (sl *StructuredLogger) Log(level LogLevel, message string, fields map[string]interface{})
Log writes a structured log entry
func (*StructuredLogger) LogWithFields ¶
func (sl *StructuredLogger) LogWithFields(level LogLevel, message string, fields map[string]interface{})
LogWithFields logs a message with additional fields
func (*StructuredLogger) Warning ¶
func (sl *StructuredLogger) Warning(message string, fields ...map[string]interface{})
Warning logs a warning message
type TraceIDHandler ¶ added in v1.35.0
type TraceIDHandler struct {
// contains filtered or unexported fields
}
TraceIDHandler is a slog.Handler middleware that injects OTel trace_id and span_id into every log record when a span is active in the context. It must be the outermost handler in the chain so trace IDs are extracted at call time, before the record enters the async buffer.
func NewTraceIDHandler ¶ added in v1.35.0
func NewTraceIDHandler(next slog.Handler) *TraceIDHandler
NewTraceIDHandler wraps next, injecting trace context into every Handle call.