rustracing/
lib.rs

1//! [OpenTracing][opentracing] API for Rust
2//!
3//! # Examples
4//!
5//! ```
6//! use rustracing::sampler::AllSampler;
7//! use rustracing::tag::Tag;
8//! use rustracing::Tracer;
9//! use std::thread;
10//! use std::time::Duration;
11//!
12//! // Creates a tracer
13//! let (span_tx, span_rx) = crossbeam_channel::bounded(10);
14//! let tracer = Tracer::with_sender(AllSampler, span_tx);
15//! {
16//!     // Starts "parent" span
17//!     let parent_span = tracer.span("parent").start_with_state(());
18//!     thread::sleep(Duration::from_millis(10));
19//!     {
20//!         // Starts "child" span
21//!         let mut child_span = tracer
22//!             .span("child_span")
23//!             .child_of(&parent_span)
24//!             .tag(Tag::new("key", "value"))
25//!             .start_with_state(());
26//!
27//!         child_span.log(|log| {
28//!             log.error().message("a log message");
29//!         });
30//!     } // The "child" span dropped and will be sent to `span_rx`
31//! } // The "parent" span dropped and will be sent to `span_rx`
32//!
33//! // Outputs finished spans to the standard output
34//! while let Ok(span) = span_rx.try_recv() {
35//!     println!("# SPAN: {:?}", span);
36//! }
37//! ```
38//!
39//! As an actual usage example of the crate and an implmentation of the [OpenTracing] API,
40//! it may be helpful to looking at [rustracing_jaeger] crate.
41//!
42//! # References
43//!
44//! - [The OpenTracing Semantic Specification (v1.1)][specification]
45//!
46//! [opentracing]: http://opentracing.io/
47//! [specification]: https://github.com/opentracing/specification/blob/master/specification.md
48//! [rustracing_jaeger]: https://github.com/sile/rustracing_jaeger
49#![warn(missing_docs)]
50#![allow(clippy::new_ret_no_self)]
51#[macro_use]
52extern crate trackable;
53
54pub use crate::error::{Error, ErrorKind};
55pub use crate::tracer::Tracer;
56
57pub mod carrier;
58pub mod convert;
59pub mod log;
60pub mod sampler;
61pub mod span;
62pub mod tag;
63
64mod error;
65mod tracer;
66
67/// This crate specific `Result` type.
68pub type Result<T> = std::result::Result<T, Error>;
69
70#[cfg(test)]
71mod tests {
72    use super::*;
73    use crate::sampler::AllSampler;
74    use crate::tag::{StdTag, Tag};
75    use std::thread;
76    use std::time::Duration;
77
78    #[test]
79    fn it_works() {
80        let (span_tx, span_rx) = crossbeam_channel::bounded(10);
81        let tracer = Tracer::with_sender(AllSampler, span_tx);
82        {
83            let span = tracer.span("it_works").start_with_state(());
84            let mut child = span.child("child", |options| options.start_with_state(()));
85            child.set_tags(|| StdTag::peer_addr("127.0.0.1:80".parse().unwrap()));
86        }
87
88        let span = span_rx.try_recv().unwrap();
89        assert_eq!(span.operation_name(), "child");
90
91        let span = span_rx.try_recv().unwrap();
92        assert_eq!(span.operation_name(), "it_works");
93    }
94
95    #[test]
96    fn example_code_works() {
97        // Creates a tracer
98        let (span_tx, span_rx) = crossbeam_channel::bounded(10);
99        let tracer = Tracer::with_sender(AllSampler, span_tx);
100        {
101            // Starts "parent" span
102            let parent_span = tracer.span("parent").start_with_state(());
103            thread::sleep(Duration::from_millis(10));
104            {
105                // Starts "child" span
106                let mut child_span = tracer
107                    .span("child_span")
108                    .child_of(&parent_span)
109                    .tag(Tag::new("key", "value"))
110                    .start_with_state(());
111
112                child_span.log(|log| {
113                    log.error().message("a log message");
114                });
115            } // The "child" span dropped and will be sent to `span_rx`
116        } // The "parent" span dropped and will be sent to `span_rx`
117
118        // Outputs finished spans to the standard output
119        let mut count = 0;
120        while let Ok(span) = span_rx.try_recv() {
121            println!("# SPAN: {:?}", span);
122            count += 1;
123        }
124        assert_eq!(count, 2);
125    }
126
127    #[test]
128    fn nonblocking_on_full_queue() {
129        let (span_tx, span_rx) = crossbeam_channel::bounded(2);
130        let tracer = Tracer::with_sender(AllSampler, span_tx);
131        {
132            let span = tracer.span("first").start_with_state(());
133            let mut child = span.child("second", |options| options.start_with_state(()));
134            child.set_tags(|| StdTag::peer_addr("127.0.0.1:80".parse().unwrap()));
135            let _ = tracer.span("third").start_with_state(());
136        } // All spans dropped but only two ones will be sent to `span_rx` due to capacity limit, others are lost
137
138        // If the code continues, there was no blocking operation while sending span to the channel
139        assert!(span_rx.is_full());
140        assert_eq!(span_rx.len(), 2);
141
142        let span = span_rx.try_recv().unwrap();
143        assert_eq!(span.operation_name(), "third");
144
145        let span = span_rx.try_recv().unwrap();
146        assert_eq!(span.operation_name(), "second");
147
148        assert!(span_rx.is_empty());
149    }
150}