opentelemetry/trace/tracer.rs
1use crate::{
2 trace::{Event, Link, Span, SpanKind, TraceContextExt},
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/// Pass a [`Context`] explicitly to [`Tracer::start_with_context`] when you
76/// want to choose a span's parent. To make a context current within async
77/// code, use [`FutureExt::with_context`]. Do not hold a [`Context::attach`]
78/// guard or a [`mark_span_as_active`] guard across an `.await`: while the
79/// task is suspended, unrelated code on the same thread could see that
80/// context as current.
81///
82/// ```
83/// # async fn run() -> Result<(), ()> {
84/// use opentelemetry::{trace::FutureExt, Context};
85/// let cx = Context::current();
86///
87/// let my_future = async {
88/// // ...
89/// };
90///
91/// my_future
92/// .with_context(cx)
93/// .await;
94/// # Ok(())
95/// # }
96/// ```
97///
98/// The wrapper makes the context current for each poll and restores the
99/// previous context when that poll returns. Creating a span, making it current,
100/// and ending it are separate operations. See [Async context
101/// propagation](crate::trace#async-context-propagation) for an example that
102/// creates a child span inside a future.
103///
104/// [`FutureExt::with_context`]: crate::trace::FutureExt::with_context
105/// [`mark_span_as_active`]: crate::trace::mark_span_as_active
106/// [`Context`]: crate::Context
107pub trait Tracer {
108 /// The [`Span`] type used by this tracer.
109 type Span: Span;
110
111 /// Starts a new [`Span`].
112 ///
113 /// By default the currently active `Span` is set as the new `Span`'s parent.
114 ///
115 /// Each span has zero or one parent span and zero or more child spans, which
116 /// represent causally related operations. A tree of related spans comprises a
117 /// trace. A span is said to be a root span if it does not have a parent. Each
118 /// trace includes a single root span, which is the shared ancestor of all other
119 /// spans in the trace.
120 fn start<T>(&self, name: T) -> Self::Span
121 where
122 T: Into<Cow<'static, str>>,
123 {
124 Context::map_current(|cx| self.start_with_context(name, cx))
125 }
126
127 /// Starts a new [`Span`] with a given context.
128 ///
129 /// If this context contains a span, the newly created span will be a child of
130 /// that span.
131 ///
132 /// Each span has zero or one parent span and zero or more child spans, which
133 /// represent causally related operations. A tree of related spans comprises a
134 /// trace. A span is said to be a root span if it does not have a parent. Each
135 /// trace includes a single root span, which is the shared ancestor of all other
136 /// spans in the trace.
137 fn start_with_context<T>(&self, name: T, parent_cx: &Context) -> Self::Span
138 where
139 T: Into<Cow<'static, str>>,
140 {
141 self.build_with_context(SpanBuilder::from_name(name), parent_cx)
142 }
143
144 /// Creates a span builder.
145 ///
146 /// [`SpanBuilder`]s allow you to specify all attributes of a [`Span`] before
147 /// the span is started.
148 fn span_builder<T>(&self, name: T) -> SpanBuilder
149 where
150 T: Into<Cow<'static, str>>,
151 {
152 SpanBuilder::from_name(name)
153 }
154
155 /// Start a [`Span`] from a [`SpanBuilder`].
156 fn build(&self, builder: SpanBuilder) -> Self::Span {
157 Context::map_current(|cx| self.build_with_context(builder, cx))
158 }
159
160 /// Start a span from a [`SpanBuilder`] with a parent context.
161 fn build_with_context(&self, builder: SpanBuilder, parent_cx: &Context) -> Self::Span;
162
163 /// Start a new span and execute the given closure with reference to the context
164 /// in which the span is active.
165 ///
166 /// This method starts a new span and sets it as the active span for the given
167 /// function. It then executes the body. It ends the span before returning the
168 /// execution result.
169 ///
170 /// # Examples
171 ///
172 /// ```
173 /// use opentelemetry::{global, trace::{Span, Tracer, get_active_span}, KeyValue};
174 ///
175 /// fn my_function() {
176 /// // start an active span in one function
177 /// global::tracer("my-component").in_span("span-name", |_cx| {
178 /// // anything happening in functions we call can still access the active span...
179 /// my_other_function();
180 /// })
181 /// }
182 ///
183 /// fn my_other_function() {
184 /// // call methods on the current span from
185 /// get_active_span(|span| {
186 /// span.add_event("An event!".to_string(), vec![KeyValue::new("happened", true)]);
187 /// })
188 /// }
189 /// ```
190 fn in_span<T, F, N>(&self, name: N, f: F) -> T
191 where
192 F: FnOnce(Context) -> T,
193 N: Into<Cow<'static, str>>,
194 Self::Span: Send + Sync + 'static,
195 {
196 self.in_span_with_builder(self.span_builder(name), f)
197 }
198
199 /// Start a new span with a given parent context and execute the given closure with
200 /// reference to the context in which the span is active.
201 ///
202 /// This method starts a new span as a child of the provided parent context and sets
203 /// it as the active span for the given function. It then executes the body. It ends
204 /// the span before returning the execution result.
205 ///
206 /// # Examples
207 ///
208 /// ```
209 /// use opentelemetry::{global, trace::{Span, Tracer, TraceContextExt}, Context, KeyValue};
210 ///
211 /// fn my_function() {
212 /// let tracer = global::tracer("my-component");
213 ///
214 /// // Create a parent context
215 /// let parent = tracer.start("parent-span");
216 /// let parent_cx = Context::current_with_span(parent);
217 ///
218 /// // start an active span with explicit parent context
219 /// tracer.in_span_with_context("child-span", &parent_cx, |_cx| {
220 /// // child span is active here
221 /// })
222 /// }
223 /// ```
224 fn in_span_with_context<T, F, N>(&self, name: N, parent_cx: &Context, f: F) -> T
225 where
226 F: FnOnce(Context) -> T,
227 N: Into<Cow<'static, str>>,
228 Self::Span: Send + Sync + 'static,
229 {
230 self.in_span_with_builder_and_context(self.span_builder(name), parent_cx, f)
231 }
232
233 /// Start a new span from a [`SpanBuilder`] and execute the given closure with
234 /// reference to the context in which the span is active.
235 ///
236 /// This method builds and starts a new span from a [`SpanBuilder`] using the current
237 /// context and sets it as the active span for the given function. It then executes
238 /// the body. It ends the span before returning the execution result.
239 ///
240 /// # Examples
241 ///
242 /// ```
243 /// use opentelemetry::{global, trace::{Span, SpanKind, Tracer}, KeyValue};
244 ///
245 /// fn my_function() {
246 /// let tracer = global::tracer("my-component");
247 ///
248 /// // start an active span with span configuration
249 /// tracer.in_span_with_builder(
250 /// tracer.span_builder("span-name")
251 /// .with_kind(SpanKind::Client)
252 /// .with_attributes(vec![KeyValue::new("key", "value")]),
253 /// |_cx| {
254 /// // span is active here with configured attributes
255 /// }
256 /// )
257 /// }
258 /// ```
259 fn in_span_with_builder<T, F>(&self, builder: SpanBuilder, f: F) -> T
260 where
261 F: FnOnce(Context) -> T,
262 Self::Span: Send + Sync + 'static,
263 {
264 let span = self.build(builder);
265 let cx = Context::current_with_span(span);
266 let _guard = cx.clone().attach();
267 f(cx)
268 }
269
270 /// Start a new span from a [`SpanBuilder`] with a given parent context and execute the
271 /// given closure with reference to the context in which the span is active.
272 ///
273 /// This method builds and starts a new span from a [`SpanBuilder`] as a child of the
274 /// provided parent context and sets it as the active span for the given function. It
275 /// then executes the body. It ends the span before returning the execution result.
276 ///
277 /// # Examples
278 ///
279 /// ```
280 /// use opentelemetry::{global, trace::{Span, SpanKind, Tracer, TraceContextExt}, Context, KeyValue};
281 ///
282 /// fn my_function() {
283 /// let tracer = global::tracer("my-component");
284 ///
285 /// // Create a parent context
286 /// let parent = tracer.start("parent-span");
287 /// let parent_cx = Context::current_with_span(parent);
288 ///
289 /// // start an active span with explicit parent context and span configuration
290 /// tracer.in_span_with_builder_and_context(
291 /// tracer.span_builder("child-span")
292 /// .with_kind(SpanKind::Client)
293 /// .with_attributes(vec![KeyValue::new("key", "value")]),
294 /// &parent_cx,
295 /// |_cx| {
296 /// // child span is active here with configured attributes
297 /// }
298 /// )
299 /// }
300 /// ```
301 fn in_span_with_builder_and_context<T, F>(
302 &self,
303 builder: SpanBuilder,
304 parent_cx: &Context,
305 f: F,
306 ) -> T
307 where
308 F: FnOnce(Context) -> T,
309 Self::Span: Send + Sync + 'static,
310 {
311 let span = self.build_with_context(builder, parent_cx);
312 let cx = parent_cx.with_span(span);
313 let _guard = cx.clone().attach();
314 f(cx)
315 }
316}
317
318/// `SpanBuilder` allows span attributes to be configured before the span
319/// has started.
320///
321/// ```
322/// use opentelemetry::{
323/// global,
324/// trace::{TracerProvider, SpanBuilder, SpanKind, Tracer},
325/// };
326///
327/// let tracer = global::tracer("example-tracer");
328///
329/// // The builder can be used to create a span directly with the tracer
330/// let _span = tracer.build(SpanBuilder {
331/// name: "example-span-name".into(),
332/// span_kind: Some(SpanKind::Server),
333/// ..Default::default()
334/// });
335///
336/// // Or used with builder pattern
337/// let _span = tracer
338/// .span_builder("example-span-name")
339/// .with_kind(SpanKind::Server)
340/// .start(&tracer);
341/// ```
342#[derive(Clone, Debug, Default)]
343pub struct SpanBuilder {
344 /// Span kind
345 pub span_kind: Option<SpanKind>,
346
347 /// Span name
348 pub name: Cow<'static, str>,
349
350 /// Span start time
351 pub start_time: Option<SystemTime>,
352
353 /// Span attributes that are provided at the span creation time.
354 /// More attributes can be added afterwards.
355 /// Providing duplicate keys will result in multiple attributes
356 /// with the same key, as there is no de-duplication performed.
357 pub attributes: Option<Vec<KeyValue>>,
358
359 /// Span events
360 pub events: Option<Vec<Event>>,
361
362 /// Span Links
363 pub links: Option<Vec<Link>>,
364}
365
366/// SpanBuilder methods
367impl SpanBuilder {
368 /// Create a new span builder from a span name
369 pub fn from_name<T: Into<Cow<'static, str>>>(name: T) -> Self {
370 SpanBuilder {
371 name: name.into(),
372 ..Default::default()
373 }
374 }
375
376 /// Assign span kind
377 pub fn with_kind(self, span_kind: SpanKind) -> Self {
378 SpanBuilder {
379 span_kind: Some(span_kind),
380 ..self
381 }
382 }
383
384 /// Assign span start time
385 pub fn with_start_time<T: Into<SystemTime>>(self, start_time: T) -> Self {
386 SpanBuilder {
387 start_time: Some(start_time.into()),
388 ..self
389 }
390 }
391
392 /// Assign span attributes from an iterable.
393 /// Providing duplicate keys will result in multiple attributes
394 /// with the same key, as there is no de-duplication performed.
395 pub fn with_attributes<I>(self, attributes: I) -> Self
396 where
397 I: IntoIterator<Item = KeyValue>,
398 {
399 SpanBuilder {
400 attributes: Some(attributes.into_iter().collect()),
401 ..self
402 }
403 }
404
405 /// Assign events
406 pub fn with_events(self, events: Vec<Event>) -> Self {
407 SpanBuilder {
408 events: Some(events),
409 ..self
410 }
411 }
412
413 /// Assign links
414 pub fn with_links(self, mut links: Vec<Link>) -> Self {
415 links.retain(|l| l.span_context.is_valid());
416 SpanBuilder {
417 links: Some(links),
418 ..self
419 }
420 }
421
422 /// Builds a span with the given tracer from this configuration.
423 pub fn start<T: Tracer>(self, tracer: &T) -> T::Span {
424 Context::map_current(|cx| tracer.build_with_context(self, cx))
425 }
426
427 /// Builds a span with the given tracer from this configuration and parent.
428 pub fn start_with_context<T: Tracer>(self, tracer: &T, parent_cx: &Context) -> T::Span {
429 tracer.build_with_context(self, parent_cx)
430 }
431}