package log import ( "context" "io" "log/slog" "path/filepath" "runtime" "strings" sdktrace "go.opentelemetry.io/otel/trace" ) var projectRoot = getCompileTimeModuleRoot() func getCompileTimeModuleRoot() string { // 获取当前函数的调用信息 _, file, _, ok := runtime.Caller(0) if !ok { return "" } // file 就是编译时的绝对路径 return filepath.Dir(filepath.Dir(file)) } func isProjectFile(file string) bool { // 检查文件是否在编译时的模块根目录下 if projectRoot != "" { if rel, err := filepath.Rel(projectRoot, file); err == nil { if !strings.HasPrefix(rel, "..") { return true } } } // 其他回退逻辑... return false } func NewContextHandler(w io.Writer, encoding string, opts *slog.HandlerOptions) slog.Handler { if strings.EqualFold(encoding, "json") { return &ContextHandler{ Handler: slog.NewJSONHandler(w, opts), } } return &ContextHandler{ Handler: slog.NewTextHandler(w, opts), } } type ContextHandler struct { slog.Handler encoding string } func (h *ContextHandler) Handle(ctx context.Context, r slog.Record) error { var attrs []slog.Attr spanCtx := sdktrace.SpanContextFromContext(ctx) if spanCtx.HasTraceID() { attrs = append(attrs, slog.String("trace", spanCtx.TraceID().String())) } if spanCtx.HasSpanID() { attrs = append(attrs, slog.String("span", spanCtx.SpanID().String())) } r.AddAttrs(attrs...) return h.Handler.Handle(ctx, r) }