metriki_tracing/
lib.rs

1//! # Metriki as a Tracing Backend
2//!
3//! This library acts as a backend for
4//! [tracing](https://github.com/tokio-rs/tracing). It tracks spans
5//! and events created with tracing API and translates them into
6//! [metriki](https://github.com/sunng87/metriki) concepts.
7//!
8//! * Spans are recorded with metriki timers.
9//! * Events are recorded with metriki meters.
10//!
11//! By using this backend, developers are able to add Metriki and its
12//! exporter/reporter ecosystem into tracing without touching metriki
13//! apis.
14//!
15use std::sync::Arc;
16
17use tracing::Subscriber;
18use tracing::{Event, Id};
19use tracing_subscriber::{
20    layer::{Context, Layer},
21    registry::LookupSpan,
22};
23
24use metriki_core::metrics::TimerContextArc;
25use metriki_core::MetricsRegistry;
26
27// A tracing layer to be integrated with tracing_subscriber's
28// Registry.
29//
30// ```no_run
31// // Create MetrikiLayer from metriki registry
32// let layer = MetrikiLayer::new(global_registry());
33//
34// // Create a subscriber with tracing_subscriber's Registry and
35// // configure MetrikiLayer with it
36// let subscriber = Registry::default().with(layer);
37//
38// // Configure the subscriber to tracing
39// tracing::subscriber::set_global_default(subscriber).unwrap();
40// ```
41//
42pub struct MetrikiLayer {
43    registry: Arc<MetricsRegistry>,
44}
45
46impl<S> Layer<S> for MetrikiLayer
47where
48    S: Subscriber + for<'span> LookupSpan<'span>,
49{
50    fn on_event(&self, event: &Event<'_>, _ctx: Context<'_, S>) {
51        // register event as meter
52        // FIXME: better event metrics name
53        self.registry.meter(event.metadata().name()).mark();
54    }
55
56    fn on_enter(&self, _id: &Id, ctx: Context<'_, S>) {
57        if let Some(span_ref) = ctx.lookup_current() {
58            let metadata = span_ref.metadata();
59            let name = metadata.name();
60            let timer = self.registry.timer(name);
61            let timer_ctx = TimerContextArc::start(timer);
62
63            span_ref.extensions_mut().insert(timer_ctx);
64        }
65    }
66
67    fn on_exit(&self, _id: &Id, ctx: Context<'_, S>) {
68        if let Some(span_ref) = ctx.lookup_current() {
69            if let Some(timer_ctx) = span_ref.extensions().get::<TimerContextArc>() {
70                timer_ctx.stop();
71            }
72        }
73    }
74}
75
76impl MetrikiLayer {
77    // Create `MetrikiLayer` from a Metriki MetricsRegistry
78    pub fn new(registry: Arc<MetricsRegistry>) -> MetrikiLayer {
79        MetrikiLayer { registry }
80    }
81}