usage/
usage.rs

1// Run this example:
2// cargo run --example usage -- http://<server>:4317
3
4use std::{env, error::Error as StdError, process, sync::Arc};
5
6use opentelemetry_otlp::WithExportConfig as _;
7use spdlog::prelude::*;
8use spdlog_opentelemetry::OpenTelemetrySink;
9
10fn otel_logger_provider(
11    service_name: &'static str,
12) -> Result<opentelemetry_sdk::logs::SdkLoggerProvider, Box<dyn StdError>> {
13    let Some(endpoint) = env::args().nth(1) else {
14        error!("invalid cli argument. usage: `usage <otlp-endpoint>`");
15        process::exit(1);
16    };
17
18    let exporter = opentelemetry_otlp::LogExporter::builder()
19        .with_tonic()
20        .with_endpoint(endpoint)
21        .build()?;
22    let logger_provider = opentelemetry_sdk::logs::SdkLoggerProvider::builder()
23        .with_resource(
24            opentelemetry_sdk::Resource::builder()
25                .with_service_name(service_name)
26                .build(),
27        )
28        // Use batch exporter for better throughput.
29        //
30        // If you choose batch exporter, don't conbine your sink with spdlog-rs async sink, because
31        // it's already async inside OpenTelemetry SDK's `BatchLogProcessor`.
32        //
33        // .with_simple_exporter(exporter)
34        .with_batch_exporter(exporter)
35        .build();
36
37    Ok(logger_provider)
38}
39
40fn setup_logger(
41    provider: &opentelemetry_sdk::logs::SdkLoggerProvider,
42) -> Result<(), Box<dyn StdError>> {
43    let sink = Arc::new(OpenTelemetrySink::builder().provider(provider).build()?);
44
45    let logger = spdlog::default_logger().fork_with(|logger| {
46        logger.set_level_filter(LevelFilter::All);
47        logger.sinks_mut().push(sink);
48        // Now the new logger has 3 sinks: stdout + stderr + OpenTelemetry
49        //                                 ^^^^^^^^^^^^^^^
50        //                                 forked from the default logger
51        Ok(())
52    })?;
53    spdlog::set_default_logger(logger);
54    Ok(())
55}
56
57#[tokio::main]
58async fn main() -> Result<(), Box<dyn StdError>> {
59    let provider = otel_logger_provider("spdlog-opentelemetry-example")?;
60
61    setup_logger(&provider)?;
62
63    trace!("this is a trace message");
64    info!("this is an info message", kv: { id = 1 });
65    warn!("this is a warn message");
66    error!("this is an error message");
67
68    // Ensure logs are finally sent before exiting.
69    _ = provider.shutdown();
70
71    Ok(())
72}