1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
// Copyright 2020 TiKV Project Authors. Licensed under Apache-2.0.

//! `minitrace` is a high-performance, ergonomic, library-level timeline tracing library for Rust.
//!
//! Unlike most tracing libraries which are primarily designed for instrumenting executables,
//! `minitrace` also accommodates the need for library instrumentation. It stands out due to
//! its extreme lightweight and fast performance compared to other tracing libraries. Moreover,
//! it has zero overhead when not enabled in the executable, making it a worry-free choice for
//! libraries concerned about unnecessary performance loss.
//!
//! # Getting Started
//!
//! ## Libraries
//!
//! Libraries should include `minitrace` as a dependency without enabling any extra features.
//!
//! ```toml
//! [dependencies]
//! minitrace = "0.6"
//! ```
//!
//! Libraries can attach their spans to the caller's span (if caller has set [local parent](#local-span))
//! via the API boundary.
//!
//! ```
//! use minitrace::prelude::*;
//! # struct QueryResult;
//! # struct Error;
//!
//! struct Connection {
//!     // ...
//! }
//!
//! impl Connection {
//!     #[trace]
//!     pub fn query(sql: &str) -> Result<QueryResult, Error> {
//!         // ...
//!         # Ok(QueryResult)
//!     }
//! }
//! ```
//!
//! Libraries can also create a new trace individually to record their work.
//!
//! ```
//! use minitrace::prelude::*;
//! # struct HttpRequest;
//! # struct Error;
//!
//! pub fn send_request(req: HttpRequest) -> Result<(), Error> {
//!     let root = Span::root("send_request", SpanContext::random());
//!     let _guard = root.set_local_parent();
//!
//!     // ...
//!     # Ok(())
//! }
//! ```
//!
//! ## Executables
//!
//! Executables should include `minitrace` as a dependency with the `enable` feature
//! set. To disable `minitrace` statically, simply don't set the `enable` feature.
//!
//! ```toml
//! [dependencies]
//! minitrace = { version = "0.6", features = ["enable"] }
//! ```
//!
//! Executables should initialize a reporter implementation early in the program's runtime.
//! Span records generated before the implementation is initialized will be ignored. Before
//! terminating, the reporter should be flushed to ensure all span records are reported.
//!
//! ```
//! use minitrace::collector::Config;
//! use minitrace::collector::ConsoleReporter;
//!
//! fn main() {
//!     minitrace::set_reporter(ConsoleReporter, Config::default());
//!
//!     // ...
//!
//!     minitrace::flush();
//! }
//! ```
//!
//! # Key Concepts
//!
//! `minitrace` operates through three types: [`Span`], [`LocalSpan`], and [`Event`], each
//! representing a different type of tracing record. The macro [`trace`] is available to
//! manage these types automatically. For [`Future`] instrumentation, necessary utilities
//! are provided by [`FutureExt`].
//!
//! ## Span
//!
//! A [`Span`] represents an individual unit of work. It contains:
//! - A name
//! - A start timestamp and duration
//! - A set of key-value properties
//! - A reference to a parent `Span`
//!
//! A new `Span` can be started through [`Span::root()`], requiring the trace id and the
//! parent span id from a remote source. If there's no remote parent span, the parent span
//! id is typically set to its default value of zero.
//!
//! Once we have the root `Span`, we can create a child `Span` using [`Span::enter_with_parent()`],
//! thereby establishing the reference relationship between the spans.
//!
//! `Span` is thread-safe and can be sent across threads.
//! ```
//! use minitrace::collector::Config;
//! use minitrace::collector::ConsoleReporter;
//! use minitrace::prelude::*;
//!
//! minitrace::set_reporter(ConsoleReporter, Config::default());
//!
//! {
//!     let root_span = Span::root("root", SpanContext::random());
//!
//!     {
//!         let child_span = Span::enter_with_parent("a child span", &root_span);
//!
//!         // ...
//!
//!         // child_span ends here.
//!     }
//!
//!     // root_span ends here.
//! }
//!
//! minitrace::flush();
//! ```
//!
//! Sometimes, passing a `Span` through a function to create a child `Span` can be inconvenient.
//! We can employ a thread-local approach to avoid an explicit argument passing in the function.
//! In minitrace, [`Span::set_local_parent()`] and [`Span::enter_with_local_parent()`] serve this purpose.
//!
//! [`Span::set_local_parent()`] method sets __a local context of the `Span`__ for the current thread.
//! [`Span::enter_with_local_parent()`] accesses the parent `Span` from the local context and creates
//! a child `Span` with it.
//!
//! ```
//! use minitrace::prelude::*;
//!
//! {
//!     let root_span = Span::root("root", SpanContext::random());
//!     let _guard = root_span.set_local_parent();
//!
//!     foo();
//!
//!     // root_span ends here.
//! }
//!
//! fn foo() {
//!     // The parent of this span is `root`.
//!     let _child_span = Span::enter_with_local_parent("a child span");
//!
//!     // ...
//!
//!     // _child_span ends here.
//! }
//! ```
//!
//! ## Local Span
//!
//! In a clear single-thread execution flow, where we can ensure that the `Span` does
//! not cross threads, meaning:
//! - The `Span` is not sent to or shared by other threads
//! - In asynchronous code, the lifetime of the `Span` doesn't cross an `.await` point
//!
//! we can use `LocalSpan` as a substitute for `Span` to effectively reduce overhead
//! and greatly enhance performance.
//!
//! However, there is a precondition: The creation of `LocalSpan` must take place
//! within __a local context of a `Span`__, which is established by invoking the
//! [`Span::set_local_parent()`] method.
//!
//! If the code spans multiple function calls, this isn't always straightforward to
//! confirm if the precondition is met. As such, it's recommended to invoke
//! [`Span::set_local_parent()`] immediately after the creation of `Span`.
//!
//! After __a local context of a `Span`__ is set using [`Span::set_local_parent()`],
//! use [`LocalSpan::enter_with_local_parent()`] to start a `LocalSpan`, which then
//! becomes the new local parent.
//!
//! If no local context is set, the [`LocalSpan::enter_with_local_parent()`] will do nothing.
//! ```
//! use minitrace::collector::Config;
//! use minitrace::collector::ConsoleReporter;
//! use minitrace::prelude::*;
//!
//! minitrace::set_reporter(ConsoleReporter, Config::default());
//!
//! {
//!     let root = Span::root("root", SpanContext::random());
//!     let _guard = root.set_local_parent();
//!
//!     {
//!         // The parent of this span is `root`.
//!         let _span1 = LocalSpan::enter_with_local_parent("a child span");
//!
//!         foo();
//!     }
//! }
//!
//! fn foo() {
//!     // The parent of this span is `span1`.
//!     let _span2 = LocalSpan::enter_with_local_parent("a child span of child span");
//! }
//!
//! minitrace::flush();
//! ```
//!
//! ## Event
//!
//! [`Event`] represents a single point in time where something occurred during the execution of a program.
//!
//! An `Event` can be seen as a log record attached to a span.
//! ```
//! use minitrace::collector::Config;
//! use minitrace::collector::ConsoleReporter;
//! use minitrace::prelude::*;
//!
//! minitrace::set_reporter(ConsoleReporter, Config::default());
//!
//! {
//!     let root = Span::root("root", SpanContext::random());
//!     let _guard = root.set_local_parent();
//!
//!     Event::add_to_parent("event in root", &root, || []);
//!     {
//!         let _span1 = LocalSpan::enter_with_local_parent("a child span");
//!
//!         Event::add_to_local_parent("event in span1", || [("key".into(), "value".into())]);
//!     }
//! }
//!
//! minitrace::flush();
//! ```
//!
//! ## Macro
//!
//! The attribute-macro [`trace`] helps to reduce boilerplate.
//!
//! Note: For successful tracing a function using the [`trace`] macro, the function call should occur
//! within __a local context of a `Span`__.
//!
//! For more detailed usage instructions, please refer to [`trace`].
//!
//! ```
//! use futures::executor::block_on;
//! use minitrace::collector::Config;
//! use minitrace::collector::ConsoleReporter;
//! use minitrace::prelude::*;
//!
//! #[trace]
//! fn do_something(i: u64) {
//!     std::thread::sleep(std::time::Duration::from_millis(i));
//! }
//!
//! #[trace]
//! async fn do_something_async(i: u64) {
//!     futures_timer::Delay::new(std::time::Duration::from_millis(i)).await;
//! }
//!
//! minitrace::set_reporter(ConsoleReporter, Config::default());
//!
//! {
//!     let root = Span::root("root", SpanContext::random());
//!     let _guard = root.set_local_parent();
//!
//!     do_something(100);
//!
//!     block_on(
//!         async {
//!             do_something_async(100).await;
//!         }
//!         .in_span(Span::enter_with_local_parent("aync_job")),
//!     );
//! }
//!
//! minitrace::flush();
//! ```
//!
//! ## Reporter
//!
//! [`Reporter`] is responsible for reporting the span records to a remote agent,
//! such as Jaeger.
//!
//! Executables should initialize a reporter implementation early in the program's
//! runtime. Span records generated before the implementation is initialized will be ignored.
//!
//! For an easy start, `minitrace` offers a [`ConsoleReporter`] that prints span
//! records to stderr. For more advanced use, crates like `minitrace-jaeger`, `minitrace-datadog`,
//! and `minitrace-opentelemetry` are available.
//!
//! By default, the reporter is triggered every 500 milliseconds. The reporter can also be
//! triggered manually by calling [`flush()`]. See [`Config`] for customizing the reporting behavior.
//! ```
//! use std::time::Duration;
//!
//! use minitrace::collector::Config;
//! use minitrace::collector::ConsoleReporter;
//!
//! minitrace::set_reporter(
//!     ConsoleReporter,
//!     Config::default().batch_report_interval(Duration::from_secs(1)),
//! );
//!
//! minitrace::flush();
//! ```
//!
//! # Performance
//!
//! `minitrace` is designed to be fast and lightweight, considering four scenarios:
//!
//! - **No Tracing**: `minitrace` is not included as dependency in the executable, while the
//! libraries has been instrumented. In this case, it will be completely removed from libraries,
//! causing zero overhead.
//!
//! - **Sample Tracing**: `minitrace` is enabled in the executable, but only a small portion
//! of the traces are enabled via [`Span::root()`], while the other portion start with placeholders
//! by [`Span::noop()`]. The overhead in this case is very small - merely an integer
//! load, comparison, and jump.
//!
//! - **Full Tracing with Tail Sampling**: `minitrace` is enabled in the executable, and all
//! traces are enabled. However, only a select few abnormal tracing records (e.g., P99) are
//! reported. Normal traces can be dismissed by using [`Span::cancel()`] to avoid reporting.
//! This could be useful when you are interested in examining program's tail latency.
//!
//! - **Full Tracing**: `minitrace` is enabled in the executable, and all traces are enabled.
//! All tracing records are reported. `minitrace` performs 10x to 100x faster than other tracing
//! libraries in this case.
//!
//!
//! [`Span`]: crate::Span
//! [`LocalSpan`]: crate::local::LocalSpan
//! [`SpanRecord`]: crate::collector::SpanRecord
//! [`FutureExt`]: crate::future::FutureExt
//! [`trace`]: crate::trace
//! [`LocalCollector`]: crate::local::LocalCollector
//! [`Span::root()`]: crate::Span::root
//! [`Span::noop()`]: crate::Span::noop
//! [`Span::cancel()`]: crate::Span::cancel
//! [`Span::enter_with_parent()`]: crate::Span::enter_with_parent
//! [`Span::set_local_parent()`]: crate::Span::set_local_parent
//! [`LocalSpan::enter_with_local_parent()`]: crate::local::LocalSpan::enter_with_local_parent
//! [`Event`]: crate::Event
//! [`Reporter`]: crate::collector::Reporter
//! [`ConsoleReporter`]: crate::collector::ConsoleReporter
//! [`Config`]: crate::collector::Config
//! [`Future`]: std::future::Future

