π¨ slog: Loki handler
See the codeA Loki Handler for slog Go library.
See also:
slog.Handler chaining, fanout, routing, failover, load balancing...slog attribute formattingslog sampling policyslog.Handler for test purposesHTTP middlewares:
slog loggerslog loggerslog loggerslog loggernet/http middleware for slog loggerLoggers:
slog handler for Zapslog handler for Zerologslog handler for LogrusLog sinks:
slog handler for Datadogslog handler for Betterstackslog handler for Rollbarslog handler for Lokislog handler for Sentryslog handler for Syslogslog handler for Logstashslog handler for Fluentdslog handler for Graylogslog handler for Quickwitslog handler for Slackslog handler for Telegramslog handler for Mattermostslog handler for Microsoft Teamsslog handler for Webhookslog handler for Kafkaslog handler for NATSslog handler for Parquet + Object Storageslog handler for Go channelsgo get github.com/samber/slog-loki/v3
Compatibility: go >= 1.21
No breaking changes will be made to exported APIs before v4.0.0.
GoDoc: https://pkg.go.dev/github.com/samber/slog-loki/v3
type Option struct {
// log level (default: debug)
Level slog.Leveler
// loki
Client *loki.Client
// optional: customize webhook event builder
Converter Converter
// optional: fetch attributes from context
AttrFromContext []func(ctx context.Context) []slog.Attr
// optional: see slog.HandlerOptions
AddSource bool
ReplaceAttr func(groups []string, a slog.Attr) slog.Attr
// By default, LokiHandler.Handle sends record attributes as labels to Loki.
// When set to true, this handler sends record attributes as structured metadata.
//
// Combine with RemoveAttrsConverter to avoid sending attributes as labels.
HandleRecordsWithMetadata bool
}
Attributes will be injected in log payload.
Other global parameters:
slogloki.SourceKey = "source"
slogloki.ErrorKeys = []string{"error", "err"}
slogloki.SubAttributeSeparator = "__"
slogloki.AttributeKeyInvalidCharReplacement = "_"
Default behaviour (all attributes are treated as labels):
import (
"github.com/grafana/loki-client-go/loki"
slogloki "github.com/samber/slog-loki/v3"
"log/slog"
)
func main() {
// setup loki client
config, _ := loki.NewDefaultConfig("http://localhost:3100/loki/api/v1/push")
config.TenantID = "xyz"
client, _ := loki.New(config)
logger := slog.New(slogloki.Option{Level: slog.LevelDebug, Client: client}.NewLokiHandler())
logger = logger.
With("environment", "dev").
With("release", "v1.0.0")
// log error
logger.Error("caramba!")
// log user signup
logger.Info("user registration")
// stop loki client and purge buffers
client.Stop()
}
To send record attributes as structured metadata (instead of labels), use the HandleRecordsWithMetadata option along with the RemoveAttrsConverter converter:
import (
"github.com/grafana/loki-client-go/loki"
slogloki "github.com/samber/slog-loki/v3"
"log/slog"
)
func main() {
// setup loki client
config, _ := loki.NewDefaultConfig("http://localhost:3100/loki/api/v1/push")
config.TenantID = "xyz"
client, _ := loki.New(config)
// With slogloki.RemoveAttrsConverter and HandleRecordsWithMetadata enabled, attributes are not sent as labels, thus
// allowing to log high-cardinality metadata without impacting performance.
o := slogloki.Option{
HandleRecordsWithMetadata: true,
Converter: slogloki.RemoveAttrsConverter,
Level: slog.LevelDebug,
Client: client,
}
logger := slog.New(o.NewLokiHandler())
// Attributes added via WithAttrs are always sent as labels to Loki.
logger = logger.With("release", "v1.0.0")
// This will send the "span_id", a high cardinality value, as structured metadata, not as a label.
//
// More about structured metadata in Loki:
// https://grafana.com/docs/loki/latest/get-started/labels/structured-metadata/
logger.Error("A message with structured metadata", slog.String("span_id", "1234567"))
client.Stop()
}
Note: Attributes added via
WithAttrsare always sent as labels to Loki.
Import the samber/slog-otel library.
import (
slogloki "github.com/samber/slog-loki"
slogotel "github.com/samber/slog-otel"
"go.opentelemetry.io/otel/sdk/trace"
)
func main() {
tp := trace.NewTracerProvider(
trace.WithSampler(trace.AlwaysSample()),
)
tracer := tp.Tracer("hello/world")
ctx, span := tracer.Start(context.Background(), "foo")
defer span.End()
span.AddEvent("bar")
logger := slog.New(
slogloki.Option{
// ...
AttrFromContext: []func(ctx context.Context) []slog.Attr{
slogotel.ExtractOtelAttrFromContext([]string{"tracing"}, "trace_id", "span_id"),
},
}.NewLokiHandler(),
)
logger.ErrorContext(ctx, "a message")
}
Don't hesitate ;)
# Install some dev dependencies
make tools
# Run tests
make test
# or
make watch-test
Give a βοΈ if this project helped you!
Copyright Β© 2023 Samuel Berthe.
This project is MIT licensed.
Go
88.6%
Makefile
11.4%
π¨ slog: Loki handler
See the codeA Loki Handler for slog Go library.
See also:
slog.Handler chaining, fanout, routing, failover, load balancing...slog attribute formattingslog sampling policyslog.Handler for test purposesHTTP middlewares:
slog loggerslog loggerslog loggerslog loggernet/http middleware for slog loggerLoggers:
slog handler for Zapslog handler for Zerologslog handler for LogrusLog sinks:
slog handler for Datadogslog handler for Betterstackslog handler for Rollbarslog handler for Lokislog handler for Sentryslog handler for Syslogslog handler for Logstashslog handler for Fluentdslog handler for Graylogslog handler for Quickwitslog handler for Slackslog handler for Telegramslog handler for Mattermostslog handler for Microsoft Teamsslog handler for Webhookslog handler for Kafkaslog handler for NATSslog handler for Parquet + Object Storageslog handler for Go channelsgo get github.com/samber/slog-loki/v3
Compatibility: go >= 1.21
No breaking changes will be made to exported APIs before v4.0.0.
GoDoc: https://pkg.go.dev/github.com/samber/slog-loki/v3
type Option struct {
// log level (default: debug)
Level slog.Leveler
// loki
Client *loki.Client
// optional: customize webhook event builder
Converter Converter
// optional: fetch attributes from context
AttrFromContext []func(ctx context.Context) []slog.Attr
// optional: see slog.HandlerOptions
AddSource bool
ReplaceAttr func(groups []string, a slog.Attr) slog.Attr
// By default, LokiHandler.Handle sends record attributes as labels to Loki.
// When set to true, this handler sends record attributes as structured metadata.
//
// Combine with RemoveAttrsConverter to avoid sending attributes as labels.
HandleRecordsWithMetadata bool
}
Attributes will be injected in log payload.
Other global parameters:
slogloki.SourceKey = "source"
slogloki.ErrorKeys = []string{"error", "err"}
slogloki.SubAttributeSeparator = "__"
slogloki.AttributeKeyInvalidCharReplacement = "_"
Default behaviour (all attributes are treated as labels):
import (
"github.com/grafana/loki-client-go/loki"
slogloki "github.com/samber/slog-loki/v3"
"log/slog"
)
func main() {
// setup loki client
config, _ := loki.NewDefaultConfig("http://localhost:3100/loki/api/v1/push")
config.TenantID = "xyz"
client, _ := loki.New(config)
logger := slog.New(slogloki.Option{Level: slog.LevelDebug, Client: client}.NewLokiHandler())
logger = logger.
With("environment", "dev").
With("release", "v1.0.0")
// log error
logger.Error("caramba!")
// log user signup
logger.Info("user registration")
// stop loki client and purge buffers
client.Stop()
}
To send record attributes as structured metadata (instead of labels), use the HandleRecordsWithMetadata option along with the RemoveAttrsConverter converter:
import (
"github.com/grafana/loki-client-go/loki"
slogloki "github.com/samber/slog-loki/v3"
"log/slog"
)
func main() {
// setup loki client
config, _ := loki.NewDefaultConfig("http://localhost:3100/loki/api/v1/push")
config.TenantID = "xyz"
client, _ := loki.New(config)
// With slogloki.RemoveAttrsConverter and HandleRecordsWithMetadata enabled, attributes are not sent as labels, thus
// allowing to log high-cardinality metadata without impacting performance.
o := slogloki.Option{
HandleRecordsWithMetadata: true,
Converter: slogloki.RemoveAttrsConverter,
Level: slog.LevelDebug,
Client: client,
}
logger := slog.New(o.NewLokiHandler())
// Attributes added via WithAttrs are always sent as labels to Loki.
logger = logger.With("release", "v1.0.0")
// This will send the "span_id", a high cardinality value, as structured metadata, not as a label.
//
// More about structured metadata in Loki:
// https://grafana.com/docs/loki/latest/get-started/labels/structured-metadata/
logger.Error("A message with structured metadata", slog.String("span_id", "1234567"))
client.Stop()
}
Note: Attributes added via
WithAttrsare always sent as labels to Loki.
Import the samber/slog-otel library.
import (
slogloki "github.com/samber/slog-loki"
slogotel "github.com/samber/slog-otel"
"go.opentelemetry.io/otel/sdk/trace"
)
func main() {
tp := trace.NewTracerProvider(
trace.WithSampler(trace.AlwaysSample()),
)
tracer := tp.Tracer("hello/world")
ctx, span := tracer.Start(context.Background(), "foo")
defer span.End()
span.AddEvent("bar")
logger := slog.New(
slogloki.Option{
// ...
AttrFromContext: []func(ctx context.Context) []slog.Attr{
slogotel.ExtractOtelAttrFromContext([]string{"tracing"}, "trace_id", "span_id"),
},
}.NewLokiHandler(),
)
logger.ErrorContext(ctx, "a message")
}
Don't hesitate ;)
# Install some dev dependencies
make tools
# Run tests
make test
# or
make watch-test
Give a βοΈ if this project helped you!
Copyright Β© 2023 Samuel Berthe.
This project is MIT licensed.
Go
88.6%
Makefile
11.4%