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}