1mod delay_writer;
2
3pub use self::delay_writer::DelayWriter;
4use crate::config::Config;
5use anyhow::Context;
6use opentelemetry_otlp::WithExportConfig;
7use tonic::metadata::{
8 MetadataKey,
9 MetadataMap,
10};
11use tracing_appender::non_blocking::WorkerGuard;
12use tracing_log::LogTracer;
13use tracing_subscriber::{
14 filter::EnvFilter,
15 layer::SubscriberExt,
16};
17
18pub fn setup(config: &Config) -> anyhow::Result<WorkerGuard> {
22 let file_writer = tracing_appender::rolling::hourly(config.log_file_dir(), "log.txt");
23 let (nonblocking_file_writer, guard) = tracing_appender::non_blocking(file_writer);
24
25 let mut env_filter = EnvFilter::default();
26 for directive in config.log.directives.iter() {
28 env_filter = env_filter.add_directive(
29 directive
30 .parse()
31 .context("failed to parse logging directive")?,
32 );
33 }
34
35 let stderr_formatting_layer = tracing_subscriber::fmt::layer().with_writer(std::io::stderr);
36 let file_formatting_layer = tracing_subscriber::fmt::layer()
37 .with_ansi(false)
38 .with_writer(nonblocking_file_writer);
39
40 let opentelemetry_layer = if config.log.opentelemetry {
41 eprintln!("setting up opentelemetry...");
42
43 opentelemetry::global::set_error_handler(|error| {
44 eprintln!("opentelemetry error: {:?}", anyhow::Error::from(error));
47 })
48 .context("failed to set opentelemetry error handler")?;
49
50 let mut map = MetadataMap::with_capacity(config.log.headers.len());
51 for (k, v) in config.log.headers.iter() {
52 let k = MetadataKey::from_bytes(k.as_bytes()).context("invalid header name")?;
53 map.insert(k, v.parse().context("invalid header value")?);
54 }
55
56 let exporter = {
57 let mut exporter = opentelemetry_otlp::new_exporter()
58 .tonic()
59 .with_metadata(map)
60 .with_tls_config(Default::default());
61
62 if let Some(endpoint) = config.log.endpoint.as_ref() {
63 exporter = exporter.with_endpoint(endpoint);
64 }
65
66 exporter
67 };
68
69 let tracer = opentelemetry_otlp::new_pipeline()
70 .tracing()
71 .with_exporter(exporter)
72 .install_batch(opentelemetry_sdk::runtime::Tokio)
73 .context("failed to install otlp opentelemetry exporter")?;
74
75 Some(tracing_opentelemetry::layer().with_tracer(tracer))
76 } else {
77 None
78 };
79
80 let subscriber = tracing_subscriber::Registry::default()
81 .with(env_filter)
82 .with(file_formatting_layer)
83 .with(stderr_formatting_layer);
84
85 if let Some(opentelemetry_layer) = opentelemetry_layer {
86 let subscriber = subscriber.with(opentelemetry_layer);
87
88 tracing::subscriber::set_global_default(subscriber).context("failed to set subscriber")?;
89 } else {
90 tracing::subscriber::set_global_default(subscriber).context("failed to set subscriber")?;
91 }
92
93 LogTracer::init().context("failed to init log tracer")?;
94
95 Ok(guard)
96}