dora_tracing/
lib.rs

1//! Enable tracing using Opentelemetry and Jaeger.
2//!
3//! This module init a tracing propagator for Rust code that requires tracing, and is
4//! able to serialize and deserialize context that has been sent via the middleware.
5
6use std::path::Path;
7
8use eyre::Context as EyreContext;
9use tracing::metadata::LevelFilter;
10use tracing_subscriber::{
11    filter::FilterExt, prelude::__tracing_subscriber_SubscriberExt, EnvFilter, Layer,
12};
13
14use eyre::ContextCompat;
15use tracing_subscriber::Registry;
16pub mod telemetry;
17
18pub fn set_up_tracing(name: &str) -> eyre::Result<()> {
19    set_up_tracing_opts(name, Some("warn"), None)
20}
21
22pub struct FileLogging {
23    pub file_name: String,
24    pub filter: LevelFilter,
25}
26
27pub fn set_up_tracing_opts(
28    name: &str,
29    stdout_filter: Option<impl AsRef<str>>,
30    file: Option<FileLogging>,
31) -> eyre::Result<()> {
32    let mut layers = Vec::new();
33
34    if let Some(filter) = stdout_filter {
35        let parsed = EnvFilter::builder().parse_lossy(filter);
36        // Filter log using `RUST_LOG`. More useful for CLI.
37        let env_filter = EnvFilter::from_default_env().or(parsed);
38        let layer = tracing_subscriber::fmt::layer()
39            .compact()
40            .with_filter(env_filter);
41        layers.push(layer.boxed());
42    }
43
44    if let Some(file) = file {
45        let FileLogging { file_name, filter } = file;
46        let out_dir = Path::new("out");
47        std::fs::create_dir_all(out_dir).context("failed to create `out` directory")?;
48        let path = out_dir.join(file_name).with_extension("txt");
49        let file = std::fs::OpenOptions::new()
50            .create(true)
51            .append(true)
52            .open(path)
53            .context("failed to create log file")?;
54        // Filter log using `RUST_LOG`. More useful for CLI.
55        let layer = tracing_subscriber::fmt::layer()
56            .with_ansi(false)
57            .with_writer(file)
58            .with_filter(filter);
59        layers.push(layer.boxed());
60    }
61
62    if let Some(endpoint) = std::env::var_os("DORA_JAEGER_TRACING") {
63        let endpoint = endpoint
64            .to_str()
65            .wrap_err("Could not parse env variable: DORA_JAEGER_TRACING")?;
66        let tracer = crate::telemetry::init_jaeger_tracing(name, endpoint)
67            .wrap_err("Could not instantiate tracing")?;
68        let telemetry = tracing_opentelemetry::layer().with_tracer(tracer);
69        layers.push(telemetry.boxed());
70    }
71
72    let registry = Registry::default().with(layers);
73    tracing::subscriber::set_global_default(registry).context(format!(
74        "failed to set tracing global subscriber for {name}"
75    ))
76}