1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
//! Distributed Tracing 関連の機能を提供する create.

use rustracing::sampler::NullSampler;
use rustracing::tag::StdTag;
use rustracing_jaeger::{Span, Tracer};
use std::cell::RefCell;
use std::sync::{Arc, Mutex};
use trackable::error::{ErrorKind, TrackableError};

thread_local! {
    static TRACER: RefCell<Option<Tracer>> = RefCell::new(None);
}

/// A tracer containing a thread local `Tracer`.
#[derive(Debug, Clone)]
pub struct ThreadLocalTracer {
    tracer: Arc<Mutex<Tracer>>,
}

impl ThreadLocalTracer {
    /// Returns a new `ThreadLocalTracer`.
    pub fn new(tracer: Tracer) -> Self {
        Self {
            tracer: Arc::new(Mutex::new(tracer)),
        }
    }

    /// Returns a new `Span` applying the specified function.
    pub fn span<F>(&self, f: F) -> Span
    where
        F: FnOnce(&Tracer) -> Span,
    {
        TRACER.with(|local_tracer| {
            if local_tracer.borrow().is_none() {
                if let Ok(global_tracer) = self.tracer.try_lock() {
                    *local_tracer.borrow_mut() = Some(global_tracer.clone());
                }
            }
            if let Some(ref t) = *local_tracer.borrow() {
                f(t)
            } else {
                Span::inactive()
            }
        })
    }
}

/// An extension of `Span`.
pub trait SpanExt {
    /// Logs the specified error into the given span.
    fn log_error<K: ErrorKind>(&mut self, e: &TrackableError<K>);
}

impl SpanExt for Span {
    fn log_error<K: ErrorKind>(&mut self, e: &TrackableError<K>) {
        self.set_tag(StdTag::error);
        self.log(|log| {
            let kind = format!("{:?}", e.kind());
            log.error().kind(kind).message(e.to_string());
        })
    }
}

/// Returns a tracer which samples nothing.
pub fn make_null_tracer() -> ThreadLocalTracer {
    let (tracer, _) = rustracing_jaeger::Tracer::new(NullSampler);
    ThreadLocalTracer::new(tracer)
}