package component import ( "context" "fmt" "log/slog" "slices" "strings" ) type componentKey int const storageKey componentKey = iota // Component identifies a named unit within a module and its position in the call hierarchy. type Component interface { Module() string Path() []string PathString() string LogValue() slog.Value } type component struct { module string path []string } func (c component) Module() string { return c.module } func (c component) Path() []string { return slices.Clone(c.path) } func (c component) PathString() string { return strings.Join(c.path, ".") } func (c component) LogValue() slog.Value { return slog.GroupValue( slog.String("module", c.module), slog.String("path", c.PathString()), ) } func insert(ctx context.Context, module string, name string, path []string) context.Context { return context.WithValue(ctx, storageKey, component{ module: module, path: append(path, name), }) } // FromContext retrieves the current component from the context; returns nil if none is present. func FromContext(ctx context.Context) Component { c, ok := ctx.Value(storageKey).(component) if !ok { return nil } return c } // FieldsFromContext returns the component as a string map with keys "module" and "path"; returns nil if none is present. func FieldsFromContext(ctx context.Context) map[string]string { c := FromContext(ctx) if c == nil { return nil } return map[string]string{ "module": c.Module(), "path": c.PathString(), } } // New sets a new component on the context, resetting any existing component. func New(ctx context.Context, module string, name string) (context.Context, error) { if ctx == nil { return nil, fmt.Errorf("context is nil") } if module == "" { return nil, fmt.Errorf("module cannot be empty") } if name == "" { return nil, fmt.Errorf("name cannot be empty") } return insert(ctx, module, name, []string{}), nil } // Extend appends name to the current component path, inheriting its module. func Extend(ctx context.Context, name string) (context.Context, error) { if ctx == nil { return nil, fmt.Errorf("context is nil") } c := FromContext(ctx) if c == nil { return nil, fmt.Errorf("missing parent component") } if name == "" { return nil, fmt.Errorf("name cannot be empty") } return insert(ctx, c.Module(), name, c.Path()), nil } // MustNew is New but panics on error. func MustNew(ctx context.Context, module string, name string) context.Context { if ctx == nil { panic("context is nil") } if module == "" { panic("module cannot be empty") } if name == "" { panic("name cannot be empty") } return insert(ctx, module, name, []string{}) } // MustExtend is Extend but panics on error. func MustExtend(ctx context.Context, name string) context.Context { if ctx == nil { panic("context is nil") } c := FromContext(ctx) if c == nil { panic("missing parent component") } if name == "" { panic("name cannot be empty") } return insert(ctx, c.Module(), name, c.Path()) }