> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/open-telemetry/opentelemetry-rust/llms.txt
> Use this file to discover all available pages before exploring further.

# opentelemetry-appender-tracing

> Bridge tracing crate events to OpenTelemetry logs

# opentelemetry-appender-tracing

**Version:** 0.31.1

The `opentelemetry-appender-tracing` crate bridges `tracing` events to OpenTelemetry logs, allowing applications using the `tracing` ecosystem to export structured logs via OpenTelemetry.

<Note>
  This is different from [`tracing-opentelemetry`](https://docs.rs/tracing-opentelemetry), which converts `tracing` spans into OpenTelemetry traces. This crate specifically handles `tracing` **events** as OpenTelemetry **logs**.
</Note>

## Installation

```toml theme={null}
[dependencies]
tracing = ">=0.1.40"
tracing-subscriber = { version = "0.3", features = ["registry", "std"] }
opentelemetry = { version = "0.31", features = ["logs"] }
opentelemetry-sdk = { version = "0.31", features = ["logs"] }
opentelemetry-appender-tracing = "0.31"
```

### Feature Flags

* `experimental_metadata_attributes`: Include code metadata (file path, line number, module) as attributes
* `experimental_span_attributes`: Include parent span information as attributes

## Quick Start

### Basic Setup

```rust theme={null}
use opentelemetry_sdk::logs::SdkLoggerProvider;
use opentelemetry_stdout::LogExporter;
use opentelemetry_appender_tracing::layer::OpenTelemetryTracingBridge;
use tracing_subscriber::prelude::*;

// 1. Set up OpenTelemetry logger provider
let exporter = LogExporter::default();
let provider = SdkLoggerProvider::builder()
    .with_simple_exporter(exporter)
    .build();

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

// 3. Register with tracing subscriber
tracing_subscriber::registry()
    .with(otel_layer)
    .with(tracing_subscriber::fmt::layer()) // Optional: also log to stdout
    .init();

// 4. Use tracing as normal
tracing::info!("Application started");
tracing::error!("Something went wrong");
```

### Structured Events

```rust theme={null}
use tracing::error;

error!(
    name: "my-event-name",
    target: "my-system",
    event_id = 10,
    user_name = "alice",
    user_email = "alice@example.com",
    message = "This is an example message"
);
```

## Core Types

<ParamField path="layer::OpenTelemetryTracingBridge" type="struct">
  A `tracing_subscriber::Layer` that forwards `tracing` events to OpenTelemetry logs
</ParamField>

```rust theme={null}
use opentelemetry_appender_tracing::layer::OpenTelemetryTracingBridge;
use opentelemetry_sdk::logs::SdkLoggerProvider;

let provider: SdkLoggerProvider = /* ... */;
let layer = OpenTelemetryTracingBridge::new(&provider);
```

## Field Mapping

How `tracing` events map to OpenTelemetry logs:

### Event Name

`tracing` events can optionally have a name, which becomes the OpenTelemetry `EventName`:

```rust theme={null}
tracing::info!(name: "user.login", user_id = 42);
// -> LogRecord.EventName = "user.login"
```

### Target

The `target` field maps to OpenTelemetry `InstrumentationScope`:

```rust theme={null}
tracing::info!(target: "http_server", "Request received");
// -> InstrumentationScope.name = "http_server"
```

### Severity

`tracing::Level` maps to OpenTelemetry severity:

| `tracing::Level` | Severity Text | Severity Number |
| ---------------- | ------------- | --------------- |
| `ERROR`          | Error         | 17              |
| `WARN`           | Warn          | 13              |
| `INFO`           | Info          | 9               |
| `DEBUG`          | Debug         | 5               |
| `TRACE`          | Trace         | 1               |

### Fields → Attributes

`tracing` event fields become OpenTelemetry attributes, except:

* Field named `"message"` → `LogRecord::Body`
* If no `"message"` field exists, the event's formatted message → `LogRecord::Body`

```rust theme={null}
tracing::info!(
    user_id = 42,
    action = "login",
    message = "User logged in"
);
// -> Body = "User logged in"
// -> Attributes: { user_id: 42, action: "login" }
```

## Type Conversion

| `tracing` Type        | OpenTelemetry Type          | Notes                                        |
| --------------------- | --------------------------- | -------------------------------------------- |
| `i64`                 | `AnyValue::Int`             |                                              |
| `u64`, `u128`, `i128` | `AnyValue::Int` or `String` | Converted if fits in `i64`, else stringified |
| `f32`, `f64`          | `AnyValue::Double`          |                                              |
| `bool`                | `AnyValue::Boolean`         |                                              |
| `&str`                | `AnyValue::String`          |                                              |
| `&[u8]`               | `AnyValue::Bytes`           | Binary data                                  |
| `&dyn Debug`          | `AnyValue::String`          | Via `Debug` formatting                       |
| `&dyn Error`          | `AnyValue::String`          | Stored in `exception.message` attribute      |

## Automatic Context Attachment

The bridge automatically attaches OpenTelemetry trace context to logs:

```rust theme={null}
use tracing::info;
use opentelemetry::trace::{Tracer, TraceContextExt};
use opentelemetry::Context;

let tracer = /* get tracer */;
tracer.in_span("my_operation", |cx| {
    info!("Processing item");
    // Log automatically includes:
    // - trace_id
    // - span_id
    // - trace_flags
});
```

## Examples

### Basic Logging

```rust theme={null}
use tracing::{info, warn, error};

info!("Server started on port 8080");
warn!("High memory usage detected");
error!("Database connection failed");
```

### Named Events

```rust theme={null}
use tracing::error;

error!(
    name: "database.connection.failed",
    database = "users_db",
    retry_count = 3,
    "Failed to connect after retries"
);
```

### With Explicit Message

```rust theme={null}
use tracing::info;

info!(
    user_id = 42,
    action = "purchase",
    amount = 99.99,
    message = "User completed purchase"
);
```

### Exception Logging

```rust theme={null}
use tracing::error;
use std::error::Error;

fn handle_error(err: &dyn Error) {
    error!(
        error = err as &dyn Error,
        "Operation failed"
    );
}
```

### With Parent Spans

```rust theme={null}
use tracing::{info, info_span};

let span = info_span!("request", request_id = "123");
let _guard = span.enter();

info!("Processing request");
// Log includes parent span context automatically
```

## Integration with OTLP

```rust theme={null}
use opentelemetry_otlp::LogExporter;
use opentelemetry_sdk::logs::{BatchLogProcessor, SdkLoggerProvider};
use opentelemetry_appender_tracing::layer::OpenTelemetryTracingBridge;
use tracing_subscriber::prelude::*;

let exporter = LogExporter::builder()
    .with_http()
    .build()?;

let provider = SdkLoggerProvider::builder()
    .with_log_processor(BatchLogProcessor::builder(exporter).build())
    .build();

let otel_layer = OpenTelemetryTracingBridge::new(&provider);

tracing_subscriber::registry()
    .with(otel_layer)
    .init();
```

## Combining with Tracing Spans

<Note>
  For converting `tracing` **spans** to OpenTelemetry **traces**, use the third-party [`tracing-opentelemetry`](https://docs.rs/tracing-opentelemetry) crate. Both can be used together:

  * `tracing-opentelemetry`: Spans → OpenTelemetry Traces
  * `opentelemetry-appender-tracing`: Events → OpenTelemetry Logs
</Note>

```rust theme={null}
use tracing_subscriber::prelude::*;

// Hypothetical combined setup
tracing_subscriber::registry()
    .with(tracing_opentelemetry::layer()) // Spans → Traces
    .with(OpenTelemetryTracingBridge::new(&logger_provider)) // Events → Logs
    .with(tracing_subscriber::fmt::layer()) // Also print to console
    .init();
```

## Metadata Attributes (Experimental)

With `experimental_metadata_attributes` feature:

```toml theme={null}
[dependencies]
opentelemetry-appender-tracing = { version = "0.31", features = ["experimental_metadata_attributes"] }
```

Automatically includes:

* `code.filepath`: Source file path
* `code.line_number`: Line number
* `code.function_name`: Module path

## Performance Considerations

* Events are only processed if the level is enabled
* Use `BatchLogProcessor` for better throughput
* Field serialization has overhead; avoid excessive fields
* The bridge integrates as a `Layer`, allowing composition with other layers

## Differences from tracing-opentelemetry

| Feature        | `opentelemetry-appender-tracing` | `tracing-opentelemetry`      |
| -------------- | -------------------------------- | ---------------------------- |
| Purpose        | Events → OpenTelemetry Logs      | Spans → OpenTelemetry Traces |
| Maintained by  | OpenTelemetry project            | Third-party (Tokio)          |
| Event handling | Converts to logs                 | Converts to span events      |
| Span handling  | Not supported                    | Converts to traces           |

## Related Crates

* **[opentelemetry](/api/opentelemetry)** - Core API with Logs Bridge API
* **[opentelemetry-sdk](/api/opentelemetry-sdk)** - SDK with log processors
* **[opentelemetry-appender-log](/api/opentelemetry-appender-log)** - Bridge for `log` crate
* **[tracing](https://docs.rs/tracing/)** - Application-level tracing for Rust
* **[tracing-opentelemetry](https://docs.rs/tracing-opentelemetry)** - Third-party spans-to-traces bridge

## Documentation

<Card title="Full API Documentation" icon="book" href="https://docs.rs/opentelemetry-appender-tracing/0.31.1">
  View complete API reference on docs.rs
</Card>

<Card title="tracing Crate" icon="arrow-up-right-from-square" href="https://docs.rs/tracing/">
  Documentation for the tracing crate
</Card>

## Minimum Rust Version

**MSRV:** 1.75.0
