opentelemetry_spanprocessor_any/trace/tracer.rs
1use crate::{
2 sdk,
3 trace::{Event, Link, Span, SpanId, SpanKind, StatusCode, TraceContextExt, TraceId},
4 Context, KeyValue,
5};
6use std::borrow::Cow;
7use std::time::SystemTime;
8
9/// Interface for constructing `Span`s.
10///
11/// The OpenTelemetry library achieves in-process context propagation of `Span`s
12/// by way of the `Tracer`.
13///
14/// The `Tracer` is responsible for tracking the currently active `Span`, and
15/// exposes methods for creating and activating new `Spans`. The `Tracer` is
16/// configured with `Propagators` which support transferring span context across
17/// process boundaries.
18///
19/// `Tracer`s are generally expected to be used as singletons. Implementations
20/// SHOULD provide a single global default Tracer.
21///
22/// Some applications may require multiple `Tracer` instances, e.g. to create
23/// `Span`s on behalf of other applications. Implementations MAY provide a
24/// global registry of Tracers for such applications.
25///
26/// The `Tracer` SHOULD allow end users to configure other tracing components
27/// that control how `Span`s are passed across process boundaries, including the
28/// binary and text format `Propagator`s used to serialize `Span`s created by
29/// the `Tracer`.
30///
31/// ## In Synchronous Code
32///
33/// Spans can be created and nested manually:
34///
35/// ```
36/// use opentelemetry::{global, trace::{Span, Tracer, TraceContextExt}, Context};
37///
38/// let tracer = global::tracer("my-component");
39///
40/// let parent = tracer.start("foo");
41/// let parent_cx = Context::current_with_span(parent);
42/// let mut child = tracer.span_builder("bar").start_with_context(&tracer, &parent_cx);
43///
44/// // ...
45///
46/// child.end();
47/// drop(parent_cx) // end parent
48/// ```
49///
50/// Spans can also use the current thread's [`Context`] to track which span is active:
51///
52/// ```
53/// use opentelemetry::{global, trace::{SpanKind, Tracer}};
54///
55/// let tracer = global::tracer("my-component");
56///
57/// // Create simple spans with `in_span`
58/// tracer.in_span("foo", |_foo_cx| {
59/// // parent span is active
60/// tracer.in_span("bar", |_bar_cx| {
61/// // child span is now the active span and associated with the parent span
62/// });
63/// // child has ended, parent now the active span again
64/// });
65/// // parent has ended, no active spans
66///
67/// // -- OR --
68///
69/// // create complex spans with span builder and `with_span`
70/// let parent_span = tracer.span_builder("foo").with_kind(SpanKind::Server).start(&tracer);
71/// tracer.with_span(parent_span, |_foo_cx| {
72/// // parent span is active
73/// let child_span = tracer.span_builder("bar").with_kind(SpanKind::Client).start(&tracer);
74/// tracer.with_span(child_span, |_bar_cx| {
75/// // child span is now the active span and associated with the parent span
76/// });
77/// // child has ended, parent now the active span again
78/// });
79/// // parent has ended, no active spans
80/// ```
81///
82/// Spans can also be marked as active, and the resulting guard allows for
83/// greater control over when the span is no longer considered active.
84///
85/// ```
86/// use opentelemetry::{global, trace::{Span, Tracer, mark_span_as_active}};
87/// let tracer = global::tracer("my-component");
88///
89/// let parent_span = tracer.start("foo");
90/// let parent_active = mark_span_as_active(parent_span);
91///
92/// {
93/// let child = tracer.start("bar");
94/// let _child_active = mark_span_as_active(child);
95///
96/// // do work in the context of the child span...
97///
98/// // exiting the scope drops the guard, child is no longer active
99/// }
100/// // Parent is active span again
101///
102/// // Parent can be dropped manually, or allowed to go out of scope as well.
103/// drop(parent_active);
104///
105/// // no active span
106/// ```
107///
108/// ## In Asynchronous Code
109///
110/// If you are instrumenting code that make use of [`std::future::Future`] or
111/// async/await, be sure to use the [`FutureExt`] trait. This is needed because
112/// the following example _will not_ work:
113///
114/// ```no_run
115/// # use opentelemetry::{global, trace::{Tracer, mark_span_as_active}};
116/// # let tracer = global::tracer("foo");
117/// # let span = tracer.start("foo-span");
118/// async {
119/// // Does not work
120/// let _g = mark_span_as_active(span);
121/// // ...
122/// };
123/// ```
124///
125/// The context guard `_g` will not exit until the future generated by the
126/// `async` block is complete. Since futures can be entered and exited
127/// _multiple_ times without them completing, the span remains active for as
128/// long as the future exists, rather than only when it is polled, leading to
129/// very confusing and incorrect output.
130///
131/// In order to trace asynchronous code, the [`Future::with_context`] combinator
132/// can be used:
133///
134/// ```
135/// # async fn run() -> Result<(), ()> {
136/// use opentelemetry::{trace::FutureExt, Context};
137/// let cx = Context::current();
138///
139/// let my_future = async {
140/// // ...
141/// };
142///
143/// my_future
144/// .with_context(cx)
145/// .await;
146/// # Ok(())
147/// # }
148/// ```
149///
150/// [`Future::with_context`] attaches a context to the future, ensuring that the
151/// context's lifetime is as long as the future's.
152///
153/// [`FutureExt`]: crate::trace::FutureExt
154/// [`Future::with_context`]: crate::trace::FutureExt::with_context()
155/// [`Context`]: crate::Context
156pub trait Tracer {
157 /// The `Span` type used by this `Tracer`.
158 type Span: Span;
159
160 /// Starts a new `Span`.
161 ///
162 /// By default the currently active `Span` is set as the new `Span`'s
163 /// parent. The `Tracer` MAY provide other default options for newly
164 /// created `Span`s.
165 ///
166 /// `Span` creation MUST NOT set the newly created `Span` as the currently
167 /// active `Span` by default, but this functionality MAY be offered additionally
168 /// as a separate operation.
169 ///
170 /// Each span has zero or one parent spans and zero or more child spans, which
171 /// represent causally related operations. A tree of related spans comprises a
172 /// trace. A span is said to be a _root span_ if it does not have a parent. Each
173 /// trace includes a single root span, which is the shared ancestor of all other
174 /// spans in the trace. Implementations MUST provide an option to create a `Span` as
175 /// a root span, and MUST generate a new `TraceId` for each root span created.
176 /// For a Span with a parent, the `TraceId` MUST be the same as the parent.
177 /// Also, the child span MUST inherit all `TraceState` values of its parent by default.
178 ///
179 /// A `Span` is said to have a _remote parent_ if it is the child of a `Span`
180 /// created in another process. Each propagators' deserialization must set
181 /// `is_remote` to true on a parent `SpanContext` so `Span` creation knows if the
182 /// parent is remote.
183 fn start<T>(&self, name: T) -> Self::Span
184 where
185 T: Into<Cow<'static, str>>,
186 {
187 self.start_with_context(name, &Context::current())
188 }
189
190 /// Starts a new `Span` with a given context
191 ///
192 /// By default the currently active `Span` is set as the new `Span`'s
193 /// parent. The `Tracer` MAY provide other default options for newly
194 /// created `Span`s.
195 ///
196 /// `Span` creation MUST NOT set the newly created `Span` as the currently
197 /// active `Span` by default, but this functionality MAY be offered additionally
198 /// as a separate operation.
199 ///
200 /// Each span has zero or one parent spans and zero or more child spans, which
201 /// represent causally related operations. A tree of related spans comprises a
202 /// trace. A span is said to be a _root span_ if it does not have a parent. Each
203 /// trace includes a single root span, which is the shared ancestor of all other
204 /// spans in the trace. Implementations MUST provide an option to create a `Span` as
205 /// a root span, and MUST generate a new `TraceId` for each root span created.
206 /// For a Span with a parent, the `TraceId` MUST be the same as the parent.
207 /// Also, the child span MUST inherit all `TraceState` values of its parent by default.
208 ///
209 /// A `Span` is said to have a _remote parent_ if it is the child of a `Span`
210 /// created in another process. Each propagators' deserialization must set
211 /// `is_remote` to true on a parent `SpanContext` so `Span` creation knows if the
212 /// parent is remote.
213 fn start_with_context<T>(&self, name: T, parent_cx: &Context) -> Self::Span
214 where
215 T: Into<Cow<'static, str>>;
216
217 /// Creates a span builder
218 ///
219 /// An ergonomic way for attributes to be configured before the `Span` is started.
220 fn span_builder<T>(&self, name: T) -> SpanBuilder
221 where
222 T: Into<Cow<'static, str>>;
223
224 /// Create a span from a [SpanBuilder]
225 fn build(&self, builder: SpanBuilder) -> Self::Span {
226 self.build_with_context(builder, &Context::current())
227 }
228
229 /// Create a span from a [SpanBuilder] with a parent context.
230 fn build_with_context(&self, builder: SpanBuilder, parent_cx: &Context) -> Self::Span;
231
232 /// Start a new span and execute the given closure with reference to the span's
233 /// context.
234 ///
235 /// This method starts a new span and sets it as the active span for the given
236 /// function. It then executes the body. It closes the span before returning the
237 /// execution result.
238 ///
239 /// # Examples
240 ///
241 /// ```
242 /// use opentelemetry::{global, trace::{Span, Tracer, get_active_span}, KeyValue};
243 ///
244 /// fn my_function() {
245 /// // start an active span in one function
246 /// global::tracer("my-component").in_span("span-name", |_cx| {
247 /// // anything happening in functions we call can still access the active span...
248 /// my_other_function();
249 /// })
250 /// }
251 ///
252 /// fn my_other_function() {
253 /// // call methods on the current span from
254 /// get_active_span(|span| {
255 /// span.add_event("An event!".to_string(), vec![KeyValue::new("happened", true)]);
256 /// })
257 /// }
258 /// ```
259 fn in_span<T, F>(&self, name: &'static str, f: F) -> T
260 where
261 F: FnOnce(Context) -> T,
262 Self::Span: Send + Sync + 'static,
263 {
264 let span = self.start(name);
265 let cx = Context::current_with_span(span);
266 let _guard = cx.clone().attach();
267 f(cx)
268 }
269
270 /// Start a new span and execute the given closure with reference to the span's
271 /// context.
272 ///
273 /// This method starts a new span and sets it as the active span for the given
274 /// function. It then executes the body. It closes the span before returning the
275 /// execution result.
276 ///
277 /// # Examples
278 ///
279 /// ```
280 /// use opentelemetry::{global, trace::{Span, SpanKind, Tracer, get_active_span}, KeyValue};
281 ///
282 /// fn my_function() {
283 /// let tracer = global::tracer("my-component");
284 /// // start a span with custom attributes via span builder
285 /// let span = tracer.span_builder("span-name").with_kind(SpanKind::Server).start(&tracer);
286 /// // Mark the span as active for the duration of the closure
287 /// global::tracer("my-component").with_span(span, |_cx| {
288 /// // anything happening in functions we call can still access the active span...
289 /// my_other_function();
290 /// })
291 /// }
292 ///
293 /// fn my_other_function() {
294 /// // call methods on the current span from
295 /// get_active_span(|span| {
296 /// span.add_event("An event!".to_string(), vec![KeyValue::new("happened", true)]);
297 /// })
298 /// }
299 /// ```
300 fn with_span<T, F>(&self, span: Self::Span, f: F) -> T
301 where
302 F: FnOnce(Context) -> T,
303 Self::Span: Send + Sync + 'static,
304 {
305 let cx = Context::current_with_span(span);
306 let _guard = cx.clone().attach();
307 f(cx)
308 }
309}
310
311/// `SpanBuilder` allows span attributes to be configured before the span
312/// has started.
313///
314/// ```
315/// use opentelemetry::{
316/// global,
317/// trace::{TracerProvider, SpanBuilder, SpanKind, Tracer},
318/// };
319///
320/// let tracer = global::tracer("example-tracer");
321///
322/// // The builder can be used to create a span directly with the tracer
323/// let _span = tracer.build(SpanBuilder {
324/// name: "example-span-name".into(),
325/// span_kind: Some(SpanKind::Server),
326/// ..Default::default()
327/// });
328///
329/// // Or used with builder pattern
330/// let _span = tracer
331/// .span_builder("example-span-name")
332/// .with_kind(SpanKind::Server)
333/// .start(&tracer);
334/// ```
335#[derive(Clone, Debug, Default)]
336pub struct SpanBuilder {
337 /// Trace id, useful for integrations with external tracing systems.
338 pub trace_id: Option<TraceId>,
339 /// Span id, useful for integrations with external tracing systems.
340 pub span_id: Option<SpanId>,
341 /// Span kind
342 pub span_kind: Option<SpanKind>,
343 /// Span name
344 pub name: Cow<'static, str>,
345 /// Span start time
346 pub start_time: Option<SystemTime>,
347 /// Span end time
348 pub end_time: Option<SystemTime>,
349 /// Span attributes
350 pub attributes: Option<Vec<KeyValue>>,
351 /// Span events
352 pub events: Option<Vec<Event>>,
353 /// Span Links
354 pub links: Option<Vec<Link>>,
355 /// Span status code
356 pub status_code: Option<StatusCode>,
357 /// Span status message
358 pub status_message: Option<Cow<'static, str>>,
359 /// Sampling result
360 pub sampling_result: Option<sdk::trace::SamplingResult>,
361}
362
363/// SpanBuilder methods
364impl SpanBuilder {
365 /// Create a new span builder from a span name
366 pub fn from_name<T: Into<Cow<'static, str>>>(name: T) -> Self {
367 SpanBuilder {
368 name: name.into(),
369 ..Default::default()
370 }
371 }
372
373 /// Specify trace id to use if no parent context exists
374 pub fn with_trace_id(self, trace_id: TraceId) -> Self {
375 SpanBuilder {
376 trace_id: Some(trace_id),
377 ..self
378 }
379 }
380
381 /// Assign span id
382 pub fn with_span_id(self, span_id: SpanId) -> Self {
383 SpanBuilder {
384 span_id: Some(span_id),
385 ..self
386 }
387 }
388
389 /// Assign span kind
390 pub fn with_kind(self, span_kind: SpanKind) -> Self {
391 SpanBuilder {
392 span_kind: Some(span_kind),
393 ..self
394 }
395 }
396
397 /// Assign span start time
398 pub fn with_start_time<T: Into<SystemTime>>(self, start_time: T) -> Self {
399 SpanBuilder {
400 start_time: Some(start_time.into()),
401 ..self
402 }
403 }
404
405 /// Assign span end time
406 pub fn with_end_time<T: Into<SystemTime>>(self, end_time: T) -> Self {
407 SpanBuilder {
408 end_time: Some(end_time.into()),
409 ..self
410 }
411 }
412
413 /// Assign span attributes
414 pub fn with_attributes(self, attributes: Vec<KeyValue>) -> Self {
415 SpanBuilder {
416 attributes: Some(attributes),
417 ..self
418 }
419 }
420
421 /// Assign events
422 pub fn with_events(self, events: Vec<Event>) -> Self {
423 SpanBuilder {
424 events: Some(events),
425 ..self
426 }
427 }
428
429 /// Assign links
430 pub fn with_links(self, mut links: Vec<Link>) -> Self {
431 links.retain(|l| l.span_context().is_valid());
432 SpanBuilder {
433 links: Some(links),
434 ..self
435 }
436 }
437
438 /// Assign status code
439 pub fn with_status_code(self, code: StatusCode) -> Self {
440 SpanBuilder {
441 status_code: Some(code),
442 ..self
443 }
444 }
445
446 /// Assign status message
447 pub fn with_status_message<T: Into<Cow<'static, str>>>(self, message: T) -> Self {
448 SpanBuilder {
449 status_message: Some(message.into()),
450 ..self
451 }
452 }
453
454 /// Assign sampling result
455 pub fn with_sampling_result(self, sampling_result: sdk::trace::SamplingResult) -> Self {
456 SpanBuilder {
457 sampling_result: Some(sampling_result),
458 ..self
459 }
460 }
461
462 /// Builds a span with the given tracer from this configuration.
463 pub fn start<T: Tracer>(self, tracer: &T) -> T::Span {
464 tracer.build_with_context(self, &Context::current())
465 }
466
467 /// Builds a span with the given tracer from this configuration and parent.
468 pub fn start_with_context<T: Tracer>(self, tracer: &T, parent_cx: &Context) -> T::Span {
469 tracer.build_with_context(self, parent_cx)
470 }
471}