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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
use crate::{
    push_span, stack::SpanStackGuard, with_top_or_null, EncodedSpanContext, Span, SpanContext,
    SpanWrap, Tag, Tracer,
};
/// Add a span to the stack that follows from a SpanWrap
/// # Example
/// ```
/// # use holochain_tracing::{null_tracer, Span, follow};
/// # let tracer = null_tracer();
/// # let data = 1;
/// # let span = Span::from(tracer.span("Following from some incoming span wrap").start());
/// # let tracer = Some(tracer);
/// # let span_wrap = span.wrap(data);
/// let _spanguard = follow(&tracer, &span_wrap, "func_name".into());
/// ```
pub fn follow<T>(
    tracer: &Option<Tracer>,
    span_wrap: &SpanWrap<T>,
    name: String,
) -> Option<SpanStackGuard> {
    tracer
        .as_ref()
        .map(|t| {
            let root_span = span_wrap
                .span_context
                .as_ref()
                .map(|c| c.follower(&t, name));
            root_span.map(|span| push_span(span))
        })
        .flatten()
}

pub fn follow_encoded(
    tracer: &Option<Tracer>,
    span_context: &EncodedSpanContext,
    name: String,
) -> Option<SpanStackGuard> {
    follow_encoded_tag_inner(tracer, span_context, name, None)
}

pub fn follow_encoded_tag(
    tracer: &Option<Tracer>,
    span_context: &EncodedSpanContext,
    name: String,
    tag: Tag,
) -> Option<SpanStackGuard> {
    follow_encoded_tag_inner(tracer, span_context, name, Some(tag))
}

fn follow_encoded_tag_inner(
    tracer: &Option<Tracer>,
    span_context: &EncodedSpanContext,
    name: String,
    tag: Option<Tag>,
) -> Option<SpanStackGuard> {
    tracer.as_ref().and_then(|t| {
        let root_span = SpanContext::decode(span_context.clone()).ok().map(|c| {
            c.follower_(&t, name, |options| {
                if let Some(tag) = tag {
                    options.tag(tag).start()
                } else {
                    options.start()
                }
            })
        });
        root_span.map(|span| push_span(span))
    })
}

pub fn wrap<T>(data: T, name: String) -> SpanWrap<T> {
    wrap_with_tag_inner(data, name, None)
}

pub fn wrap_with_tag<T>(data: T, name: String, tag: Tag) -> SpanWrap<T> {
    wrap_with_tag_inner(data, name, Some(tag))
}

fn wrap_with_tag_inner<T>(data: T, name: String, tag: Option<Tag>) -> SpanWrap<T> {
    with_top_or_null(|top| {
        let child: Span = top
            .follower_(name, |options| {
                if let Some(tag) = tag {
                    options.tag(tag).start()
                } else {
                    options.start()
                }
            })
            .into();
        child.wrap(data)
    })
}