1.AI 协作文档体系重构(objections/worklines/contracts+matrix.md) 2.coord 仲裁文档(final-decisions/cross-review/final-rulings/orchestration) 3.各服务 01/02 文档补全 4.共享包初始化(shared-ts/shared-go/hooks/ui-components/ui-tokens) 5.Proto 契约补全 6.004 架构影响地图更新 7.端口分配表 8.设计规格文档
66 lines
2.2 KiB
Go
66 lines
2.2 KiB
Go
// Package logger provides a structured logger built on zap with OpenTelemetry
|
|
// trace correlation.
|
|
//
|
|
// In production (the default) logs are emitted as JSON at Info level. When the
|
|
// ENV environment variable is set to "development" the logger switches to a
|
|
// console encoder at Debug level for human-readable output.
|
|
package logger
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
|
|
"go.opentelemetry.io/otel/trace"
|
|
"go.uber.org/zap"
|
|
"go.uber.org/zap/zapcore"
|
|
)
|
|
|
|
// ctxKey is an unexported type so context values cannot collide with callers.
|
|
type ctxKey struct{}
|
|
|
|
// fallback is returned by FromContext when no logger has been injected into
|
|
// the context; it discards all output so callers never receive a nil logger.
|
|
var fallback = zap.NewNop()
|
|
|
|
// New creates a structured logger tagged with serviceName. The encoder and
|
|
// level are selected from the ENV environment variable as described in the
|
|
// package documentation.
|
|
func New(serviceName string) *zap.Logger {
|
|
var cfg zap.Config
|
|
if os.Getenv("ENV") == "development" {
|
|
cfg = zap.NewDevelopmentConfig()
|
|
cfg.EncoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder
|
|
} else {
|
|
cfg = zap.NewProductionConfig()
|
|
cfg.Level = zap.NewAtomicLevelAt(zapcore.InfoLevel)
|
|
}
|
|
|
|
l, err := cfg.Build(zap.Fields(zap.String("service", serviceName)))
|
|
if err != nil {
|
|
// A logger that cannot be constructed is a fatal misconfiguration;
|
|
// there is no safe way to continue.
|
|
panic(err)
|
|
}
|
|
return l
|
|
}
|
|
|
|
// WithContext returns a copy of ctx that carries l so it can later be
|
|
// retrieved via FromContext.
|
|
func WithContext(ctx context.Context, l *zap.Logger) context.Context {
|
|
return context.WithValue(ctx, ctxKey{}, l)
|
|
}
|
|
|
|
// FromContext returns the logger stored in ctx. When an active OpenTelemetry
|
|
// span is present, the returned logger is decorated with a trace_id field so
|
|
// log lines can be correlated to traces. If no logger was stored in ctx a
|
|
// no-op logger is returned.
|
|
func FromContext(ctx context.Context) *zap.Logger {
|
|
if v, ok := ctx.Value(ctxKey{}).(*zap.Logger); ok && v != nil {
|
|
if sc := trace.SpanContextFromContext(ctx); sc.HasTraceID() {
|
|
return v.With(zap.String("trace_id", sc.TraceID().String()))
|
|
}
|
|
return v
|
|
}
|
|
return fallback
|
|
}
|