Major changes: - Add internal/logging package with field constants, context propagation, sensitive data auto-redaction, and per-component log levels - Add worker timeout constants (TimeoutQuickOp, TimeoutHealthCheck, etc.) - Extend SDLC with callback handlers, generate endpoints, and executor - Add new cookbook trees for aeries and slackpath progression - Add skeleton templates for queue, realtime, and microservices - Add worker component template with async job processing - Refactor services and handlers to use new logging infrastructure - Split component.go into component_infra.go and component_listing.go Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
74 lines
2.0 KiB
Go
74 lines
2.0 KiB
Go
package logging
|
|
|
|
import (
|
|
"context"
|
|
"log/slog"
|
|
)
|
|
|
|
// RedactingHandler wraps an slog.Handler to redact sensitive data.
|
|
type RedactingHandler struct {
|
|
inner slog.Handler
|
|
}
|
|
|
|
// NewRedactingHandler creates a handler that redacts sensitive values.
|
|
func NewRedactingHandler(inner slog.Handler) *RedactingHandler {
|
|
return &RedactingHandler{inner: inner}
|
|
}
|
|
|
|
// Enabled implements slog.Handler.
|
|
func (h *RedactingHandler) Enabled(ctx context.Context, level slog.Level) bool {
|
|
return h.inner.Enabled(ctx, level)
|
|
}
|
|
|
|
// Handle implements slog.Handler.
|
|
func (h *RedactingHandler) Handle(ctx context.Context, r slog.Record) error {
|
|
// Clone the record with redacted attributes
|
|
newRecord := slog.NewRecord(r.Time, r.Level, r.Message, r.PC)
|
|
r.Attrs(func(a slog.Attr) bool {
|
|
newRecord.AddAttrs(h.redactAttr(a))
|
|
return true
|
|
})
|
|
return h.inner.Handle(ctx, newRecord)
|
|
}
|
|
|
|
// WithAttrs implements slog.Handler.
|
|
func (h *RedactingHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
|
|
redacted := make([]slog.Attr, len(attrs))
|
|
for i, a := range attrs {
|
|
redacted[i] = h.redactAttr(a)
|
|
}
|
|
return &RedactingHandler{inner: h.inner.WithAttrs(redacted)}
|
|
}
|
|
|
|
// WithGroup implements slog.Handler.
|
|
func (h *RedactingHandler) WithGroup(name string) slog.Handler {
|
|
return &RedactingHandler{inner: h.inner.WithGroup(name)}
|
|
}
|
|
|
|
// redactAttr redacts an attribute if its key or value is sensitive.
|
|
func (h *RedactingHandler) redactAttr(a slog.Attr) slog.Attr {
|
|
// Check if the field name indicates sensitive data
|
|
if IsSensitiveField(a.Key) {
|
|
return slog.String(a.Key, RedactedValue)
|
|
}
|
|
|
|
// Check the value based on its kind
|
|
switch a.Value.Kind() {
|
|
case slog.KindString:
|
|
s := a.Value.String()
|
|
if ContainsSensitiveData(s) {
|
|
return slog.String(a.Key, RedactedValue)
|
|
}
|
|
case slog.KindGroup:
|
|
// Recursively redact group attributes
|
|
attrs := a.Value.Group()
|
|
redacted := make([]slog.Attr, len(attrs))
|
|
for i, attr := range attrs {
|
|
redacted[i] = h.redactAttr(attr)
|
|
}
|
|
return slog.Attr{Key: a.Key, Value: slog.GroupValue(redacted...)}
|
|
}
|
|
|
|
return a
|
|
}
|