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

# Basic Logging

> Learn how to collect and export logs using OpenTelemetry Rust SDK with the tracing-appender bridge

## Overview

OpenTelemetry logs provide structured logging capabilities that integrate seamlessly with traces and metrics. This guide shows how to use the `tracing` crate with OpenTelemetry's log appender bridge.

## Dependencies

Add these dependencies to your `Cargo.toml`:

```toml Cargo.toml theme={null}
[dependencies]
opentelemetry_sdk = { version = "*", features = ["logs"] }
opentelemetry-stdout = { version = "*", features = ["logs"] }
opentelemetry-appender-tracing = "*"
tracing = { version = "0.1", features = ["std"] }
tracing-subscriber = { version = "0.3", features = ["env-filter", "registry", "std", "fmt"] }
```

## Complete Example

<Steps>
  <Step title="Initialize the Logger Provider">
    Set up the logger provider with a stdout exporter and resource attributes.

    ```rust theme={null}
    use opentelemetry_appender_tracing::layer;
    use opentelemetry_sdk::logs::SdkLoggerProvider;
    use opentelemetry_sdk::Resource;
    use tracing_subscriber::{prelude::*, EnvFilter};

    fn main() {
        let exporter = opentelemetry_stdout::LogExporter::default();
        let provider: SdkLoggerProvider = SdkLoggerProvider::builder()
            .with_resource(
                Resource::builder()
                    .with_service_name("log-appender-tracing-example")
                    .build(),
            )
            .with_simple_exporter(exporter)
            .build();
    }
    ```
  </Step>

  <Step title="Configure Tracing Subscriber">
    Set up the tracing subscriber with OpenTelemetry layer and filtering.

    ```rust theme={null}
    // To prevent a telemetry-induced-telemetry loop, OpenTelemetry's own internal
    // logging is properly suppressed. However, logs emitted by external components
    // (such as reqwest, tonic, etc.) are not suppressed.
    //
    // The filter levels are set as follows:
    // - Allow `info` level and above by default.
    // - Completely restrict logs from `hyper`, `tonic`, `h2`, and `reqwest`.
    let filter_otel = EnvFilter::new("info")
        .add_directive("hyper=off".parse().unwrap())
        .add_directive("tonic=off".parse().unwrap())
        .add_directive("h2=off".parse().unwrap())
        .add_directive("reqwest=off".parse().unwrap());

    let otel_layer = layer::OpenTelemetryTracingBridge::new(&provider)
        .with_filter(filter_otel);
    ```
  </Step>

  <Step title="Add Console Output Layer">
    Optionally add a fmt layer for console output alongside OpenTelemetry.

    ```rust theme={null}
    // Create a new tracing::Fmt layer to print the logs to stdout
    let filter_fmt = EnvFilter::new("info")
        .add_directive("opentelemetry=debug".parse().unwrap());

    let fmt_layer = tracing_subscriber::fmt::layer()
        .with_thread_names(true)
        .with_filter(filter_fmt);

    tracing_subscriber::registry()
        .with(otel_layer)
        .with(fmt_layer)
        .init();
    ```
  </Step>

  <Step title="Emit Log Records">
    Use the `tracing` macros to emit structured log records.

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

    error!(
        name: "my-event-name",
        target: "my-system",
        event_id = 20,
        user_name = "otel",
        user_email = "otel@opentelemetry.io",
        message = "This is an example message"
    );

    // Don't forget to shutdown the provider
    let _ = provider.shutdown();
    ```
  </Step>
</Steps>

## Log Levels

The `tracing` crate provides standard log levels:

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

trace!("Very detailed diagnostic information");
debug!("Debug information");
info!("General informational messages");
warn!("Warning messages");
error!("Error messages");
```

## Structured Fields

Add structured fields to your logs for better searchability:

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

info!(
    user_id = 12345,
    action = "login",
    ip_address = "192.168.1.1",
    "User logged in successfully"
);
```

<Note>
  The OpenTelemetry logs API is designed to be used as a bridge. The recommended approach is to use the `tracing` crate for logging in your application and let the OpenTelemetry appender bridge handle the export.
</Note>

## Filter Configuration

<Tip>
  Use `EnvFilter` to control which logs are processed. This is crucial for preventing telemetry loops and reducing noise from third-party libraries.
</Tip>

### Common Filter Patterns

```rust theme={null}
// Allow all logs at info level or above
EnvFilter::new("info")

// Allow debug logs from your crate, info from others
EnvFilter::new("myapp=debug,info")

// Suppress specific crates entirely
EnvFilter::new("info")
    .add_directive("hyper=off".parse().unwrap())
    .add_directive("tonic=off".parse().unwrap())
```

## Advanced: Custom Log Processors

You can create custom log processors to enrich or filter logs. Here's a simple example:

```rust theme={null}
use opentelemetry_sdk::logs::{LogProcessor, SdkLogRecord};
use opentelemetry::InstrumentationScope;
use opentelemetry_sdk::error::OTelSdkResult;
use std::time::Duration;

#[derive(Debug)]
struct EnrichmentLogProcessor<P: LogProcessor> {
    delegate: P,
}

impl<P: LogProcessor> LogProcessor for EnrichmentLogProcessor<P> {
    fn emit(&self, data: &mut SdkLogRecord, instrumentation: &InstrumentationScope) {
        // Add custom attributes
        data.add_attribute("enriched", true);
        self.delegate.emit(data, instrumentation);
    }

    fn force_flush(&self) -> OTelSdkResult {
        self.delegate.force_flush()
    }

    fn shutdown_with_timeout(&self, timeout: Duration) -> OTelSdkResult {
        self.delegate.shutdown_with_timeout(timeout)
    }
}
```

For a complete implementation, see the `logs-advanced` example in the source repository.

## Output Format

The stdout exporter will output logs in JSON format:

```json theme={null}
{
  "resourceLogs": [
    {
      "resource": {
        "attributes": [
          {
            "key": "service.name",
            "value": { "stringValue": "log-appender-tracing-example" }
          }
        ]
      },
      "scopeLogs": [
        {
          "logRecords": [
            {
              "severityText": "ERROR",
              "body": { "stringValue": "This is an example message" },
              "attributes": [
                { "key": "event_id", "value": { "intValue": 20 } },
                { "key": "user_name", "value": { "stringValue": "otel" } }
              ]
            }
          ]
        }
      ]
    }
  ]
}
```
