Documentation
¶
Overview ¶
Package wideslog collects slog records from one operation into a single structured record: a wide event.
Set up the logger once with New or JSONHandler, then wrap each operation:
ctx, event := wideslog.NewEvent(ctx, logger, "checkout")
event.Add(slog.String("request_id", "req-1"))
logger.InfoContext(ctx, "payment authorized")
event.End()
Log calls made with the returned context are buffered instead of being written immediately. End emits them as one record whose root carries the shared context, and the buffered lines live in the events field. Logs made without an active event pass through to the wrapped handler unchanged. Abort discards the buffered lines without emitting anything.
See the README and the example program for a full walkthrough.
Example ¶
package main
import (
"bytes"
"context"
"fmt"
"log/slog"
"github.com/lrweck/wideslog"
)
func main() {
var buf bytes.Buffer
logger := wideslog.JSONHandler(&buf, nil)
ctx, event := wideslog.NewEvent(context.Background(), logger, "checkout")
event.Add(slog.String("request_id", "req-1"))
logger.InfoContext(ctx, "customer loaded", "customer_id", "cus_42A19C")
logger.InfoContext(ctx, "payment authorized", "amount_cents", 12990)
event.End()
fmt.Println(buf.String())
}
Output:
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func JSONHandler ¶
JSONHandler returns a logger backed by slog's JSONHandler.
Types ¶
type Config ¶
type Config struct {
TimeMode TimeMode
OffsetUnit OffsetUnit
}
Config defines the timestamp behavior of an Event.
type Event ¶
type Event struct {
// contains filtered or unexported fields
}
Event collects request-scoped slog records into one wide event.
An Event is safe for concurrent use. This is useful when multiple goroutines contribute logs to the same request.
func FromContext ¶
FromContext returns the Event stored in ctx, or nil when none is present.
func NewEvent ¶
func NewEvent( ctx context.Context, logger *slog.Logger, msg string, options ...Option, ) (context.Context, *Event)
NewEvent begins collecting records for a request-scoped wide event.
msg identifies the operation and becomes the message of the root wide record. The returned context contains the Event. Any slog call made with this context is captured by a wideslog Handler.
NewEvent panics when logger is not backed by a wideslog Handler (use wideslog.New or wideslog.JSONHandler). A logger created with plain slog would silently emit records instead of buffering them.
NewEvent must be called on a context without an existing Event. Calling it twice stores the inner event in the context and the outer event stops collecting records.
func (*Event) Abort ¶ added in v0.1.2
func (e *Event) Abort()
Abort discards the event without emitting it, releasing the buffered records. Like End it is idempotent; any Add after it is ignored, and logs made through the event's context fall through to the wrapped handler.
func (*Event) Add ¶
Add attaches attributes to the root of the final wide event.
These attributes are not added to individual events.
func (*Event) End ¶
func (e *Event) End()
End emits the accumulated wide event, using the context captured at NewEvent.
End is idempotent. Only the first call emits the event, and no error is returned: an output handler that fails to write is treated the same way slog treats handler errors, silently.
The root record carries the message passed to NewEvent. Steps logged through the event's context, including the final one, live in the events field. The root record uses the highest level found in the buffered steps (Info when there are none), so handlers that only accept serious levels still receive it.
type Handler ¶
type Handler struct {
// contains filtered or unexported fields
}
Handler buffers slog records when an Event is present in the context.
When no Event is present, it behaves like the wrapped slog.Handler.
func NewHandler ¶
NewHandler returns a Handler that wraps next.
It returns an error when next is nil. Use New or JSONHandler for the convenience APIs, which panic on a nil handler the way slog.New does.
func (*Handler) Enabled ¶
Enabled reports whether the wrapped handler accepts level.
This preserves normal slog filtering behavior.
func (*Handler) Handle ¶
Handle buffers record in the active Event or forwards it to the wrapped handler when no Event exists.
A record reaching an Event that has already ended (via End or Abort) is forwarded to the wrapped handler so it is emitted as a standalone log instead of being silently discarded.
Levels the wrapped handler rejects are not buffered; filtering is enforced when the record arrives, matching what slog would do without an Event.
Only the attributes the logging handler adds beyond the Event's root scopes are attached to the buffered record: shared attributes are stripped from the matching scopes, so the group skeleton stays but the shared context is written once at the root.
type OffsetUnit ¶
type OffsetUnit uint8
OffsetUnit selects the unit used for relative event timestamps.
const ( // OffsetNanoseconds records offsets in nanoseconds. OffsetNanoseconds OffsetUnit = iota // OffsetMicroseconds records offsets in microseconds. OffsetMicroseconds // OffsetMilliseconds records offsets in milliseconds. OffsetMilliseconds )
func (OffsetUnit) String ¶
func (u OffsetUnit) String() string
type Option ¶
type Option func(*Config)
Option configures an Event created by NewEvent.
func WithOffsetUnit ¶
func WithOffsetUnit(unit OffsetUnit) Option
WithOffsetUnit sets the unit used when TimeOffset is enabled.
func WithTimeMode ¶ added in v0.1.2
WithTimeMode sets how individual event timestamps are represented.