1#![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
67pub 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::span::{FinishedSpan, RoutingMetadata, Span};
75 use crate::tag::{StdTag, Tag, TagValue};
76 use std::sync::atomic::{AtomicI64, Ordering};
77 use std::sync::Arc;
78 use std::thread;
79 use std::time::Duration;
80
81 #[derive(Debug)]
82 struct TestRouting {
83 zone_id: u64,
84 account_id: u64,
85 }
86
87 impl RoutingMetadata for TestRouting {
88 fn group_key(&self) -> String {
89 format!("{}|{}", self.zone_id, self.account_id)
90 }
91
92 fn encode(&self) -> String {
93 format!("zone={};account={}", self.zone_id, self.account_id)
94 }
95 }
96
97 #[tokio::test]
98 async fn it_works() {
99 let (tracer, mut span_rx) = Tracer::new(AllSampler);
100 {
101 let span = tracer.span("it_works").start_with_state(());
102 let mut child = span.child("child", |options| options.start_with_state(()));
103 child.set_tags(|| StdTag::peer_addr("127.0.0.1:80".parse().unwrap()));
104 }
105
106 let span = span_rx.recv().await.unwrap();
107 assert_eq!(span.operation_name(), "child");
108
109 let span = span_rx.recv().await.unwrap();
110 assert_eq!(span.operation_name(), "it_works");
111 }
112
113 #[tokio::test]
114 async fn example_code_works() {
115 let (tracer, mut span_rx) = Tracer::new(AllSampler);
117 {
118 let parent_span = tracer.span("parent").start_with_state(());
120 thread::sleep(Duration::from_millis(10));
121 {
122 let mut child_span = tracer
124 .span("child_span")
125 .child_of(&parent_span)
126 .tag(Tag::new("key", "value"))
127 .start_with_state(());
128
129 child_span.log(|log| {
130 log.error().message("a log message");
131 });
132 } } let span = span_rx.recv().await.unwrap();
136 assert_eq!(span.operation_name(), "child_span");
137
138 let span = span_rx.recv().await.unwrap();
139 assert_eq!(span.operation_name(), "parent");
140 }
141
142 #[test]
143 fn finish_callback() {
144 let span_counter = AtomicI64::new(1);
145 let finish_cb = move |span: &mut Span<()>| {
146 let call_num = span_counter.fetch_add(1, Ordering::Relaxed);
147 span.set_tag(|| Tag::new("callback-call", call_num));
148 };
149
150 let (tracer, mut span_rx) = Tracer::new(AllSampler);
151 {
152 let parent_span = tracer
153 .span("parent")
154 .finish_callback(finish_cb)
155 .start_with_state(());
156
157 let child_with_cb = parent_span.child("child_with_cb", |s| s.start_with_state(()));
158 let mut child_no_cb = parent_span.child("child_no_cb", |s| s.start_with_state(()));
159 child_no_cb.take_finish_callback();
160
161 drop(child_with_cb);
162 drop(child_no_cb);
163 drop(parent_span);
164 }
165
166 let find_span_counter = |s: &FinishedSpan<()>| match s
167 .tags()
168 .iter()
169 .find(|t| t.name() == "callback-call")?
170 .value()
171 {
172 TagValue::Integer(v) => Some(*v),
173 v => panic!("invalid `callback-call` tag value: {v:?}"),
174 };
175
176 let child_with_cb = span_rx.try_recv().unwrap();
177 assert_eq!(child_with_cb.operation_name(), "child_with_cb");
178 assert_eq!(find_span_counter(&child_with_cb), Some(1));
179
180 let child_no_cb = span_rx.try_recv().unwrap();
181 assert_eq!(child_no_cb.operation_name(), "child_no_cb");
182 assert_eq!(find_span_counter(&child_no_cb), None);
183
184 let parent_span = span_rx.try_recv().unwrap();
185 assert_eq!(parent_span.operation_name(), "parent");
186 assert_eq!(find_span_counter(&parent_span), Some(2));
187 }
188
189 #[test]
190 fn discarded_span_is_not_received() {
191 let (tracer, mut span_rx) = Tracer::new(AllSampler);
192 {
193 let parent = tracer.span("parent").start_with_state(());
194 let mut discarded = parent.child("discarded", |s| s.start_with_state(()));
195 let sibling = parent.child("sibling", |s| s.start_with_state(()));
196
197 discarded.discard();
198 discarded.set_tag(|| Tag::new("key", "value"));
199 discarded.log(|log| {
200 log.std().message("ignored");
201 });
202 assert!(!discarded.is_sampled());
203 assert!(discarded.context().is_none());
204
205 drop(discarded);
206 drop(sibling);
207 drop(parent);
208 }
209
210 assert_eq!(span_rx.try_recv().unwrap().operation_name(), "sibling");
211 assert_eq!(span_rx.try_recv().unwrap().operation_name(), "parent");
212 assert!(span_rx.try_recv().is_err());
213 }
214
215 #[test]
216 fn discarded_span_does_not_run_finish_callback() {
217 let calls = Arc::new(AtomicI64::new(0));
218 let (tracer, mut span_rx) = Tracer::new(AllSampler);
219 {
220 let calls = Arc::clone(&calls);
221 let mut span = tracer
222 .span("span")
223 .finish_callback(move |_: &mut Span<()>| {
224 calls.fetch_add(1, Ordering::Relaxed);
225 })
226 .start_with_state(());
227
228 span.discard();
229 span.discard();
230 }
231
232 assert_eq!(calls.load(Ordering::Relaxed), 0);
233 assert!(span_rx.try_recv().is_err());
234 }
235
236 #[allow(dead_code)]
237 fn span_can_be_shared() {
238 fn trait_check<T: Send + Sync>() {}
239 trait_check::<Span<()>>();
240 }
241
242 #[test]
243 fn routing_inherited_by_children() {
244 let routing = Arc::new(TestRouting {
245 zone_id: 7,
246 account_id: 99,
247 });
248 let expected_group_key = routing.group_key();
249 let expected_encoded = routing.encode();
250
251 let (tracer, mut span_rx) = Tracer::new(AllSampler);
252 {
253 let parent = tracer
255 .span("parent")
256 .routing(routing.clone())
257 .start_with_state(());
258 let child = parent.child("child", |s| s.start_with_state(()));
259 let grandchild = child.child("grandchild", |s| s.start_with_state(()));
260
261 drop(grandchild);
262 drop(child);
263 drop(parent);
264 }
265
266 for expected in ["grandchild", "child", "parent"] {
269 let span = span_rx.try_recv().unwrap();
270 assert_eq!(span.operation_name(), expected);
271
272 let r = span
273 .routing()
274 .unwrap_or_else(|| panic!("{expected} should inherit routing"));
275 assert_eq!(r.group_key(), expected_group_key);
276 assert_eq!(r.encode(), expected_encoded);
277 }
278 }
279
280 #[test]
281 fn routing_last_set_wins() {
282 let second = Arc::new(TestRouting {
283 zone_id: 2,
284 account_id: 2,
285 });
286 let expected_group_key = second.group_key();
287 let expected_encoded = second.encode();
288
289 let (tracer, mut span_rx) = Tracer::new(AllSampler);
290 {
291 let span = tracer
293 .span("span")
294 .routing(Arc::new(TestRouting {
295 zone_id: 1,
296 account_id: 1,
297 }))
298 .routing(second.clone())
299 .start_with_state(());
300 drop(span);
301 }
302
303 let span = span_rx.try_recv().unwrap();
304 let r = span.routing().expect("routing should be set");
305 assert_eq!(r.group_key(), expected_group_key);
306 assert_eq!(r.encode(), expected_encoded);
307 }
308}