opentelemetry/trace/
span.rs

1use crate::{trace::SpanContext, KeyValue};
2use std::borrow::Cow;
3use std::error::Error;
4use std::time::SystemTime;
5
6/// The interface for a single operation within a trace.
7///
8/// Spans can be nested to form a trace tree. Each trace contains a root span,
9/// which typically describes the entire operation and, optionally, one or more
10/// sub-spans for its sub-operations.
11///
12/// The span `name` concisely identifies the work represented by the span, for
13/// example, an RPC method name, a function name, or the name of a subtask or
14/// stage within a larger computation. The span name should be the most general
15/// string that identifies a (statistically) interesting class of spans, rather
16/// than individual span instances while still being human-readable. That is,
17/// `"get_user"` is a reasonable name, while `"get_user/314159"`, where `"314159"` is
18/// a user ID, is not a good name due to its high cardinality. _Generality_
19/// should be prioritized over _human-readability_.
20///
21/// For example, here are potential span names for an endpoint that gets a
22/// hypothetical account information:
23///
24/// | Span Name         | Guidance     |
25/// | ----------------- | ------------ |
26/// | `get`             | Too general  |
27/// | `get_account/42`  | Too specific |
28/// | `get_account`     | Good, and account_id=42 would make a nice Span attribute |
29/// | `get_account/{accountId}` | Also good (using the "HTTP route") |
30///
31/// The span's start and end timestamps reflect the elapsed real time of the
32/// operation.
33///
34/// For example, if a span represents a request-response cycle (e.g. HTTP or an
35/// RPC), the span should have a start time that corresponds to the start time
36/// of the first sub-operation, and an end time of when the final sub-operation
37/// is complete. This includes:
38///
39/// * receiving the data from the request
40/// * parsing of the data (e.g. from a binary or json format)
41/// * any middleware or additional processing logic
42/// * business logic
43/// * construction of the response
44/// * sending of the response
45///
46/// Child spans (or in some cases events) may be created to represent
47/// sub-operations which require more detailed observability. Child spans should
48/// measure the timing of the respective sub-operation, and may add additional
49/// attributes.
50pub trait Span {
51    /// Record an event in the context this span.
52    ///
53    /// Note that the OpenTelemetry project documents certain "[standard
54    /// attributes]" that have prescribed semantic meanings and are available via
55    /// the [opentelemetry_semantic_conventions] crate.
56    ///
57    /// [standard attributes]: https://github.com/open-telemetry/opentelemetry-specification/blob/v1.9.0/specification/trace/semantic_conventions/README.md
58    /// [opentelemetry_semantic_conventions]: https://docs.rs/opentelemetry-semantic-conventions
59    fn add_event<T>(&mut self, name: T, attributes: Vec<KeyValue>)
60    where
61        T: Into<Cow<'static, str>>,
62    {
63        self.add_event_with_timestamp(name, crate::time::now(), attributes)
64    }
65
66    /// Record an error as an event for this span.
67    ///
68    /// An additional call to [Span::set_status] is required if the status of the
69    /// span should be set to error, as this method does not change the span status.
70    ///
71    /// If this span is not being recorded then this method does nothing.
72    fn record_error(&mut self, err: &dyn Error) {
73        if self.is_recording() {
74            let attributes = vec![KeyValue::new("exception.message", err.to_string())];
75            self.add_event("exception", attributes);
76        }
77    }
78
79    /// Record an event with a timestamp in the context this span.
80    ///
81    /// Note that the OpenTelemetry project documents certain "[standard
82    /// attributes]" that have prescribed semantic meanings and are available via
83    /// the [opentelemetry_semantic_conventions] crate.
84    ///
85    /// [standard attributes]: https://github.com/open-telemetry/opentelemetry-specification/blob/v1.9.0/specification/trace/semantic_conventions/README.md
86    /// [opentelemetry_semantic_conventions]: https://docs.rs/opentelemetry-semantic-conventions
87    fn add_event_with_timestamp<T>(
88        &mut self,
89        name: T,
90        timestamp: SystemTime,
91        attributes: Vec<KeyValue>,
92    ) where
93        T: Into<Cow<'static, str>>;
94
95    /// A reference to the [`SpanContext`] for this span.
96    fn span_context(&self) -> &SpanContext;
97
98    /// Returns `true` if this span is recording information.
99    ///
100    /// Spans will not be recording information after they have ended.
101    ///
102    /// This flag may be `true` despite the entire trace being sampled out. This
103    /// allows recording and processing of information about the individual
104    /// spans without sending it to the backend. An example of this scenario may
105    /// be recording and processing of all incoming requests for the processing
106    /// and building of SLA/SLO latency charts while sending only a subset -
107    /// sampled spans - to the backend.
108    fn is_recording(&self) -> bool;
109
110    /// Set an attribute of this span.
111    ///
112    /// Setting an attribute with the same key as an existing attribute
113    /// results in both being stored as attribute, without any de-duplication
114    /// performed.
115    ///
116    /// Note that the OpenTelemetry project documents certain "[standard
117    /// attributes]" that have prescribed semantic meanings and are available via
118    /// the [opentelemetry_semantic_conventions] crate.
119    ///
120    /// [standard attributes]: https://github.com/open-telemetry/opentelemetry-specification/blob/v1.9.0/specification/trace/semantic_conventions/README.md
121    /// [opentelemetry_semantic_conventions]: https://docs.rs/opentelemetry-semantic-conventions
122    fn set_attribute(&mut self, attribute: KeyValue);
123
124    /// Set multiple attributes of this span.
125    ///
126    /// Setting an attribute with the same key as an existing attribute
127    /// results in both being stored as attribute, without any de-duplication
128    /// performed.
129    ///
130    /// Note that the OpenTelemetry project documents certain "[standard
131    /// attributes]" that have prescribed semantic meanings and are available via
132    /// the [opentelemetry_semantic_conventions] crate.
133    ///
134    /// [standard attributes]: https://github.com/open-telemetry/opentelemetry-specification/blob/v1.9.0/specification/trace/semantic_conventions/README.md
135    /// [opentelemetry_semantic_conventions]: https://docs.rs/opentelemetry-semantic-conventions
136    fn set_attributes(&mut self, attributes: impl IntoIterator<Item = KeyValue>) {
137        if self.is_recording() {
138            for attr in attributes.into_iter() {
139                self.set_attribute(attr);
140            }
141        }
142    }
143
144    /// Sets the status of this `Span`.
145    ///
146    /// If used, this will override the default span status, which is [`Status::Unset`].
147    fn set_status(&mut self, status: Status);
148
149    /// Updates the span's name.
150    ///
151    /// After this update, any sampling behavior based on the name will depend on
152    /// the implementation.
153    fn update_name<T>(&mut self, new_name: T)
154    where
155        T: Into<Cow<'static, str>>;
156
157    /// Adds [`Link`] to another [`SpanContext`].
158    ///
159    /// This method allows linking the current span to another span, identified by its `SpanContext`. Links can be used
160    /// to connect spans from different traces or within the same trace. Attributes can be attached to the link to
161    /// provide additional context or metadata.
162    ///
163    /// # Arguments
164    ///
165    /// * `span_context` - The `SpanContext` of the span to link to. This represents the target span's unique identifiers
166    ///   and trace information.
167    /// * `attributes` - A vector of `KeyValue` pairs that describe additional attributes of the link. These attributes
168    ///   can include any contextual information relevant to the link between the spans.
169    ///
170    /// [`Link`]: crate::trace::Link
171    fn add_link(&mut self, span_context: SpanContext, attributes: Vec<KeyValue>);
172
173    /// Signals that the operation described by this span has now ended.
174    fn end(&mut self) {
175        self.end_with_timestamp(crate::time::now());
176    }
177
178    /// Signals that the operation described by this span ended at the given time.
179    fn end_with_timestamp(&mut self, timestamp: SystemTime);
180}
181
182/// `SpanKind` describes the relationship between the [`Span`], its parents, and
183/// its children in a trace.
184///
185/// `SpanKind` describes two independent properties that benefit tracing systems
186/// during analysis:
187///
188/// The first property described by `SpanKind` reflects whether the span is a
189/// "logical" remote child or parent. By "logical", we mean that the span is
190/// logically a remote child or parent, from the point of view of the library
191/// that is being instrumented. Spans with a remote parent are interesting
192/// because they are sources of external load. Spans with a remote child are
193/// interesting because they reflect a non-local system dependency.
194///
195/// The second property described by `SpanKind` reflects whether a child span
196/// represents a synchronous call.  When a child span is synchronous, the parent
197/// is expected to wait for it to complete under ordinary circumstances. It can
198/// be useful for tracing systems to know this property, since synchronous spans
199/// may contribute to the overall trace latency. Asynchronous scenarios can be
200/// remote or local.
201///
202/// In order for `SpanKind` to be meaningful, callers should arrange that a
203/// single span does not serve more than one purpose. For example, a server-side
204/// span should not be used directly as the parent of another remote span. As a
205/// simple guideline, instrumentation should create a new span prior to
206/// extracting and serializing the SpanContext for a remote call.
207///
208/// Note: there are complex scenarios where a `SpanKind::Client` span may have a
209/// child that is also logically a `SpanKind::Client` span, or a
210/// `SpanKind::Producer` span might have a local child that is a
211/// `SpanKind::Client` span, depending on how the various libraries that are
212/// providing the functionality are built and instrumented. These scenarios,
213/// when they occur, should be detailed in the semantic conventions appropriate
214/// to the relevant libraries.
215///
216/// To summarize the interpretation of these kinds:
217///
218/// | `SpanKind` | Synchronous | Asynchronous | Remote Incoming | Remote Outgoing |
219/// |---|---|---|---|---|
220/// | `Client` | yes | | | yes |
221/// | `Server` | yes | | yes | |
222/// | `Producer` | | yes | | maybe |
223/// | `Consumer` | | yes | maybe | |
224/// | `Internal` | | | | |
225#[derive(Clone, Debug, PartialEq, Eq)]
226pub enum SpanKind {
227    /// Indicates that the span describes a request to some remote service. This
228    /// span is usually the parent of a remote `SpanKind::Server` span and does
229    /// not end until the response is received.
230    Client,
231
232    /// Indicates that the span covers server-side handling of a synchronous RPC
233    /// or other remote request. This span is often the child of a remote
234    /// `SpanKind::Client` span that was expected to wait for a response.
235    Server,
236
237    /// Indicates that the span describes the initiators of an asynchronous
238    /// request. This parent span will often end before the corresponding child
239    /// `SpanKind::Consumer` span, possibly even before the child span starts.
240    ///
241    /// In messaging scenarios with batching, tracing individual messages
242    /// requires a new `SpanKind::Producer` span per message to be created.
243    Producer,
244
245    /// Indicates that the span describes a child of an asynchronous
246    /// `SpanKind::Producer` request.
247    Consumer,
248
249    /// Default value.
250    ///
251    /// Indicates that the span represents an internal operation within an
252    /// application, as opposed to an operations with remote parents or
253    /// children.
254    Internal,
255}
256
257/// The status of a [`Span`].
258///
259/// These values form a total order: Ok > Error > Unset. This means that setting
260/// `Status::Ok` will override any prior or future attempts to set a status with
261/// `Status::Error` or `Status::Unset`.
262///
263/// The status should remain unset, except for the following circumstances:
264///
265/// Generally, instrumentation libraries should not set the code to
266/// `Status::Ok`, unless explicitly configured to do so. Instrumentation
267/// libraries should leave the status code as unset unless there is an error.
268///
269/// Application developers and operators may set the status code to
270/// `Status::Ok`.
271///
272/// When span status is set to `Status::Ok` it should be considered final and
273/// any further attempts to change it should be ignored.
274///
275/// Analysis tools should respond to a `Status::Ok` status by suppressing any
276/// errors they would otherwise generate. For example, to suppress noisy errors
277/// such as 404s.
278///
279/// Only the value of the last call will be recorded, and implementations are
280/// free to ignore previous calls.
281#[derive(Default, Debug, Clone, PartialEq, Eq, PartialOrd)]
282pub enum Status {
283    /// The default status.
284    #[default]
285    Unset,
286
287    /// The operation contains an error.
288    Error {
289        /// The description of the error
290        description: Cow<'static, str>,
291    },
292
293    /// The operation has been validated by an application developer or operator to
294    /// have completed successfully.
295    Ok,
296}
297
298impl Status {
299    /// Create a new error status with a given description.
300    ///
301    /// # Examples
302    ///
303    /// ```
304    /// use opentelemetry::trace::Status;
305    ///
306    /// // record error with `str` description
307    /// let error_status = Status::error("something went wrong");
308    ///
309    /// // or with `String` description
310    /// let error_status = Status::error(format!("too many foos: {}", 42));
311    /// # drop(error_status);
312    /// ```
313    pub fn error(description: impl Into<Cow<'static, str>>) -> Self {
314        Status::Error {
315            description: description.into(),
316        }
317    }
318}
319
320#[cfg(test)]
321mod tests {
322    use super::*;
323
324    #[test]
325    fn status_order() {
326        assert!(Status::Ok > Status::error(""));
327        assert!(Status::error("") > Status::Unset);
328    }
329}