1use 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 .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 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 _ = provider.shutdown();
70
71 Ok(())
72}