slogotel

package module
v1.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 20, 2024 License: Apache-2.0 Imports: 8 Imported by: 3

README

slog-otel

Go Report Card codebeat badge GoDoc License

Go package that provides an implementation of log/slog's Handler interface that ensures a strong correlation between log records and Open-Telemetry spans by...

  1. Adding span and trace IDs to the log record.
  2. Adding context baggage members to the log record (can be disabled).
  3. Adding log record as span event (can be disabled).
  4. Adding log record attributes to the span event (can be disabled).
  5. Setting span status based on slog record level (only if >= slog.LevelError).

Usage

import (
    "context"
    "log/slog"

    "go.opentelemetry.io/otel/baggage"
    "go.opentelemetry.io/otel/trace"

    sdktrace "go.opentelemetry.io/otel/sdk/trace"
    slogotel "github.com/remychantenay/slog-otel"
)

// 1. Configure slog.
slog.SetDefault(slog.New(slogotel.OtelHandler{
    Next: slog.NewJSONHandler(os.Stdout, nil),
}))

// 2. Set up your logger.
logger := slog.Default()
logger = logger.With("component", "server")

// 3. (Optional) Add baggage to your context.
m1, _ := baggage.NewMember("key_1", "value_1")
m2, _ := baggage.NewMember("key_2", "value_2")
bag, _ := baggage.New(m1, m2)
ctx := baggage.ContextWithBaggage(context.Background(), bag)

// 4. Start your span.
ctx, span := tracer.Start(ctx, "operation-name")
defer span.End()

// 5. Log.
logger.InfoContext(ctx, "Hello world!", "locale", "en_US")
Example

The following initial log:

{
    "time": "2023-09-11T08:28:02.77215605Z",
    "level": "INFO",
    "component": "server",
    "msg": "Hello world!",
    "locale": "en_US"
}

... will be written as:

{
    "time": "2023-09-11T08:28:02.77215605Z",
    "level": "INFO",
    "component": "server",
    "msg": "Hello world!",
    "locale": "en_US",
    "trace_id": "a9938fd7a6313e0f27f3fc87f574bff6",
    "span_id": "ed58f84d8971bf60",
    "key_1": "value_1",
    "key_2": "value_2"
}

and the related span will look like:

 {
 	"Name": "GET /resources",
 	"SpanContext": {
 		"TraceID": "a9938fd7a6313e0f27f3fc87f574bff6",
 		"SpanID": "ed58f84d8971bf60",
 		...
 	},
 	"Parent": {
 		...
 	},
 	"SpanKind": 2,
 	"StartTime": "2023-09-11T08:28:02.761992425Z",
 	"EndTime": "2023-09-11T08:28:02.773230425Z",
 	"Attributes": [{
 			"Key": "http.method",
 			"Value": {
 				"Type": "STRING",
 				"Value": "GET"
 			}
 		},
		...
 	],
 	"Events": [{
 		"Name": "log_record",
 		"Attributes": [{
 				"Key": "msg",
 				"Value": {
 					"Type": "STRING",
 					"Value": "Hello world!"
 				}
 			},
 			{
 				"Key": "level",
 				"Value": {
 					"Type": "STRING",
 					"Value": "INFO"
 				}
 			},
 			{
 				"Key": "time",
 				"Value": {
 					"Type": "STRING",
 					"Value": "2023-09-11T08:28:02.77215605Z"
 				}
 			},
 			{
 				"Key": "locale",
 				"Value": {
 					"Type": "STRING",
 					"Value": "en_US"
 				}
 			},
 			{
 				"Key": "component",
 				"Value": {
 					"Type": "STRING",
 					"Value": "server"
 				}
 			}
 		],
 	}],
 	...
 }

License

Apache License Version 2.0

Documentation

Overview

Package slogotel provides a custom handler for `log/slog` to ensures strong correlation between log records and Open-Telemetry spans.

Usage

