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 #[allow(dead_code)]
190 fn span_can_be_shared() {
191 fn trait_check<T: Send + Sync>() {}
192 trait_check::<Span<()>>();
193 }
194
195 #[test]
196 fn routing_inherited_by_children() {
197 let routing = Arc::new(TestRouting {
198 zone_id: 7,
199 account_id: 99,
200 });
201 let expected_group_key = routing.group_key();
202 let expected_encoded = routing.encode();
203
204 let (tracer, mut span_rx) = Tracer::new(AllSampler);
205 {
206 let parent = tracer
208 .span("parent")
209 .routing(routing.clone())
210 .start_with_state(());
211 let child = parent.child("child", |s| s.start_with_state(()));
212 let grandchild = child.child("grandchild", |s| s.start_with_state(()));
213
214 drop(grandchild);
215 drop(child);
216 drop(parent);
217 }
218
219 for expected in ["grandchild", "child", "parent"] {
222 let span = span_rx.try_recv().unwrap();
223 assert_eq!(span.operation_name(), expected);
224
225 let r = span
226 .routing()
227 .unwrap_or_else(|| panic!("{expected} should inherit routing"));
228 assert_eq!(r.group_key(), expected_group_key);
229 assert_eq!(r.encode(), expected_encoded);
230 }
231 }
232
233 #[test]
234 fn routing_last_set_wins() {
235 let second = Arc::new(TestRouting {
236 zone_id: 2,
237 account_id: 2,
238 });
239 let expected_group_key = second.group_key();
240 let expected_encoded = second.encode();
241
242 let (tracer, mut span_rx) = Tracer::new(AllSampler);
243 {
244 let span = tracer
246 .span("span")
247 .routing(Arc::new(TestRouting {
248 zone_id: 1,
249 account_id: 1,
250 }))
251 .routing(second.clone())
252 .start_with_state(());
253 drop(span);
254 }
255
256 let span = span_rx.try_recv().unwrap();
257 let r = span.routing().expect("routing should be set");
258 assert_eq!(r.group_key(), expected_group_key);
259 assert_eq!(r.encode(), expected_encoded);
260 }
261}