zipkin_types/
span.rs

1//  Copyright 2017 Palantir Technologies, Inc.
2//
3//  Licensed under the Apache License, Version 2.0 (the "License");
4//  you may not use this file except in compliance with the License.
5//  You may obtain a copy of the License at
6//
7//      http://www.apache.org/licenses/LICENSE-2.0
8//
9//  Unless required by applicable law or agreed to in writing, software
10//  distributed under the License is distributed on an "AS IS" BASIS,
11//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//  See the License for the specific language governing permissions and
13//  limitations under the License.
14
15//! Spans.
16use crate::{Annotation, Endpoint, SpanId, TraceId};
17use std::collections::HashMap;
18use std::time::{Duration, SystemTime};
19
20/// The "kind" of a span.
21///
22/// This has an impact on the relationship between the span's timestamp, duration, and local
23/// endpoint.
24#[derive(Debug, Copy, Clone)]
25#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
26#[cfg_attr(feature = "serde", serde(rename_all = "SCREAMING_SNAKE_CASE"))]
27#[non_exhaustive]
28pub enum Kind {
29    /// The client side of an RPC.
30    ///
31    /// * Timestamp - The moment a request was sent (formerly "cs")
32    /// * Duration - When present, indicates when a response was received (formerly "cr")
33    /// * Remote Endpoint - Represents the server.
34    Client,
35
36    /// The server side of an RPC.
37    ///
38    /// * Timestamp - The moment a request was received (formerly "sr")
39    /// * Duration - When present, indicates when a response was received (formerly "ss")
40    /// * Remote Endpoint - Represents the client.
41    Server,
42
43    /// A message sent to a message broker.
44    ///
45    /// * Timestamp - The moment a message was sent to a destination (formerly "ms")
46    /// * Duration - When present, represents the delay sending the message, such as batching.
47    /// * Remote Endpoint - Represents the broker.
48    Producer,
49
50    /// A message received from a message broker.
51    ///
52    /// * Timestamp - The moment a message was received from an origin (formerly "mr")
53    /// * Duration - When present, represents the delay consuming the message, such as from a
54    ///     backlog.
55    /// * Remote Endpoint - Represents the broker.
56    Consumer,
57}
58
59/// A `Span` represents a single operation over some range of time.
60///
61/// Multiple spans make up a single "trace" of a distributed computation, and
62/// spans can be nested. A new trace is created with a "root" span, and
63/// subsections of that computation are recorded in individual spans.
64///
65/// For spans tracing a remote service call, two records will typically be
66/// generated, one from the client and the other from the server. The client is
67/// responsible for recording the timestamp and duration associated with the
68/// span, and the server span should omit that information. The client and
69/// server may both add their own annotations and binary annotations the span -
70/// they will be merged.
71#[derive(Debug, Clone)]
72#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
73#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
74pub struct Span {
75    trace_id: TraceId,
76    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
77    name: Option<String>,
78    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
79    parent_id: Option<SpanId>,
80    id: SpanId,
81    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
82    kind: Option<Kind>,
83    #[cfg_attr(
84        feature = "serde",
85        serde(
86            skip_serializing_if = "Option::is_none",
87            with = "crate::opt_time_micros"
88        )
89    )]
90    timestamp: Option<SystemTime>,
91    #[cfg_attr(
92        feature = "serde",
93        serde(
94            skip_serializing_if = "Option::is_none",
95            with = "crate::opt_duration_micros"
96        )
97    )]
98    duration: Option<Duration>,
99    #[cfg_attr(
100        feature = "serde",
101        serde(skip_serializing_if = "is_false", default = "value_false")
102    )]
103    debug: bool,
104    #[cfg_attr(
105        feature = "serde",
106        serde(skip_serializing_if = "is_false", default = "value_false")
107    )]
108    shared: bool,
109    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
110    local_endpoint: Option<Endpoint>,
111    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
112    remote_endpoint: Option<Endpoint>,
113    #[cfg_attr(
114        feature = "serde",
115        serde(skip_serializing_if = "Vec::is_empty", default)
116    )]
117    annotations: Vec<Annotation>,
118    #[cfg_attr(
119        feature = "serde",
120        serde(skip_serializing_if = "HashMap::is_empty", default)
121    )]
122    tags: HashMap<String, String>,
123}
124
125#[cfg(feature = "serde")]
126#[inline]
127fn is_false(v: &bool) -> bool {
128    !*v
129}
130
131#[cfg(feature = "serde")]
132#[inline]
133fn value_false() -> bool {
134    false
135}
136
137impl Span {
138    /// Returns a builder used to construct a `Span`.
139    #[inline]
140    pub fn builder() -> Builder {
141        Builder {
142            trace_id: None,
143            name: None,
144            parent_id: None,
145            id: None,
146            kind: None,
147            timestamp: None,
148            duration: None,
149            debug: false,
150            shared: false,
151            local_endpoint: None,
152            remote_endpoint: None,
153            annotations: vec![],
154            tags: HashMap::new(),
155        }
156    }
157
158    /// The randomly generated, unique identifier for a trace, set on all spans within it.
159    #[inline]
160    pub fn trace_id(&self) -> TraceId {
161        self.trace_id
162    }
163
164    /// The logical operation this span represents (e.g. an RPC method).
165    ///
166    /// Leave absent if unknown.
167    ///
168    /// These are lookup labels, so take care to ensure names are low cardinality. For example, do
169    /// not embed variables into the name.
170    #[inline]
171    pub fn name(&self) -> Option<&str> {
172        self.name.as_deref()
173    }
174
175    /// The parent span ID, or `None` if this is the root span in a trace.
176    #[inline]
177    pub fn parent_id(&self) -> Option<SpanId> {
178        self.parent_id
179    }
180
181    /// The unique 64 bit identifier for this operation within the trace.
182    #[inline]
183    pub fn id(&self) -> SpanId {
184        self.id
185    }
186
187    /// The "kind" of operation this span represents.
188    ///
189    /// When absent, the span is local or incomplete.
190    #[inline]
191    pub fn kind(&self) -> Option<Kind> {
192        self.kind
193    }
194
195    /// The start of the span.
196    #[inline]
197    pub fn timestamp(&self) -> Option<SystemTime> {
198        self.timestamp
199    }
200
201    /// The duration of the critical path, if known.
202    ///
203    /// Durations are recorded in microseconds, and rounded up to a minimum of 1. Durations of
204    /// children can be longer than their parents due to asynchronous operations.
205    #[inline]
206    pub fn duration(&self) -> Option<Duration> {
207        self.duration
208    }
209
210    /// Determines if this span is part of a normal or forcibly sampled span.
211    ///
212    /// If true, the span should always be sampled regardless of the sampling configuration.
213    #[inline]
214    pub fn debug(&self) -> bool {
215        self.debug
216    }
217
218    /// Determines if this span was started by another tracer (e.g. on a different host).
219    #[inline]
220    pub fn shared(&self) -> bool {
221        self.shared
222    }
223
224    /// Returns the host that recorded this span, primarily for query by service name.
225    ///
226    /// Instrumentation should always record this. The IP address is usually the site local or
227    /// advertised service address. When present, the port indicates the listen port.
228    #[inline]
229    pub fn local_endpoint(&self) -> Option<&Endpoint> {
230        self.local_endpoint.as_ref()
231    }
232
233    /// Returns the other side of the connection for RPC or messaging spans.
234    #[inline]
235    pub fn remote_endpoint(&self) -> Option<&Endpoint> {
236        self.remote_endpoint.as_ref()
237    }
238
239    /// Returns the annotations associated with this span.
240    #[inline]
241    pub fn annotations(&self) -> &[Annotation] {
242        &self.annotations
243    }
244
245    /// Returns tags used to give spans context for search, viewing, and analysis.
246    #[inline]
247    pub fn tags(&self) -> &HashMap<String, String> {
248        &self.tags
249    }
250}
251
252/// A builder for `Span`s.
253pub struct Builder {
254    trace_id: Option<TraceId>,
255    name: Option<String>,
256    parent_id: Option<SpanId>,
257    id: Option<SpanId>,
258    kind: Option<Kind>,
259    timestamp: Option<SystemTime>,
260    duration: Option<Duration>,
261    debug: bool,
262    shared: bool,
263    local_endpoint: Option<Endpoint>,
264    remote_endpoint: Option<Endpoint>,
265    annotations: Vec<Annotation>,
266    tags: HashMap<String, String>,
267}
268
269impl From<Span> for Builder {
270    #[inline]
271    fn from(s: Span) -> Builder {
272        Builder {
273            trace_id: Some(s.trace_id),
274            name: s.name,
275            parent_id: s.parent_id,
276            id: Some(s.id),
277            kind: s.kind,
278            timestamp: s.timestamp,
279            duration: s.duration,
280            debug: s.debug,
281            shared: s.shared,
282            local_endpoint: s.local_endpoint,
283            remote_endpoint: s.remote_endpoint,
284            annotations: s.annotations,
285            tags: s.tags,
286        }
287    }
288}
289
290impl Builder {
291    /// Sets the trace ID of the span.
292    #[inline]
293    pub fn trace_id(&mut self, trace_id: TraceId) -> &mut Builder {
294        self.trace_id = Some(trace_id);
295        self
296    }
297
298    /// Sets the name of the span.
299    ///
300    /// Defaults to `None`.
301    #[inline]
302    pub fn name(&mut self, name: &str) -> &mut Builder {
303        self.name = Some(name.to_lowercase());
304        self
305    }
306
307    /// Sets the ID of the span's parent.
308    ///
309    /// Defaults to `None`.
310    #[inline]
311    pub fn parent_id(&mut self, parent_id: SpanId) -> &mut Builder {
312        self.parent_id = Some(parent_id);
313        self
314    }
315
316    /// Sets the ID of the span.
317    #[inline]
318    pub fn id(&mut self, id: SpanId) -> &mut Builder {
319        self.id = Some(id);
320        self
321    }
322
323    /// Sets the kind of the span.
324    ///
325    /// Defaults to `None`.
326    #[inline]
327    pub fn kind(&mut self, kind: Kind) -> &mut Builder {
328        self.kind = Some(kind);
329        self
330    }
331
332    /// Sets the time of the beginning of the span.
333    ///
334    /// Defaults to `None`.
335    #[inline]
336    pub fn timestamp(&mut self, timestamp: SystemTime) -> &mut Builder {
337        self.timestamp = Some(timestamp);
338        self
339    }
340
341    /// Sets the duration of the span.
342    ///
343    /// Defaults to `None`.
344    #[inline]
345    pub fn duration(&mut self, duration: Duration) -> &mut Builder {
346        self.duration = Some(duration);
347        self
348    }
349
350    /// Sets the debug state of the span.
351    ///
352    /// Defaults to `false`.
353    #[inline]
354    pub fn debug(&mut self, debug: bool) -> &mut Builder {
355        self.debug = debug;
356        self
357    }
358
359    /// Sets the shared state of the span.
360    ///
361    /// Defaults to `false`.
362    #[inline]
363    pub fn shared(&mut self, shared: bool) -> &mut Builder {
364        self.shared = shared;
365        self
366    }
367
368    /// Sets the local endpoint of the span.
369    ///
370    /// Defaults to `None`.
371    #[inline]
372    pub fn local_endpoint(&mut self, local_endpoint: Endpoint) -> &mut Builder {
373        self.local_endpoint = Some(local_endpoint);
374        self
375    }
376
377    /// Sets the remote endpoint of the span.
378    ///
379    /// Defaults to `None`.
380    #[inline]
381    pub fn remote_endpoint(&mut self, remote_endpoint: Endpoint) -> &mut Builder {
382        self.remote_endpoint = Some(remote_endpoint);
383        self
384    }
385
386    /// Adds an annotation to the span.
387    #[inline]
388    pub fn annotation(&mut self, annotation: Annotation) -> &mut Builder {
389        self.annotations.push(annotation);
390        self
391    }
392
393    /// Adds multiple annotations to the span.
394    #[inline]
395    pub fn annotations<I>(&mut self, annotations: I) -> &mut Builder
396    where
397        I: IntoIterator<Item = Annotation>,
398    {
399        self.annotations.extend(annotations);
400        self
401    }
402
403    /// Adds a tag to the span.
404    #[inline]
405    pub fn tag(&mut self, key: &str, value: &str) -> &mut Builder {
406        self.tags.insert(key.to_string(), value.to_string());
407        self
408    }
409
410    /// As multiple tags to the span.
411    #[inline]
412    pub fn tags<I>(&mut self, tags: I) -> &mut Builder
413    where
414        I: IntoIterator<Item = (String, String)>,
415    {
416        self.tags.extend(tags);
417        self
418    }
419
420    /// Constructs a `Span`.
421    ///
422    /// # Panics
423    ///
424    /// Panics if `trace_id` or `id` was not set.
425    #[inline]
426    pub fn build(&self) -> Span {
427        Span {
428            trace_id: self.trace_id.expect("trace ID not set"),
429            name: self.name.clone(),
430            id: self.id.expect("span ID not set"),
431            kind: self.kind,
432            parent_id: self.parent_id,
433            timestamp: self.timestamp,
434            duration: self.duration,
435            debug: self.debug,
436            shared: self.shared,
437            local_endpoint: self.local_endpoint.clone(),
438            remote_endpoint: self.remote_endpoint.clone(),
439            annotations: self.annotations.clone(),
440            tags: self.tags.clone(),
441        }
442    }
443}