Logging & tracing utilities for micro services.
Based on:
go.uber.org/zap
go.opencensus.io/trace
go.opentelemetry.io/otel
Tested to be compatible wih Datadog tracing.
The main idea is to unify logging and tracing, and insulate the app layer from the intricacies of tracing.
This repositories provides a few wrappers around a zap.Logger
:
- a logger factory based on zap logger, with a convenient builder to link logs to trace spans
- a logger builder, e.g. to initialize a root logger for your service
TODOs:
- [] explore how to expose zerolog as an alternative to zap
With OpenCensus tracing.
import (
"context"
"github.com/fredbi/go-trace/log"
"go.opencensus.io/trace"
)
func tracedFunc() {
ctx := context.Background()
zlg, closer := log.MustGetLogger("root") // builds a named zap logger with sensible defaults
defer closer()
lgf := log.NewFactory(zlg) // builds a logger with trace propagation
ctx, span := trace.StartSpan(ctx, "span name")
defer span.End()
lg := lgf.For(ctx)
lg.Info("log propagated as a trace span")
}
With OpenTelemetry tracing.
import (
"context"
"github.com/fredbi/go-trace/log"
"go.opentelemetry.io/otel"
)
func tracedFunc() {
tracer := otel.Tracer("") // returns the global default tracer
ctx := context.Background()
zlg, closer := log.MustGetLogger("root")
defer closer()
lgf := log.NewFactory(zlg) // builds a logger with trace propagation
ctx, span := tracer.Start(ctx, "span name")
defer span.End()
lg := lgf.For(ctx)
lg.Info("log propagated as a trace span")
}
A simple wrapper to instrument tracing in apps with minimal boiler-plate.
With OpenCensus tracing.
import (
"context"
"github.com/fredbi/go-trace/log"
"github.com/fredbi/go-trace/opencensus/tracer"
)
type loggable struct {
lgf log.Factory
}
func (l *loggable) Logger() log.Factory {
return l.lgf
}
func tracedFunc() {
zlg := log.MustGetLogger("root") // builds a named zap logger with sensible defaults
lgf := log.NewFactory(zlg) // builds a logger with trace propagation
component := loggable{lfg: lgf}
ctx, span, lg := tracer.StartSpan(context.Background(), component) // the span is named automatically from the calling function
defer span.End()
lg.Info("log propagated as a trace span")
}
With OpenTelemetry tracing.
import (
"context"
"github.com/fredbi/go-trace/log"
"github.com/fredbi/go-trace/otel/tracer"
)
type loggable struct {
lgf log.Factory
tracer trace.Tracer
}
func (l *loggable) Logger() log.Factory {
return l.lgf
}
// Tracer returns the configured tracer. If this method, is not provided,
// the default globally registered OTEL tracer is returned.
func (l *loggable) Tracer() trace.Tracer {
return l.tracer
}
func tracedFunc() {
zlg := log.MustGetLogger("root") // builds a named zap logger with sensible defaults
lgf := log.NewFactory(zlg, log.WithOTEL(true)) // builds a logger with trace propagation
component := loggable{lfg: lgf}
ctx, span, lg := tracer.StartSpan(context.Background(), component) // the span is named automatically from the calling function
defer span.End()
lg.Info("log propagated as a trace span")
}
-
middleware.LogRequests
logs all requests from a http server, using the logger factory -
opencensus/middleware.OCHTTP
wraps theochttp
opencensus plugin into a more convenient middleware function. -
otel/middleware.OTELHTTP
wraps theotelhttp
OTEL contrib plugin.
Mock trace exporters for opencensus and OTEL.
Various opencensus exporters (as a separate module).
- misc/influxdb: export opencensus metrics to an influxdb sink
- misc/amplitude (experimental): propagate trace event to the amplitude API
Much inspired by prior art from @casualjim. Thanks so much.