import (
	"context"
	"log/slog"

	"go.opentelemetry.io/otel/baggage"
	"go.opentelemetry.io/otel/trace"
	sdktrace "go.opentelemetry.io/otel/sdk/trace"
	slogotel "github.com/remychantenay/slog-otel"
)

// 1. Configure slog.
slog.SetDefault(slog.New(slogotel.OtelHandler{
	Next: slog.NewJSONHandler(os.Stdout, nil),
}))

// 2. Set up your logger.
logger := slog.Default()
logger = logger.With("component", "server")

// 3. (Optional) Add baggage to your context.
m1, _ := baggage.NewMember("key_1", "value_1")
m2, _ := baggage.NewMember("key_2", "value_2")
bag, _ := baggage.New(m1, m2)
ctx := baggage.ContextWithBaggage(context.Background(), bag)

// 4. Start your span.
tracer := sdktrace.NewTracerProvider().Tracer("server")
ctx, span := tracer.Start(ctx, "operation-name")
defer span.End()

// 5. Log.
logger.InfoContext(ctx, "Hello world!", "locale", "en_US")

Index

Constants

View Source
const (
	// TraceIDKey is the key used by the Otel handler
	// to inject the trace ID in the log record.
	TraceIDKey = "trace_id"
	// SpanIDKey is the key used by the Otel handler
	// to inject the span ID in the log record.
	SpanIDKey = "span_id"
	// SpanEventKey is the key used by the Otel handler
	// to inject the log record in the recording span, as a span event.
	SpanEventKey = "log_record"
)

Variables

This section is empty.

Functions

This section is empty.

Types

type HandlerFn

type HandlerFn func(slog.Handler) slog.Handler

HandlerFn defines the handler used by slog.Handler as return value.

func NewOtelHandler

func NewOtelHandler(opts ...OtelHandlerOpt) HandlerFn

NewOtelHandler creates and returns a new HandlerFn, which wraps a handler with OtelHandler to use with log/slog.

type OtelHandler

type OtelHandler struct {
	// Next represents the next handler in the chain.
	Next slog.Handler
	// NoBaggage determines whether to add context baggage members to the log record.
	NoBaggage bool
	// NoTraceEvents determines whether to record an event for every log on the active trace.
	NoTraceEvents bool
}

OtelHandler is an implementation of slog's Handler interface. Its role is to ensure correlation between logs and OTel spans by:

1. Adding otel span and trace IDs to the log record. 2. Adding otel context baggage members to the log record. 3. Setting slog record as otel span event. 4. Adding slog record attributes to the otel span event. 5. Setting span status based on slog record level (only if >= slog.LevelError).

func New added in v1.3.0

func New(next slog.Handler, opts ...OtelHandlerOpt) *OtelHandler

New creates a new OtelHandler to use with log/slog

func (OtelHandler) Enabled

func (h OtelHandler) Enabled(ctx context.Context, level slog.Level) bool

Enabled reports whether the logger emits log records at the given context and level. Note: We handover the decision down to the next handler.

func (OtelHandler) Handle

func (h OtelHandler) Handle(ctx context.Context, record slog.Record) error

Handle handles the provided log record and adds correlation between a slog record and an Open-Telemetry span.

func (OtelHandler) WithAttrs

func (h OtelHandler) WithAttrs(attrs []slog.Attr) slog.Handler

WithAttrs returns a new Otel whose attributes consists of handler's attributes followed by attrs.

func (OtelHandler) WithGroup

func (h OtelHandler) WithGroup(name string) slog.Handler

WithGroup returns a new Otel with a group, provided the group's name.

type OtelHandlerOpt added in v1.3.0

type OtelHandlerOpt func(handler *OtelHandler)

func WithNoBaggage added in v1.3.0

func WithNoBaggage(noBaggage bool) OtelHandlerOpt

WithNoBaggage returns an OtelHandlerOpt, which sets the NoBaggage flag

func WithNoTraceEvents added in v1.3.0

func WithNoTraceEvents(noTraceEvents bool) OtelHandlerOpt

WithNoTraceEvents returns an OtelHandlerOpt, which sets the NoTraceEvents flag

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL