swap from standalone attrs call to slog.LogValuer interface
This commit is contained in:
@@ -9,7 +9,7 @@ Mirror: https://github.com/wisehodl/go-mana-component
|
|||||||
|
|
||||||
- Injects a named component identity into a `context.Context` at library boundaries
|
- Injects a named component identity into a `context.Context` at library boundaries
|
||||||
- Propagates module identity and component hierarchy across layers
|
- Propagates module identity and component hierarchy across layers
|
||||||
- Provides `slog` attributes for structured logging and a string map for generic consumers
|
- Implements `slog.LogValuer` for use as a structured log attribute, and provides a string map for generic consumers
|
||||||
|
|
||||||
## What this library does not do
|
## What this library does not do
|
||||||
|
|
||||||
@@ -40,15 +40,15 @@ constructs a logger internally.
|
|||||||
### At a library boundary
|
### At a library boundary
|
||||||
|
|
||||||
A top-level constructor receives a context and creates a new component
|
A top-level constructor receives a context and creates a new component
|
||||||
identity. Injecting the component attributes on the logger allows it to carry
|
identity. Passing the component as a `slog.Any` group attribute allows the
|
||||||
`module` and `path` automatically.
|
logger to carry `module` and `path` automatically.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func NewPool(ctx context.Context, id string, handler slog.Handler) (*Pool, error) {
|
func NewPool(ctx context.Context, id string, handler slog.Handler) (*Pool, error) {
|
||||||
ctx = component.MustNew(ctx, "honeybee", "outbound_pool")
|
ctx = component.MustNew(ctx, "honeybee", "outbound_pool")
|
||||||
|
|
||||||
attrs, _ := component.Attrs(ctx)
|
c, _ := component.Get(ctx)
|
||||||
logger := slog.New(handler).WithAttrs(attrs).With(slog.String("pool_id", id))
|
logger := slog.New(handler).With(slog.Any("component", c), slog.String("pool_id", id))
|
||||||
|
|
||||||
return &Pool{ctx: ctx, logger: logger}, nil
|
return &Pool{ctx: ctx, logger: logger}, nil
|
||||||
}
|
}
|
||||||
@@ -63,8 +63,8 @@ path. No parent identifiers need to be passed as arguments.
|
|||||||
func NewWorker(ctx context.Context, id string, handler slog.Handler) (*Worker, error) {
|
func NewWorker(ctx context.Context, id string, handler slog.Handler) (*Worker, error) {
|
||||||
ctx = component.MustExtend(ctx, "outbound_worker")
|
ctx = component.MustExtend(ctx, "outbound_worker")
|
||||||
|
|
||||||
attrs, _ := component.Attrs(ctx)
|
c, _ := component.Get(ctx)
|
||||||
logger := slog.New(handler).WithAttrs(attrs).With(slog.Any("peer_id", id))
|
logger := slog.New(handler).With(slog.Any("component", c), slog.Any("peer_id", id))
|
||||||
|
|
||||||
return &Worker{ctx: ctx, logger: logger}, nil
|
return &Worker{ctx: ctx, logger: logger}, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ type Component interface {
|
|||||||
Module() string
|
Module() string
|
||||||
Path() []string
|
Path() []string
|
||||||
PathString() string
|
PathString() string
|
||||||
|
LogValue() slog.Value
|
||||||
}
|
}
|
||||||
|
|
||||||
type component struct {
|
type component struct {
|
||||||
@@ -27,6 +28,12 @@ type component struct {
|
|||||||
func (c component) Module() string { return c.module }
|
func (c component) Module() string { return c.module }
|
||||||
func (c component) Path() []string { return slices.Clone(c.path) }
|
func (c component) Path() []string { return slices.Clone(c.path) }
|
||||||
func (c component) PathString() string { return strings.Join(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 {
|
func insert(ctx context.Context, module string, name string, path []string) context.Context {
|
||||||
return context.WithValue(ctx, storageKey, component{
|
return context.WithValue(ctx, storageKey, component{
|
||||||
@@ -117,16 +124,3 @@ func GetFields(ctx context.Context) (map[string]string, bool) {
|
|||||||
"path": c.PathString(),
|
"path": c.PathString(),
|
||||||
}, true
|
}, true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attrs returns the slog projection of GetFields.
|
|
||||||
func Attrs(ctx context.Context) ([]slog.Attr, bool) {
|
|
||||||
fields, ok := GetFields(ctx)
|
|
||||||
if !ok {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
|
|
||||||
return []slog.Attr{
|
|
||||||
slog.String("module", fields["module"]),
|
|
||||||
slog.String("path", fields["path"]),
|
|
||||||
}, true
|
|
||||||
}
|
|
||||||
|
|||||||
+12
-17
@@ -2,7 +2,6 @@ package component
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"log/slog"
|
|
||||||
"slices"
|
"slices"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
@@ -120,22 +119,18 @@ func TestGetFields(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func assertAttr(t *testing.T, attr slog.Attr, key string, value string) {
|
func TestLogValue(t *testing.T) {
|
||||||
t.Helper()
|
|
||||||
if attr.Key != key {
|
|
||||||
t.Errorf("expected attr key %q, got %q", key, attr.Key)
|
|
||||||
}
|
|
||||||
if attr.Value.String() != value {
|
|
||||||
t.Errorf("expected attr value %q, got %q", value, attr.Value.String())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAttrs(t *testing.T) {
|
|
||||||
ctx := MustNew(context.Background(), "mymodule", "mycomponent")
|
ctx := MustNew(context.Background(), "mymodule", "mycomponent")
|
||||||
attrs, ok := Attrs(ctx)
|
c, _ := Get(ctx)
|
||||||
if !ok {
|
v := c.LogValue()
|
||||||
t.Fatal("expected attrs in context")
|
attrs := v.Group()
|
||||||
|
if len(attrs) != 2 {
|
||||||
|
t.Fatalf("expected 2 attrs, got %d", len(attrs))
|
||||||
|
}
|
||||||
|
if attrs[0].Key != "module" || attrs[0].Value.String() != "mymodule" {
|
||||||
|
t.Errorf("expected module=mymodule, got %s=%s", attrs[0].Key, attrs[0].Value.String())
|
||||||
|
}
|
||||||
|
if attrs[1].Key != "path" || attrs[1].Value.String() != "mycomponent" {
|
||||||
|
t.Errorf("expected path=mycomponent, got %s=%s", attrs[1].Key, attrs[1].Value.String())
|
||||||
}
|
}
|
||||||
assertAttr(t, attrs[0], "module", "mymodule")
|
|
||||||
assertAttr(t, attrs[1], "path", "mycomponent")
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user