Files
go-simple-api/internal/logging/logger.go
T
2026-07-16 10:13:46 +03:30

44 lines
1.7 KiB
Go

// Package logging builds the single *slog.Logger instance shared across the
// whole application. Every log line the app writes goes through this
// logger, formatted as JSON to stdout.
//
// Why JSON to stdout specifically? This is the standard "12-factor app"
// approach to logging: the application doesn't know or care where its logs
// end up (a file, Loki, Elasticsearch, ...) - it just writes structured
// lines to stdout, and an external agent (in your case, Grafana Alloy)
// takes care of collecting, parsing, and shipping them. Because every line
// is valid JSON with consistent keys, Alloy/Loki can index and query on
// fields like "status", "path", or "request_id" without any custom parsing
// rules or regexes.
package logging
import (
"log/slog"
"os"
)
// New builds and returns the application's structured logger.
//
// The minimum log level is controlled by the LOG_LEVEL environment
// variable: set LOG_LEVEL=debug to see verbose Debug()-level output;
// anything else (or unset) defaults to Info level, which hides Debug logs.
func New() *slog.Logger {
level := slog.LevelInfo
if os.Getenv("LOG_LEVEL") == "debug" {
level = slog.LevelDebug
}
// slog.NewJSONHandler formats every log record as a single-line JSON
// object and writes it to the given io.Writer (here, os.Stdout).
// Swapping this for slog.NewTextHandler would switch to human-readable
// text output instead - useful for local dev if you ever want it - but
// every other part of the app that calls logger.Info/Error/etc would
// stay completely unchanged, since they only depend on *slog.Logger,
// not on which Handler is behind it.
handler := slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
Level: level,
})
return slog.New(handler)
}