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?

OpenTelemetryopen in new window is an open source and vendor-neutral API for distributed tracingopen in new window (including logs and errors) and metricsopen in new window.

Otel specifies how to collect and export telemetry data in a vendor agnostic way. With OpenTelemetry, you can instrumentopen in new window your application once and then add or change vendors without changing the instrumentation, for example, many open source tracing toolsopen in new window already support OpenTelemetry.

OpenTelemetry is available for most programming languages and provides interoperability across different languages and environments.

Installation

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 exampleopen in new window 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 an open source and blazingly fast distributed tracing tool 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 startedopen in new window 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:

Last Updated: