go-trace
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.
Logging
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
Usage
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")
}
Tracing
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
-
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.
Exporters
Mock trace exporters for opencensus and OTEL.
Misc
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
Credits
Much inspired by prior art from @casualjim. Thanks so much.