Skip to main content

Overview

OpenTelemetry Rust provides logging capabilities through a bridge API rather than an end-user logging API. This design allows you to continue using familiar logging libraries like log and tracing while automatically bridging those logs to OpenTelemetry backends.

Architecture

Unlike traces and metrics, OpenTelemetry does not provide a dedicated logging API for end-users. Instead, it recommends using existing logging libraries and bridging them to OpenTelemetry logs.
The logs architecture consists of three main components:
+------------------+       +-------------------+       +------------------+
|                  |       |                   |       |                  |
| Log Crate        +-------> Log Appender      +-------> LogProcessor     |
| (log/tracing)    |       | (Bridge)          |       | (Batch/Simple)   |
|                  |       |                   |       |                  |
+------------------+       +-------------------+       +------------------+
                                                               |
                                                               v
                                                       +------------------+
                                                       |                  |
                                                       | LogExporter      |
                                                       | (OTLP/stdout)    |
                                                       |                  |
                                                       +------------------+

Components

  1. Logging Library: Your application uses log or tracing crates for emitting logs
  2. Log Appender (Bridge): Converts logs from the logging library to OpenTelemetry LogRecords
  3. LogProcessor: Handles batching and processing of log records
  4. LogExporter: Exports logs to backends (OTLP, stdout, etc.)

Bridge API vs End-User API

The OpenTelemetry Logs Bridge API is designed for logging library authors, not application developers:
use log::info;

// Application code uses familiar logging APIs
info!("User logged in"; "user_id" => user.id);

Key Concepts

LogRecord

A LogRecord represents a single log event with the following key properties:
  • Timestamp: When the log event occurred
  • Observed Timestamp: When the log was recorded by the system
  • Severity: Log level (TRACE, DEBUG, INFO, WARN, ERROR, FATAL)
  • Body: The log message
  • Attributes: Key-value pairs for structured logging
  • Trace Context: Links logs to traces (trace ID, span ID, trace flags)
  • Target: The module/component that emitted the log
  • Event Name: Optional name for the log event

Severity Levels

OpenTelemetry defines 24 severity levels, but most appenders map from standard log levels:
Standard LevelOTel SeveritySeverity Number
TRACETrace1
DEBUGDebug5
INFOInfo9
WARNWarn13
ERRORError17
FATALFatal21

AnyValue

Log attributes and body use the AnyValue type to support various data types:
  • Int(i64) - Integer values
  • Double(f64) - Floating-point values
  • String(StringValue) - String values
  • Boolean(bool) - Boolean values
  • Bytes(Vec<u8>) - Byte arrays
  • ListAny(Vec<AnyValue>) - Arrays of values
  • Map(HashMap<Key, AnyValue>) - Nested maps

Available Appenders

OpenTelemetry Rust provides two official log appenders:

log Appender

Bridge logs from the log crate to OpenTelemetry

tracing Appender

Bridge logs from the tracing crate to OpenTelemetry

Log Processors

Processors handle how logs are buffered and exported:
  • SimpleLogProcessor: Exports logs immediately (for development)
  • BatchLogProcessor: Batches logs for efficient export (for production)
See Log Processors for detailed configuration.

Trace Context Integration

One of the key benefits of using OpenTelemetry logs is automatic correlation with distributed traces. When a log is emitted within an active trace context, the log record automatically includes:
  • Trace ID: Links the log to a distributed trace
  • Span ID: Links the log to a specific span within the trace
  • Trace Flags: Indicates if the trace is sampled
This allows you to view logs in the context of traces in your observability backend.

Quick Start

1

Choose your logging library

Select either log or tracing based on your application’s needs
2

Set up the logger provider

Configure SdkLoggerProvider with an exporter and processor
3

Install the appender

Bridge your logging library to OpenTelemetry using the appropriate appender
4

Emit logs

Use your logging library’s macros as normal - they’ll automatically flow to OpenTelemetry

Example

Here’s a minimal example using the tracing appender:
use opentelemetry_appender_tracing::layer::OpenTelemetryTracingBridge;
use opentelemetry_sdk::logs::SdkLoggerProvider;
use tracing::error;
use tracing_subscriber::prelude::*;

fn main() {
    // Create logger provider with stdout exporter
    let exporter = opentelemetry_stdout::LogExporter::default();
    let provider = SdkLoggerProvider::builder()
        .with_simple_exporter(exporter)
        .build();

    // Create the OpenTelemetry tracing bridge
    let otel_layer = OpenTelemetryTracingBridge::new(&provider);

    // Register with tracing subscriber
    tracing_subscriber::registry()
        .with(otel_layer)
        .init();

    // Emit logs using tracing - they'll be bridged to OpenTelemetry
    error!(
        name: "user-login-failed",
        user_id = 12345,
        message = "Invalid credentials"
    );

    // Shutdown to flush remaining logs
    provider.shutdown().unwrap();
}

Next Steps

Bridge API

Learn about the core Bridge API types and traits

log Appender

Set up logging with the log crate

tracing Appender

Set up logging with the tracing crate

Log Processors

Configure batch and simple processors

Build docs developers (and LLMs) love