objectstore_server/
observability.rs1use secrecy::ExposeSecret;
8use sentry::integrations::tracing as sentry_tracing;
9use tracing::Level;
10use tracing::level_filters::LevelFilter;
11use tracing_subscriber::{EnvFilter, prelude::*};
12
13use crate::config::{Config, LogFormat};
14
15const RELEASE: &str = std::env!("OBJECTSTORE_RELEASE");
17
18pub fn init_sentry(config: &Config) -> Option<sentry::ClientInitGuard> {
24 let config = &config.sentry;
25 let dsn = config.dsn.as_ref()?;
26
27 let guard = sentry::init(sentry::ClientOptions {
28 dsn: dsn.expose_secret().parse().ok(),
29 release: Some(RELEASE.into()),
30 environment: config.environment.clone(),
31 server_name: config.server_name.clone(),
32 sample_rate: config.sample_rate,
33 traces_sampler: {
34 let traces_sample_rate = config.traces_sample_rate;
35 let inherit_sampling_decision = config.inherit_sampling_decision;
36 Some(std::sync::Arc::new(move |ctx| {
37 if let Some(sampled) = ctx.sampled()
38 && inherit_sampling_decision
39 {
40 f32::from(sampled)
41 } else {
42 traces_sample_rate
43 }
44 }))
45 },
46 enable_logs: true,
47 debug: config.debug,
48 ..Default::default()
49 });
50
51 sentry::configure_scope(|scope| {
52 for (k, v) in &config.tags {
53 scope.set_tag(k, v);
54 }
55 });
56
57 Some(guard)
58}
59
60pub fn init_tracing(config: &Config) {
66 let sentry_layer = config.sentry.is_enabled().then(|| {
69 sentry_tracing::layer().event_filter(|metadata| match *metadata.level() {
70 Level::ERROR | Level::WARN => {
71 sentry_tracing::EventFilter::Event | sentry_tracing::EventFilter::Log
72 }
73 Level::INFO | Level::DEBUG => sentry_tracing::EventFilter::Log,
74 Level::TRACE => sentry_tracing::EventFilter::Ignore,
75 })
76 });
77
78 let format = tracing_subscriber::fmt::layer()
79 .with_writer(std::io::stderr)
80 .with_target(true);
81
82 let format = match (config.logging.format, console::user_attended()) {
83 (LogFormat::Auto, true) | (LogFormat::Pretty, _) => format.compact().without_time().boxed(),
84 (LogFormat::Auto, false) | (LogFormat::Simplified, _) => format.with_ansi(false).boxed(),
85 (LogFormat::Json, _) => format
86 .json()
87 .flatten_event(true)
88 .with_current_span(true)
89 .with_span_list(true)
90 .with_file(true)
91 .with_line_number(true)
92 .boxed(),
93 };
94
95 let env_filter = match EnvFilter::try_from_default_env() {
96 Ok(env_filter) => env_filter,
97 Err(_) => EnvFilter::new(
100 "INFO,\
101 tower_http=DEBUG,\
102 objectstore=TRACE,\
103 objectstore_service=TRACE,\
104 objectstore_types=TRACE,\
105 ",
106 ),
107 };
108
109 tracing_subscriber::registry()
110 .with(format.with_filter(config.logging.level))
111 .with(sentry_layer)
112 .with(env_filter)
113 .init();
114}
115
116pub fn ensure_log_error(error: &anyhow::Error) {
118 if tracing::Level::ERROR <= tracing::level_filters::STATIC_MAX_LEVEL
119 && tracing::Level::ERROR <= LevelFilter::current()
120 {
121 tracing::error!(error = error.as_ref() as &dyn std::error::Error);
122 } else {
123 eprintln!("{error:?}");
124 }
125}