#![cfg_attr(test, allow(dead_code))]
pub(crate) mod command;
mod console_reporter;
pub(crate) mod global_collector;
pub(crate) mod id;
mod test_reporter;
use std::borrow::Cow;
use std::rc::Rc;
use std::sync::Arc;
use std::time::Duration;
pub use console_reporter::ConsoleReporter;
#[cfg(not(test))]
pub(crate) use global_collector::GlobalCollect;
#[cfg(test)]
pub(crate) use global_collector::MockGlobalCollect;
pub use global_collector::Reporter;
pub use id::SpanId;
pub use id::TraceId;
#[doc(hidden)]
pub use test_reporter::TestReporter;
use crate::local::local_collector::LocalSpansInner;
use crate::local::local_span_stack::LOCAL_SPAN_STACK;
use crate::local::raw_span::RawSpan;
use crate::Span;
#[cfg(test)]
pub(crate) type GlobalCollect = Arc<MockGlobalCollect>;
#[doc(hidden)]
#[derive(Debug)]
pub enum SpanSet {
Span(RawSpan),
LocalSpansInner(LocalSpansInner),
SharedLocalSpans(Arc<LocalSpansInner>),
}
#[derive(Clone, Debug, Default, PartialEq)]
pub struct SpanRecord {
pub trace_id: TraceId,
pub span_id: SpanId,
pub parent_id: SpanId,
pub begin_time_unix_ns: u64,
pub duration_ns: u64,
pub name: Cow<'static, str>,
pub properties: Vec<(Cow<'static, str>, Cow<'static, str>)>,
pub events: Vec<EventRecord>,
}
#[derive(Clone, Debug, Default, PartialEq)]
pub struct EventRecord {
pub name: Cow<'static, str>,
pub timestamp_unix_ns: u64,
pub properties: Vec<(Cow<'static, str>, Cow<'static, str>)>,
}
#[doc(hidden)]
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct CollectTokenItem {
pub trace_id: TraceId,
pub parent_id: SpanId,
pub collect_id: usize,
pub is_root: bool,
}
#[derive(Clone, Copy, Debug, Default)]
pub struct SpanContext {
pub trace_id: TraceId,
pub span_id: SpanId,
}
impl SpanContext {
pub fn new(trace_id: TraceId, span_id: SpanId) -> Self {
Self { trace_id, span_id }
}
pub fn random() -> Self {
Self {
trace_id: TraceId(rand::random()),
span_id: SpanId::default(),
}
}
pub fn from_span(span: &Span) -> Option<Self> {
#[cfg(not(feature = "enable"))]
{
None
}
#[cfg(feature = "enable")]
{
let inner = span.inner.as_ref()?;
let collect_token = inner.issue_collect_token().next()?;
Some(Self {
trace_id: collect_token.trace_id,
span_id: collect_token.parent_id,
})
}
}
pub fn current_local_parent() -> Option<Self> {
#[cfg(not(feature = "enable"))]
{
None
}
#[cfg(feature = "enable")]
{
let stack = LOCAL_SPAN_STACK.try_with(Rc::clone).ok()?;
let mut stack = stack.borrow_mut();
let collect_token = stack.current_collect_token()?[0];
Some(Self {
trace_id: collect_token.trace_id,
span_id: collect_token.parent_id,
})
}
}
pub fn decode_w3c_traceparent(traceparent: &str) -> Option<Self> {
let mut parts = traceparent.split('-');
match (
parts.next(),
parts.next(),
parts.next(),
parts.next(),
parts.next(),
) {
(Some("00"), Some(trace_id), Some(span_id), Some(_), None) => {
let trace_id = u128::from_str_radix(trace_id, 16).ok()?;
let span_id = u64::from_str_radix(span_id, 16).ok()?;
Some(Self::new(TraceId(trace_id), SpanId(span_id)))
}
_ => None,
}
}
pub fn encode_w3c_traceparent(&self) -> String {
Self::encode_w3c_traceparent_with_sampled(self, true)
}
pub fn encode_w3c_traceparent_with_sampled(&self, sampled: bool) -> String {
format!(
"00-{:032x}-{:016x}-{:02x}",
self.trace_id.0, self.span_id.0, sampled as u8,
)
}
}
#[must_use]
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct Config {
pub(crate) max_spans_per_trace: Option<usize>,
pub(crate) report_interval: Duration,
pub(crate) report_before_root_finish: bool,
}
impl Config {
pub fn max_spans_per_trace(self, max_spans_per_trace: Option<usize>) -> Self {
Self {
max_spans_per_trace,
..self
}
}
#[deprecated(
since = "0.6.7",
note = "Please use `report_interval` instead. This method is now a no-op."
)]
pub fn batch_report_interval(self, _batch_report_interval: Duration) -> Self {
self
}
#[deprecated(
since = "0.6.7",
note = "Please use `report_interval` instead. This method is now a no-op."
)]
pub fn batch_report_max_spans(self, _batch_report_max_spans: Option<usize>) -> Self {
self
}
pub fn report_interval(self, report_interval: Duration) -> Self {
Self {
report_interval,
..self
}
}
pub fn report_before_root_finish(self, report_before_root_finish: bool) -> Self {
Self {
report_before_root_finish,
..self
}
}
}
impl Default for Config {
fn default() -> Self {
Self {
max_spans_per_trace: None,
report_interval: Duration::from_millis(10),
report_before_root_finish: false,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn w3c_traceparent() {
let span_context = SpanContext::decode_w3c_traceparent(
"00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01",
)
.unwrap();
assert_eq!(
span_context.trace_id,
TraceId(0x0af7651916cd43dd8448eb211c80319c)
);
assert_eq!(span_context.span_id, SpanId(0xb7ad6b7169203331));
assert_eq!(
span_context.encode_w3c_traceparent(),
"00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01"
);
assert_eq!(
span_context.encode_w3c_traceparent_with_sampled(false),
"00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-00"
);
}
}