tracing_honeycomb/lib.rs
1#![deny(
2 warnings,
3 missing_debug_implementations,
4 missing_copy_implementations,
5 missing_docs
6)]
7
8//! This crate provides:
9//! - A tracing layer, `TelemetryLayer`, that can be used to publish trace data to honeycomb.io
10//! - Utilities for implementing distributed tracing against the honeycomb.io backend
11//!
12//! As a tracing layer, `TelemetryLayer` can be composed with other layers to provide stdout logging, filtering, etc.
13
14mod honeycomb;
15mod reporter;
16mod span_id;
17mod trace_id;
18mod visitor;
19
20pub use honeycomb::HoneycombTelemetry;
21pub use reporter::{LibhoneyReporter, Reporter, StdoutReporter};
22pub use span_id::SpanId;
23pub use trace_id::TraceId;
24#[doc(no_inline)]
25pub use tracing_distributed::{TelemetryLayer, TraceCtxError};
26pub use visitor::HoneycombVisitor;
27
28pub(crate) mod deterministic_sampler;
29
30#[cfg(feature = "use_parking_lot")]
31use parking_lot::Mutex;
32#[cfg(not(feature = "use_parking_lot"))]
33use std::sync::Mutex;
34
35/// Register the current span as the local root of a distributed trace.
36///
37/// Specialized to the honeycomb.io-specific SpanId and TraceId provided by this crate.
38pub fn register_dist_tracing_root(
39 trace_id: TraceId,
40 remote_parent_span: Option<SpanId>,
41) -> Result<(), TraceCtxError> {
42 tracing_distributed::register_dist_tracing_root(trace_id, remote_parent_span)
43}
44
45/// Retrieve the distributed trace context associated with the current span.
46///
47/// Returns the `TraceId`, if any, that the current span is associated with along with
48/// the `SpanId` belonging to the current span.
49///
50/// Specialized to the honeycomb.io-specific SpanId and TraceId provided by this crate.
51pub fn current_dist_trace_ctx() -> Result<(TraceId, SpanId), TraceCtxError> {
52 tracing_distributed::current_dist_trace_ctx()
53}
54
55/// Construct a TelemetryLayer that does not publish telemetry to any backend.
56///
57/// Specialized to the honeycomb.io-specific SpanId and TraceId provided by this crate.
58pub fn new_blackhole_telemetry_layer(
59) -> TelemetryLayer<tracing_distributed::BlackholeTelemetry<SpanId, TraceId>, SpanId, TraceId> {
60 TelemetryLayer::new(
61 "honeycomb_blackhole_tracing_layer",
62 tracing_distributed::BlackholeTelemetry::default(),
63 move |tracing_id| SpanId { tracing_id },
64 )
65}
66
67/// Construct a TelemetryLayer that publishes telemetry to honeycomb.io using the provided honeycomb config.
68///
69/// Specialized to the honeycomb.io-specific SpanId and TraceId provided by this crate.
70pub fn new_honeycomb_telemetry_layer(
71 service_name: &'static str,
72 honeycomb_config: libhoney::Config,
73) -> TelemetryLayer<HoneycombTelemetry<LibhoneyReporter>, SpanId, TraceId> {
74 let reporter = libhoney::init(honeycomb_config);
75 // publishing requires &mut so just mutex-wrap it
76 // FIXME: may not be performant, investigate options (eg mpsc)
77 let reporter = Mutex::new(reporter);
78
79 TelemetryLayer::new(
80 service_name,
81 HoneycombTelemetry::new(reporter, None),
82 move |tracing_id| SpanId { tracing_id },
83 )
84}
85
86/// Construct a TelemetryLayer that publishes telemetry to honeycomb.io using the
87/// provided honeycomb config, and sample rate.
88///
89/// This function differs from `new_honeycomb_telemetry_layer` and the `sample_rate`
90/// on the `libhoney::Config` there in an important way. `libhoney` samples `Event`
91/// data, which is individual spans on each trace. This means that using the
92/// sampling logic in libhoney may result in missing event data or incomplete
93/// traces. Calling this function provides trace-level sampling, meaning sampling
94/// decisions are based on a modulo of the traceID, and events in a single trace
95/// will not be sampled differently. If the trace is sampled, then all spans
96/// under it will be sent to honeycomb. If a trace is not sampled, no spans or
97/// events under it will be sent. When using this trace-level sampling, the
98/// `sample_rate` parameter on the `libhoney::Config` should be set to 1, which
99/// is the default.
100///
101/// Specialized to the honeycomb.io-specific SpanId and TraceId provided by this crate.
102pub fn new_honeycomb_telemetry_layer_with_trace_sampling(
103 service_name: &'static str,
104 honeycomb_config: libhoney::Config,
105 sample_rate: u32,
106) -> TelemetryLayer<HoneycombTelemetry<LibhoneyReporter>, SpanId, TraceId> {
107 let reporter = libhoney::init(honeycomb_config);
108 // publishing requires &mut so just mutex-wrap it
109 // FIXME: may not be performant, investigate options (eg mpsc)
110 let reporter = Mutex::new(reporter);
111
112 TelemetryLayer::new(
113 service_name,
114 HoneycombTelemetry::new(reporter, Some(sample_rate)),
115 move |tracing_id| SpanId { tracing_id },
116 )
117}
118
119/// Builds Honeycomb Telemetry with custom configuration values.
120///
121/// Methods can be chained in order to set the configuration values. The
122/// TelemetryLayer is constructed by calling [`build`].
123///
124/// New instances of `Builder` are obtained via [`Builder::new_libhoney`]
125/// or [`Builder::new_stdout`].
126///
127/// [`Builder::new_stdout`] is useful when instrumenting e.g. AWS Lambda functions.
128/// See more at [AWS Lambda Instrumentation]. For almost all other use cases you are probably
129/// looking for [`Builder::new_libhoney`].
130///
131/// [`build`]: method@Self::build
132/// [`Builder::new_stdout`]: method@Builder::<StdoutReporter>::new_stdout
133/// [`Builder::new_libhoney`]: method@Builder::<LibhoneyReporter>::new_libhoney
134/// [AWS Lambda Instrumentation]: https://docs.honeycomb.io/getting-data-in/integrations/aws/aws-lambda/
135#[derive(Debug)]
136pub struct Builder<R> {
137 reporter: R,
138 sample_rate: Option<u32>,
139 service_name: &'static str,
140}
141
142impl Builder<StdoutReporter> {
143 /// Returns a new `Builder` that reports data to stdout
144 pub fn new_stdout(service_name: &'static str) -> Self {
145 Self {
146 reporter: StdoutReporter,
147 sample_rate: None,
148 service_name,
149 }
150 }
151}
152
153impl Builder<LibhoneyReporter> {
154 /// Returns a new `Builder` that reports data to a [`libhoney::Client`]
155 pub fn new_libhoney(service_name: &'static str, config: libhoney::Config) -> Self {
156 let reporter = libhoney::init(config);
157
158 // Handle the libhoney response channel by consuming and ignoring messages. This prevents a
159 // deadlock because the responses() channel is bounded and gains an item for every event
160 // emitted.
161 let responses = reporter.responses();
162 std::thread::spawn(move || {
163 loop {
164 if responses.recv().is_err() {
165 // If we receive an error, the channel is empty & disconnected. No need to keep
166 // this thread around.
167 break;
168 }
169 }
170 });
171
172 // publishing requires &mut so just mutex-wrap it
173 // FIXME: may not be performant, investigate options (eg mpsc)
174 let reporter = Mutex::new(reporter);
175
176 Self {
177 reporter,
178 sample_rate: None,
179 service_name,
180 }
181 }
182}
183
184impl<R: Reporter> Builder<R> {
185 /// Enables sampling for the telemetry layer.
186 ///
187 /// The `sample_rate` on the `libhoney::Config` is different from this in an important way.
188 /// `libhoney` samples `Event` data, which is individual spans on each trace.
189 /// This means that using the sampling logic in libhoney may result in missing
190 /// event data or incomplete traces.
191 /// Calling this function provides trace-level sampling, meaning sampling
192 /// decisions are based on a modulo of the traceID, and events in a single trace
193 /// will not be sampled differently. If the trace is sampled, then all spans
194 /// under it will be sent to honeycomb. If a trace is not sampled, no spans or
195 /// events under it will be sent. When using this trace-level sampling,
196 /// when using a [`LibhoneyReporter`] the `sample_rate` parameter on the
197 /// [`libhoney::Config`] should be set to 1, which is the default.
198 pub fn with_trace_sampling(mut self, sample_rate: u32) -> Self {
199 self.sample_rate.replace(sample_rate);
200 self
201 }
202
203 /// Constructs the configured `TelemetryLayer`
204 pub fn build(self) -> TelemetryLayer<HoneycombTelemetry<R>, SpanId, TraceId> {
205 TelemetryLayer::new(
206 self.service_name,
207 HoneycombTelemetry::new(self.reporter, self.sample_rate),
208 move |tracing_id| SpanId { tracing_id },
209 )
210 }
211}