OpenTelemetry Zap logs [otelzap]

Vladimir Mihailenco
November 25, 2024
3 min read

With OpenTelemetry Zap, you can automatically generate OpenTelemetry events from your logging statements. This can be useful for understanding how your application is behaving in production and diagnosing issues.

OpenTelemetry Zap automatically injects trace and span IDs for each logging statement, allowing you to correlate your logs with other telemetry data from your application.

What is OpenTelemetry?

OpenTelemetry is an open-source observability framework that aims to standardize and simplify the collection, processing, and export of telemetry data from applications and systems.

OpenTelemetry supports multiple programming languages and platforms, making it suitable for a wide range of applications and environments.

OpenTelemetry enables developers to instrument their code and collect telemetry data, which can then be exported to various OpenTelemetry backends or observability platforms for analysis and visualization.

Zap instrumentation

To install otelzap instrumentation:

shell
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.

go
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:

go
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:

go
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 OpenTelemetry APM that supports distributed tracing, metrics, and logs. You can use it to monitor applications and troubleshoot issues.

Uptrace Overview

Uptrace comes with an intuitive query builder, rich dashboards, alerting rules with notifications, and integrations for most languages and frameworks.

Uptrace can process billions of spans and metrics on a single server and allows you to monitor your applications at 10x lower cost.

In just a few minutes, you can try Uptrace by visiting the cloud demo (no login required) or running it locally with Docker. The source code is available on GitHub.

What's next?

Zap logging is now integrated with OpenTelemetry traces, providing high-performance structured logging with full context propagation. Compare with Logrus for a different API, or try slog for the standard library logging approach.