go-mana-component
Component identity propagation for layered Go libraries.
Source: https://git.wisehodl.dev/jay/go-mana-component Mirror: https://github.com/wisehodl/go-mana-component
What this library does
- Injects a named component identity into a
context.Contextat library boundaries - Propagates module identity and component hierarchy across layers
- Provides
slogattributes for structured logging and a string map for generic consumers
What this library does not do
go-mana-component does not log, does not define what a module or component
means semantically, and does not manage component lifecycles or dependencies.
It only carries identity. Interpretation, enforcement of naming conventions,
metrics, and tracing instrumentation all belong elsewhere.
Installation
go get git.wisehodl.dev/jay/go-mana-component
If the primary repository is unavailable, use the replace directive in your go.mod:
replace git.wisehodl.dev/jay/go-mana-component => github.com/wisehodl/go-mana-component latest
Usage
As an example, the go-honeybee library uses a three-layer component hierarchy
for pools, workers, and connections. To provide structured logging, each
component accepts a component-aware context and an slog.Handler and then
constructs a logger internally.
At a library boundary
A top-level constructor receives a context and creates a new component
identity. Injecting the component attributes on the logger allows it to carry
module and path automatically.
func NewPool(ctx context.Context, id string, handler slog.Handler) (*Pool, error) {
ctx = component.MustNew(ctx, "honeybee", "outbound_pool")
attrs, _ := component.Attrs(ctx)
logger := slog.New(handler).WithAttrs(attrs).With(slog.String("pool_id", id))
return &Pool{ctx: ctx, logger: logger}, nil
}
Descending into a sub-component
A child constructor calls MustExtend, inheriting the module and extending the
path. No parent identifiers need to be passed as arguments.
func NewWorker(ctx context.Context, id string, handler slog.Handler) (*Worker, error) {
ctx = component.MustExtend(ctx, "outbound_worker")
attrs, _ := component.Attrs(ctx)
logger := slog.New(handler).WithAttrs(attrs).With(slog.Any("peer_id", id))
return &Worker{ctx: ctx, logger: logger}, nil
}
At the connection layer, another MustExtend call extends the path to
outbound_pool.outbound_worker.connection with no additional plumbing.
GetFields provides the component fields as a map[string]string for non-slog
consumers.
Testing
go test ./...