Skip to main content

sofie_db/
trace.rs

1use std::time::{Duration, Instant};
2
3use sofie_core::Result;
4use tracing::field::Empty;
5use tracing::{Instrument, Span};
6
7const SLOW_STATEMENT: Duration = Duration::from_millis(250);
8
9/// Outside traced work no span opens, or the worker's polling would trace every second.
10pub async fn traced_statement<T>(
11    sql: &str,
12    run: impl Future<Output = Result<T>>,
13    rows: impl FnOnce(&T) -> Option<u64>,
14) -> Result<T> {
15    let span = if Span::current().is_disabled() {
16        Span::none()
17    } else {
18        tracing::info_span!("statement", db.query.text = sql, db.rows = Empty)
19    };
20    let started = Instant::now();
21    let result = run.instrument(span.clone()).await;
22    if let Some(count) = result.as_ref().ok().and_then(rows) {
23        span.record("db.rows", count);
24    }
25    let elapsed = started.elapsed();
26    #[cfg(feature = "metrics")]
27    crate::metrics::statement(sql, elapsed);
28    if elapsed > SLOW_STATEMENT {
29        let duration_ms = u64::try_from(elapsed.as_millis()).unwrap_or(u64::MAX);
30        span.in_scope(|| tracing::warn!(db.query.text = sql, duration_ms, "slow statement"));
31    }
32    result
33}