feat(observability): configurable logging, request ids and error logs

- internal/logging: LOG_LEVEL/LOG_FORMAT parsing and slog handler
- request_id middleware (X-Request-ID or generated, echoed) + debug access log
- httpx registers errors; middleware logs internal causes with request_id
- health excluded, objects/sse debug-only, no query/body/secrets in logs
- new observability capability spec; README/.env.example docs
This commit is contained in:
iu
2026-10-11 13:40:11 +03:00
parent a5d0cee0eb
commit 6361e48b20
18 changed files with 998 additions and 5 deletions
+14 -4
View File
@@ -18,6 +18,7 @@ import (
"galo/internal/auth"
"galo/internal/config"
"galo/internal/db"
"galo/internal/logging"
"galo/internal/settings"
"galo/internal/sse"
"galo/internal/storage"
@@ -31,16 +32,25 @@ func main() {
loadDotEnv(".env")
loadDotEnv("../.env")
logger := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelInfo}))
slog.SetDefault(logger)
slog.Info("starting galo", "version", version)
cfg, err := config.Load()
if err != nil {
slog.Error("config error", "error", err)
os.Exit(1)
}
level, err := logging.ParseLevel(cfg.Log.Level)
if err != nil {
slog.Error("invalid log level", "error", err)
os.Exit(1)
}
handler, err := logging.NewHandler(cfg.Log.Format, level)
if err != nil {
slog.Error("invalid log format", "error", err)
os.Exit(1)
}
slog.SetDefault(slog.New(handler))
slog.Info("starting galo", "version", version)
switch cfg.Database.Backend {
case "sqlite":
slog.Info("metadata backend", "backend", "sqlite", "path", cfg.Database.SQLitePath)