prima_tracing/
subscriber.rs

1use tracing::{Event, Subscriber};
2use tracing_log::LogTracer;
3use tracing_subscriber::{
4    layer::{Context, SubscriberExt},
5    EnvFilter,
6};
7
8use crate::config::SubscriberConfig;
9
10pub struct Tracing;
11
12impl Tracing {}
13
14/// Configure a subscriber using [`SubscriberConfig`].
15/// The configuration is behind feature flags
16/// - `default`: uses the [`tracing_subscriber::fmt::layer()`]
17/// - `json-logger`: activate the json logger
18/// - `traces`: activate spans export via `opentelemetry-otlp`
19pub fn configure_subscriber<T: EventFormatter + Send + Sync + 'static>(
20    _config: SubscriberConfig<T>,
21) -> impl Subscriber + Send + Sync {
22    let subscriber = tracing_subscriber::Registry::default();
23    let subscriber = subscriber.with(EnvFilter::from_default_env());
24
25    #[cfg(feature = "traces")]
26    let subscriber = {
27        let tracer = crate::telemetry::configure(&_config);
28        subscriber
29            .with(tracing_opentelemetry::layer().with_tracer(tracer))
30            .with(crate::layer::VersionLayer {
31                version: _config.version.clone(),
32            })
33            .with(crate::layer::ErrorLayer)
34            .with(crate::layer::KubeEnvLayer::default())
35    };
36
37    #[cfg(not(feature = "json-logger"))]
38    let subscriber = subscriber.with(tracing_subscriber::fmt::layer());
39    #[cfg(feature = "json-logger")]
40    let subscriber = {
41        use crate::json::formatter::PrimaFormattingLayer;
42        use crate::json::storage::PrimaJsonStorage;
43        subscriber
44            .with(PrimaJsonStorage)
45            .with(crate::layer::KubeEnvLayer::default())
46            .with(PrimaFormattingLayer::new(
47                _config.service.clone(),
48                _config.country.to_string(),
49                _config.env.to_string(),
50                &std::io::stdout,
51                _config.json_formatter,
52            ))
53    };
54
55    subscriber
56}
57/// Initialize the subscriber and return the [`Uninstall`] guard
58pub fn init_subscriber(subscriber: impl Subscriber + Sync + Send) -> Uninstall {
59    LogTracer::init().expect("Failed to set logger");
60    tracing::subscriber::set_global_default(subscriber).expect("Setting default subscriber failed");
61
62    #[cfg(feature = "traces")]
63    {
64        use opentelemetry::global;
65        use opentelemetry_sdk::propagation::TraceContextPropagator;
66        global::set_text_map_propagator(TraceContextPropagator::new());
67    };
68    Uninstall
69}
70/// `EventFormatter` allows you to customise the format of [`tracing::Event`] if the `json-logger` feature is active
71pub trait EventFormatter {
72    fn format_event<S>(
73        &self,
74        event: &Event<'_>,
75        ctx: Context<'_, S>,
76        info: ContextInfo<'_>,
77    ) -> Result<Vec<u8>, std::io::Error>
78    where
79        S: Subscriber + for<'a> tracing_subscriber::registry::LookupSpan<'a>;
80}
81/// Uninstall guard for doing works in shutdown
82pub struct Uninstall;
83
84impl Drop for Uninstall {
85    fn drop(&mut self) {
86        #[cfg(feature = "traces")]
87        crate::telemetry::shutdown_tracer_provider();
88    }
89}
90/// Information about the current app context like name or environment
91pub struct ContextInfo<'a> {
92    pub(crate) app_name: &'a str,
93    pub(crate) country: &'a str,
94    pub(crate) environment: &'a str,
95}
96
97impl<'a> ContextInfo<'a> {
98    pub fn app_name(&self) -> &'a str {
99        self.app_name
100    }
101
102    pub fn country(&self) -> &'a str {
103        self.country
104    }
105
106    pub fn environment(&self) -> &'a str {
107        self.environment
108    }
109}
110
111pub struct NopEventFormatter;
112
113impl EventFormatter for NopEventFormatter {
114    fn format_event<S>(
115        &self,
116        _event: &Event<'_>,
117        _ctx: Context<'_, S>,
118        _info: ContextInfo<'_>,
119    ) -> Result<Vec<u8>, std::io::Error>
120    where
121        S: Subscriber + for<'a> tracing_subscriber::registry::LookupSpan<'a>,
122    {
123        Ok(vec![])
124    }
125}