This codebase uses Go's structured logging (log/slog) with charmbracelet/log as the handler backend for human-friendly formatted output.
--log-level Log level: debug, info, warn, error (default: "info")
--log-format Log format: text, json, logfmt (default: "text")
Environment variables override command-line flags:
LOG_LEVEL Overrides --log-level
LOG_FORMAT Overrides --log-format
# Run with debug logging
./windshift --log-level=debug
# Run with JSON output (useful for log aggregation)
./windshift --log-format=json
# Using environment variables
LOG_LEVEL=debug LOG_FORMAT=json ./windshift| Level | When to Use |
|---|---|
| debug | Detailed traces, performance metrics, request/response details. Only shown with --log-level=debug. |
| info | Normal operational events: startup, shutdown, significant state changes. Default visible level. |
| warn | Recoverable errors, deprecation notices, unexpected but handled conditions. |
| error | Failures requiring attention, unrecoverable errors, permission denials. |
All log messages use structured attributes for better filtering and analysis:
slog.Debug("item create request received")
slog.Info("service started", slog.String("version", version))
slog.Warn("cache initialization failed", slog.Any("error", err))
slog.Error("permission check failed",
slog.Int("user_id", userID),
slog.Int("workspace_id", workspaceID),
slog.Any("error", err))| Attribute | Type | Description |
|---|---|---|
component |
string | Subsystem identifier (e.g., "sso", "jira", "scm") |
error |
any | Error value for failures |
user_id |
int | User ID for user-related operations |
workspace_id |
int | Workspace ID for workspace operations |
item_id |
int | Item ID for item operations |
Use slog.String("component", "name") to identify subsystems:
| Component | Description |
|---|---|
sso |
SSO/OIDC authentication |
jira |
Jira integration |
scm |
SCM providers (GitHub, GitLab, etc.) |
notifications |
Notification service |
permissions |
Permission cache and checks |
attachments |
File attachments |
activity |
Activity tracking |
database |
Database operations |
Human-readable colored output, ideal for development:
INFO service started version=1.0.0
DEBUG creating session component=sso user_id=123
WARN cache initialization failed error="connection refused"
Machine-readable format for log aggregation systems:
{"level":"INFO","msg":"service started","version":"1.0.0"}
{"level":"DEBUG","msg":"creating session","component":"sso","user_id":123}Key-value format, compatible with many log analysis tools:
level=INFO msg="service started" version=1.0.0
level=DEBUG msg="creating session" component=sso user_id=123
Performance-critical sections use grouped timing attributes:
slog.Debug("item creation performance",
slog.Int("item_id", itemID),
slog.Group("timings_ms",
slog.Float64("validation", 1.23),
slog.Float64("transaction", 4.56),
slog.Float64("total", 7.89),
))In test files, use t.Logf() instead of slog:
func TestSomething(t *testing.T) {
t.Logf("Debug info: %v", data)
}-
Use appropriate log levels: Debug for development details, Info for operational events, Warn for recoverable issues, Error for failures.
-
Include context: Always include relevant IDs (user_id, workspace_id, item_id) to aid debugging.
-
Use component tags: Add
slog.String("component", "name")to identify the subsystem. -
Avoid sensitive data: Never log passwords, tokens, or other secrets.
-
Be concise: Log messages should be lowercase and descriptive without prefixes like "Error:".
The logger is initialized in internal/logger/logger.go and set as the default slog logger during application startup. All code can use slog.* functions directly without needing a logger instance.