// Suppress a false-positive lint from clippy
#![allow(clippy::needless_doctest_main)]
#![cfg_attr(not(feature = "enable"), allow(dead_code))]
#![cfg_attr(not(feature = "enable"), allow(unused_mut))]
#![cfg_attr(not(feature = "enable"), allow(unused_imports))]
#![cfg_attr(not(feature = "enable"), allow(unused_variables))]

pub mod collector;
mod event;
pub mod future;
pub mod local;
mod macros;
mod span;
#[doc(hidden)]
pub mod util;

pub use minitrace_macro::trace;

pub use crate::collector::global_collector::flush;
pub use crate::collector::global_collector::set_reporter;
pub use crate::event::Event;
pub use crate::span::Span;

pub mod prelude {
    //! A "prelude" for crates using `minitrace`.
    #[doc(no_inline)]
    pub use crate::collector::SpanContext;
    #[doc(no_inline)]
    pub use crate::collector::SpanId;
    #[doc(no_inline)]
    pub use crate::collector::SpanRecord;
    #[doc(no_inline)]
    pub use crate::collector::TraceId;
    #[doc(no_inline)]
    pub use crate::event::Event;
    #[doc(no_inline)]
    pub use crate::future::FutureExt as _;
    #[doc(no_inline)]
    pub use crate::local::LocalSpan;
    #[doc(no_inline)]
    pub use crate::span::Span;
    #[doc(no_inline)]
    pub use crate::trace;
}