Collecting Zap logs with OpenTelemetry
Zap provides fast, structured, leveled logging for Go. It is also very fast and efficient.
In this article you will learn how to collect and monitor Zap logs using OpenTelemetry observability framework.
What is OpenTelemetry?
OpenTelemetry is an open source and vendor-neutral API for OpenTelemetry tracing (including logs and errors) and OpenTelemetry metrics.
Otel specifies how to collect and export telemetry data in a vendor agnostic way. With OpenTelemetry, you can instrument your application once and then add or change vendors without changing the instrumentation, for example, many open source tracing tools already support OpenTelemetry.
OpenTelemetry is available for most programming languages and provides interoperability across different languages and environments.
Zap instrumentation
To install Zap OpenTelemetry instrumentation:
go get github.com/uptrace/opentelemetry-go-extra/otelzap
Usage
otelzap instrumentation records Zap log messages as events on the existing span from the passed context.Context
. It does not record anything if the context does not contain a span.
You need to create an otelzap.Logger
using this package and pass a context to propagate the active span.
import (
"go.uber.org/zap"
"github.com/uptrace/opentelemetry-go-extra/otelzap"
)
// Wrap zap logger to extend Zap with API that accepts a context.Context.
log := otelzap.New(zap.NewExample())
// And then pass ctx to propagate the span.
log.Ctx(ctx).Error("hello from zap",
zap.Error(errors.New("hello world")),
zap.String("foo", "bar"))
// Alternatively.
log.ErrorContext(ctx, "hello from zap",
zap.Error(errors.New("hello world")),
zap.String("foo", "bar"))
Both variants are fast and don't allocate. See example for details.
Global logger
Just like Zap, otelzap provides a global logger that can be set with otelzap.ReplaceGlobals
:
package main
import (
"go.uber.org/zap"
"github.com/uptrace/opentelemetry-go-extra/otelzap"
)
func main() {
logger := otelzap.New(zap.NewExample())
defer logger.Sync()
undo := otelzap.ReplaceGlobals(logger)
defer undo()
otelzap.L().Info("replaced zap's global loggers")
otelzap.Ctx(context.TODO()).Info("... and with context")
}
Sugared logger
You can also use sugared logger API in a similar way:
log := otelzap.New(zap.NewExample())
sugar := log.Sugar()
sugar.Ctx(ctx).Infow("failed to fetch URL",
// Structured context as loosely typed key-value pairs.
"url", url,
"attempt", 3,
"backoff", time.Second,
)
sugar.InfowContext(ctx, "failed to fetch URL",
// Structured context as loosely typed key-value pairs.
"url", url,
"attempt", 3,
"backoff", time.Second,
)
sugar.Ctx(ctx).Infof("Failed to fetch URL: %s", url)
sugar.InfofContext(ctx, "Failed to fetch URL: %s", url)
What is Uptrace?
Uptrace is a source-available APM powered by OpenTelemetry and ClickHouse. It allows you to identify and fix bugs in production faster knowing what conditions lead to which errors.
You can get started with Uptrace by downloading a DEB/RPM package or a pre-compiled Go binary.
What's next?
Next, instrument more operations, for example, database queries, errors, and logs. You can also learn about OpenTelemetry Go Tracing API to create your own instrumentations.
Popular instrumentations: