Logging
The clog package wires log/slog into Salusa. It registers the logger as a
DI dependency, attaches request-scoped attributes to a context, and picks a
handler: human-friendly colored output on a terminal, text output otherwise,
or any custom slog.Handler.
Registering a logger
RegisterDefault(ctx) is called during kernel bootstrap in the generated
template. It builds a lazy singleton RootLogger at Info level and registers
*slog.Logger as a dependency:
kernel.Register(func(ctx context.Context, c *config.Config) {
clog.RegisterDefault(ctx)
})For a custom setup, Register(ctx, cfg) builds the handler from a Config (a
type with Handler() (slog.Handler, error)), and RegisterWith(ctx, h) takes
a slog.Handler directly. DefaultConfig wraps a slog.Level so the level
can come from the environment:
clog.Register(ctx, clog.NewDefaultConfig(level))DefaultHandler(level) returns a tint handler with error-aware rendering when
stderr is a TTY and a plain text handler otherwise.
Using the logger
The *slog.Logger is an ordinary injectable dependency, and clog.Use(ctx)
resolves it (falling back to slog.Default if none is registered):
type Handler struct {
Logger *slog.Logger `inject:""`
}
func (h *Handler) Handle(ctx context.Context) {
h.Logger.Info("processing order", slog.Int("id", 42))
}The kernel resolves the logger through clog.Use for its own startup and
shutdown messages, and clog.RegisterDefault also sets it as the global
log/slog default so anything using slog.Default() participates.
Context attributes
clog.With(ctx, attrs...) returns a context that adds the attributes to any
logger resolved from it. Attributes accumulate:
ctx := clog.With(r.Context(), slog.String("request_id", reqID))
ctx = clog.With(ctx, slog.String("user_id", userID))
logger := clog.Use(ctx) // carries both attributesThe kernel uses this to tag service logs (logger.With("service", name) via
StartServices), so every log line from a background service identifies its
source.
Sending logs to Loki
The clog/loki subpackage provides a Config that sends logs to a Grafana
Loki endpoint through slogloki:
clog.Register(ctx, &loki.Config{
Level: slog.LevelInfo,
URL: "http://loki:3100/loki/api/v1/push",
TenantID: "my-app",
})