opentelemetry/trace/tracer.rs
1use crate::{
2 trace::{Event, Link, Span, SpanId, SpanKind, Status, TraceContextExt, TraceId, TraceState},
3 Context, KeyValue,
4};
5use std::borrow::Cow;
6use std::time::SystemTime;
7
8/// The interface for constructing [`Span`]s.
9///
10/// ## In Synchronous Code
11///
12/// Spans can be created and nested manually:
13///
14/// ```
15/// use opentelemetry::{global, trace::{Span, Tracer, TraceContextExt}, Context};
16///
17/// let tracer = global::tracer("my-component");
18///
19/// let parent = tracer.start("foo");
20/// let parent_cx = Context::current_with_span(parent);
21/// let mut child = tracer.start_with_context("bar", &parent_cx);
22///
23/// // ...
24///
25/// child.end(); // explicitly end
26/// drop(parent_cx) // or implicitly end on drop
27/// ```
28///
29/// Spans can also use the current thread's [`Context`] to track which span is active:
30///
31/// ```
32/// use opentelemetry::{global, trace::{SpanKind, Tracer}};
33///
34/// let tracer = global::tracer("my-component");
35///
36/// // Create simple spans with `in_span`
37/// tracer.in_span("foo", |_foo_cx| {
38/// // parent span is active
39/// tracer.in_span("bar", |_bar_cx| {
40/// // child span is now the active span and associated with the parent span
41/// });
42/// // child has ended, parent now the active span again
43/// });
44/// // parent has ended, no active spans
45/// ```
46///
47/// Spans can also be marked as active, and the resulting guard allows for
48/// greater control over when the span is no longer considered active.
49///
50/// ```
51/// use opentelemetry::{global, trace::{Span, Tracer, mark_span_as_active}};
52/// let tracer = global::tracer("my-component");
53///
54/// let parent_span = tracer.start("foo");
55/// let parent_active = mark_span_as_active(parent_span);
56///
57/// {
58/// let child = tracer.start("bar");
59/// let _child_active = mark_span_as_active(child);
60///
61/// // do work in the context of the child span...
62///
63/// // exiting the scope drops the guard, child is no longer active
64/// }
65/// // Parent is active span again
66///
67/// // Parent can be dropped manually, or allowed to go out of scope as well.
68/// drop(parent_active);
69///
70/// // no active span
71/// ```
72///
73/// ## In Asynchronous Code
74///
75/// If you are instrumenting code that make use of [`std::future::Future`] or
76/// async/await, be sure to use the [`FutureExt`] trait. This is needed because
77/// the following example _will not_ work:
78///
79/// ```no_run
80/// # use opentelemetry::{global, trace::{Tracer, mark_span_as_active}};
81/// # let tracer = global::tracer("foo");
82/// # let span = tracer.start("foo-span");
83/// async {
84/// // Does not work
85/// let _g = mark_span_as_active(span);
86/// // ...
87/// };
88/// ```
89///
90/// The context guard `_g` will not exit until the future generated by the
91/// `async` block is complete. Since futures can be entered and exited
92/// _multiple_ times without them completing, the span remains active for as
93/// long as the future exists, rather than only when it is polled, leading to
94/// very confusing and incorrect output.
95///
96/// In order to trace asynchronous code, the [`Future::with_context`] combinator
97/// can be used:
98///
99/// ```
100/// # async fn run() -> Result<(), ()> {
101/// use opentelemetry::{trace::FutureExt, Context};
102/// let cx = Context::current();
103///
104/// let my_future = async {
105/// // ...
106/// };
107///
108/// my_future
109/// .with_context(cx)
110/// .await;
111/// # Ok(())
112/// # }
113/// ```
114///
115/// [`Future::with_context`] attaches a context to the future, ensuring that the
116/// context's lifetime is as long as the future's.
117///
118/// [`FutureExt`]: crate::trace::FutureExt
119/// [`Future::with_context`]: crate::trace::FutureExt::with_context()
120/// [`Context`]: crate::Context
121pub trait Tracer {
122 /// The [`Span`] type used by this tracer.
123 type Span: Span;
124
125 /// Starts a new [`Span`].
126 ///
127 /// By default the currently active `Span` is set as the new `Span`'s parent.
128 ///
129 /// Each span has zero or one parent span and zero or more child spans, which
130 /// represent causally related operations. A tree of related spans comprises a
131 /// trace. A span is said to be a root span if it does not have a parent. Each
132 /// trace includes a single root span, which is the shared ancestor of all other
133 /// spans in the trace.
134 fn start<T>(&self, name: T) -> Self::Span
135 where
136 T: Into<Cow<'static, str>>,
137 {
138 Context::map_current(|cx| self.start_with_context(name, cx))
139 }
140
141 /// Starts a new [`Span`] with a given context.
142 ///
143 /// If this context contains a span, the newly created span will be a child of
144 /// that span.
145 ///
146 /// Each span has zero or one parent span and zero or more child spans, which
147 /// represent causally related operations. A tree of related spans comprises a
148 /// trace. A span is said to be a root span if it does not have a parent. Each
149 /// trace includes a single root span, which is the shared ancestor of all other
150 /// spans in the trace.
151 fn start_with_context<T>(&self, name: T, parent_cx: &Context) -> Self::Span
152 where
153 T: Into<Cow<'static, str>>,
154 {
155 self.build_with_context(SpanBuilder::from_name(name), parent_cx)
156 }
157
158 /// Creates a span builder.
159 ///
160 /// [`SpanBuilder`]s allow you to specify all attributes of a [`Span`] before
161 /// the span is started.
162 fn span_builder<T>(&self, name: T) -> SpanBuilder
163 where
164 T: Into<Cow<'static, str>>,
165 {
166 SpanBuilder::from_name(name)
167 }
168
169 /// Start a [`Span`] from a [`SpanBuilder`].
170 fn build(&self, builder: SpanBuilder) -> Self::Span {
171 Context::map_current(|cx| self.build_with_context(builder, cx))
172 }
173
174 /// Start a span from a [`SpanBuilder`] with a parent context.
175 fn build_with_context(&self, builder: SpanBuilder, parent_cx: &Context) -> Self::Span;
176
177 /// Start a new span and execute the given closure with reference to the context
178 /// in which the span is active.
179 ///
180 /// This method starts a new span and sets it as the active span for the given
181 /// function. It then executes the body. It ends the span before returning the
182 /// execution result.
183 ///
184 /// # Examples
185 ///
186 /// ```
187 /// use opentelemetry::{global, trace::{Span, Tracer, get_active_span}, KeyValue};
188 ///
189 /// fn my_function() {
190 /// // start an active span in one function
191 /// global::tracer("my-component").in_span("span-name", |_cx| {
192 /// // anything happening in functions we call can still access the active span...
193 /// my_other_function();
194 /// })
195 /// }
196 ///
197 /// fn my_other_function() {
198 /// // call methods on the current span from
199 /// get_active_span(|span| {
200 /// span.add_event("An event!".to_string(), vec![KeyValue::new("happened", true)]);
201 /// })
202 /// }
203 /// ```
204 fn in_span<T, F, N>(&self, name: N, f: F) -> T
205 where
206 F: FnOnce(Context) -> T,
207 N: Into<Cow<'static, str>>,
208 Self::Span: Send + Sync + 'static,
209 {
210 let span = self.start(name);
211 let cx = Context::current_with_span(span);
212 let _guard = cx.clone().attach();
213 f(cx)
214 }
215}
216
217/// `SpanBuilder` allows span attributes to be configured before the span
218/// has started.
219///
220/// ```
221/// use opentelemetry::{
222/// global,
223/// trace::{TracerProvider, SpanBuilder, SpanKind, Tracer},
224/// };
225///
226/// let tracer = global::tracer("example-tracer");
227///
228/// // The builder can be used to create a span directly with the tracer
229/// let _span = tracer.build(SpanBuilder {
230/// name: "example-span-name".into(),
231/// span_kind: Some(SpanKind::Server),
232/// ..Default::default()
233/// });
234///
235/// // Or used with builder pattern
236/// let _span = tracer
237/// .span_builder("example-span-name")
238/// .with_kind(SpanKind::Server)
239/// .start(&tracer);
240/// ```
241#[derive(Clone, Debug, Default)]
242pub struct SpanBuilder {
243 /// Trace id, useful for integrations with external tracing systems.
244 pub trace_id: Option<TraceId>,
245
246 /// Span id, useful for integrations with external tracing systems.
247 pub span_id: Option<SpanId>,
248
249 /// Span kind
250 pub span_kind: Option<SpanKind>,
251
252 /// Span name
253 pub name: Cow<'static, str>,
254
255 /// Span start time
256 pub start_time: Option<SystemTime>,
257
258 /// Span end time
259 pub end_time: Option<SystemTime>,
260
261 /// Span attributes that are provided at the span creation time.
262 /// More attributes can be added afterwards.
263 /// Providing duplicate keys will result in multiple attributes
264 /// with the same key, as there is no de-duplication performed.
265 pub attributes: Option<Vec<KeyValue>>,
266
267 /// Span events
268 pub events: Option<Vec<Event>>,
269
270 /// Span Links
271 pub links: Option<Vec<Link>>,
272
273 /// Span status
274 pub status: Status,
275
276 /// Sampling result
277 pub sampling_result: Option<SamplingResult>,
278}
279
280/// SpanBuilder methods
281impl SpanBuilder {
282 /// Create a new span builder from a span name
283 pub fn from_name<T: Into<Cow<'static, str>>>(name: T) -> Self {
284 SpanBuilder {
285 name: name.into(),
286 ..Default::default()
287 }
288 }
289
290 /// Specify trace id to use if no parent context exists
291 pub fn with_trace_id(self, trace_id: TraceId) -> Self {
292 SpanBuilder {
293 trace_id: Some(trace_id),
294 ..self
295 }
296 }
297
298 /// Assign span id
299 pub fn with_span_id(self, span_id: SpanId) -> Self {
300 SpanBuilder {
301 span_id: Some(span_id),
302 ..self
303 }
304 }
305
306 /// Assign span kind
307 pub fn with_kind(self, span_kind: SpanKind) -> Self {
308 SpanBuilder {
309 span_kind: Some(span_kind),
310 ..self
311 }
312 }
313
314 /// Assign span start time
315 pub fn with_start_time<T: Into<SystemTime>>(self, start_time: T) -> Self {
316 SpanBuilder {
317 start_time: Some(start_time.into()),
318 ..self
319 }
320 }
321
322 /// Assign span end time
323 pub fn with_end_time<T: Into<SystemTime>>(self, end_time: T) -> Self {
324 SpanBuilder {
325 end_time: Some(end_time.into()),
326 ..self
327 }
328 }
329
330 /// Assign span attributes from an iterable.
331 /// Providing duplicate keys will result in multiple attributes
332 /// with the same key, as there is no de-duplication performed.
333 pub fn with_attributes<I>(self, attributes: I) -> Self
334 where
335 I: IntoIterator<Item = KeyValue>,
336 {
337 SpanBuilder {
338 attributes: Some(attributes.into_iter().collect()),
339 ..self
340 }
341 }
342
343 /// Assign events
344 pub fn with_events(self, events: Vec<Event>) -> Self {
345 SpanBuilder {
346 events: Some(events),
347 ..self
348 }
349 }
350
351 /// Assign links
352 pub fn with_links(self, mut links: Vec<Link>) -> Self {
353 links.retain(|l| l.span_context.is_valid());
354 SpanBuilder {
355 links: Some(links),
356 ..self
357 }
358 }
359
360 /// Assign status code
361 pub fn with_status(self, status: Status) -> Self {
362 SpanBuilder { status, ..self }
363 }
364
365 /// Assign sampling result
366 pub fn with_sampling_result(self, sampling_result: SamplingResult) -> Self {
367 SpanBuilder {
368 sampling_result: Some(sampling_result),
369 ..self
370 }
371 }
372
373 /// Builds a span with the given tracer from this configuration.
374 pub fn start<T: Tracer>(self, tracer: &T) -> T::Span {
375 Context::map_current(|cx| tracer.build_with_context(self, cx))
376 }
377
378 /// Builds a span with the given tracer from this configuration and parent.
379 pub fn start_with_context<T: Tracer>(self, tracer: &T, parent_cx: &Context) -> T::Span {
380 tracer.build_with_context(self, parent_cx)
381 }
382}
383
384/// The result of sampling logic for a given span.
385#[derive(Clone, Debug, PartialEq)]
386pub struct SamplingResult {
387 /// The decision about whether or not to sample.
388 pub decision: SamplingDecision,
389
390 /// Extra attributes to be added to the span by the sampler
391 pub attributes: Vec<KeyValue>,
392
393 /// Trace state from parent context, may be modified by samplers.
394 pub trace_state: TraceState,
395}
396
397/// Decision about whether or not to sample
398#[derive(Clone, Debug, PartialEq, Eq)]
399pub enum SamplingDecision {
400 /// Span will not be recorded and all events and attributes will be dropped.
401 Drop,
402
403 /// Span data wil be recorded, but not exported.
404 RecordOnly,
405
406 /// Span data will be recorded and exported.
407 RecordAndSample,
408}