Garmin auth/sync routes move under /api/garmin/*; sync.Service becomes garmin.Sync with garmin.SyncConfig/ClientConfig; applog becomes internal/log; the test mock moves into the garmin package as MockClient (breaking the test-only import cycle the merge created); stale test URLs and type names updated to match. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
52 lines
1.6 KiB
Go
52 lines
1.6 KiB
Go
// Package applog provides geniusrun's structured JSON logging: a
|
|
// log/slog-based logger writing to stdout, plus context helpers so a
|
|
// logger enriched in one layer (e.g. internal/api's HTTP middleware,
|
|
// attaching a request_id) is picked up by another (e.g. internal/garmin's
|
|
// wrapper-call logging) without either package depending on the other.
|
|
package applog
|
|
|
|
import (
|
|
"context"
|
|
"io"
|
|
"log/slog"
|
|
"strings"
|
|
)
|
|
|
|
// NewLogger builds a JSON-handler *slog.Logger writing to w at the given
|
|
// level ("debug"|"info"|"warn"|"error", case-insensitive; anything else
|
|
// defaults to info).
|
|
func NewLogger(level string, w io.Writer) *slog.Logger {
|
|
return slog.New(slog.NewJSONHandler(w, &slog.HandlerOptions{Level: parseLevel(level)}))
|
|
}
|
|
|
|
func parseLevel(level string) slog.Level {
|
|
switch strings.ToLower(level) {
|
|
case "debug":
|
|
return slog.LevelDebug
|
|
case "warn":
|
|
return slog.LevelWarn
|
|
case "error":
|
|
return slog.LevelError
|
|
default:
|
|
return slog.LevelInfo
|
|
}
|
|
}
|
|
|
|
type ctxKey struct{}
|
|
|
|
// WithLogger returns a context carrying logger, retrievable via FromContext.
|
|
func WithLogger(ctx context.Context, logger *slog.Logger) context.Context {
|
|
return context.WithValue(ctx, ctxKey{}, logger)
|
|
}
|
|
|
|
// FromContext returns the logger stashed by WithLogger, or slog.Default()
|
|
// if none was -- callers (e.g. the background incremental-sync loop, or
|
|
// tests that don't bother injecting one) always get a working logger,
|
|
// never nil.
|
|
func FromContext(ctx context.Context) *slog.Logger {
|
|
if logger, ok := ctx.Value(ctxKey{}).(*slog.Logger); ok {
|
|
return logger
|
|
}
|
|
return slog.Default()
|
|
}
|