tracing_honeycomb/
visitor.rs1use chrono::{DateTime, Utc};
2use libhoney::{json, Value};
3use std::collections::HashMap;
4use std::fmt;
5use tracing::field::{Field, Visit};
6use tracing_distributed::{Event, Span};
7
8use crate::{SpanId, TraceId};
9
10const MILLIS_PER_SECOND: f64 = 1000_f64;
11
12#[derive(Default, Debug)]
14#[doc(hidden)]
15pub struct HoneycombVisitor(pub(crate) HashMap<String, Value>);
16
17static RESERVED_WORDS: [&str; 9] = [
19 "trace.span_id",
20 "trace.trace_id",
21 "trace.parent_id",
22 "service_name",
23 "level",
24 "Timestamp",
25 "name",
26 "target",
27 "duration_ms",
28];
29
30impl Visit for HoneycombVisitor {
31 fn record_i64(&mut self, field: &Field, value: i64) {
32 self.0
33 .insert(mk_field_name(field.name().to_string()), json!(value));
34 }
35
36 fn record_u64(&mut self, field: &Field, value: u64) {
37 self.0
38 .insert(mk_field_name(field.name().to_string()), json!(value));
39 }
40
41 fn record_bool(&mut self, field: &Field, value: bool) {
42 self.0
43 .insert(mk_field_name(field.name().to_string()), json!(value));
44 }
45
46 fn record_str(&mut self, field: &Field, value: &str) {
47 self.0
48 .insert(mk_field_name(field.name().to_string()), json!(value));
49 }
50
51 fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
52 let s = format!("{:?}", value);
53 self.0
54 .insert(mk_field_name(field.name().to_string()), json!(s));
55 }
56}
57
58fn mk_field_name(s: String) -> String {
59 if RESERVED_WORDS.contains(&&s[..]) {
61 format!("tracing.{}", s)
62 } else {
63 s
64 }
65}
66
67pub(crate) fn event_to_values(
68 event: Event<HoneycombVisitor, SpanId, TraceId>,
69) -> (HashMap<String, libhoney::Value>, DateTime<Utc>) {
70 let mut values = event.values.0;
71
72 values.insert(
73 "trace.trace_id".to_string(),
75 json!(event.trace_id.to_string()),
77 );
78
79 values.insert(
80 "trace.parent_id".to_string(),
82 event
83 .parent_id
84 .map(|pid| json!(pid.to_string()))
85 .unwrap_or(json!(null)),
86 );
87
88 values.insert("service_name".to_string(), json!(event.service_name));
90
91 values.insert(
92 "level".to_string(),
93 json!(format!("{}", event.meta.level())),
94 );
95
96 values.insert("name".to_string(), json!(event.meta.name()));
98 values.insert("target".to_string(), json!(event.meta.target()));
99
100 (values, event.initialized_at.into())
101}
102
103pub(crate) fn span_to_values(
104 span: Span<HoneycombVisitor, SpanId, TraceId>,
105) -> (HashMap<String, libhoney::Value>, DateTime<Utc>) {
106 let mut values = span.values.0;
107
108 values.insert(
109 "trace.span_id".to_string(),
111 json!(span.id.to_string()),
112 );
113
114 values.insert(
115 "trace.trace_id".to_string(),
117 json!(span.trace_id.to_string()),
119 );
120
121 values.insert(
122 "trace.parent_id".to_string(),
124 span.parent_id
125 .map(|pid| json!(pid.to_string()))
126 .unwrap_or(json!(null)),
127 );
128
129 values.insert("service_name".to_string(), json!(span.service_name));
131
132 values.insert("level".to_string(), json!(format!("{}", span.meta.level())));
133
134 values.insert("name".to_string(), json!(span.meta.name()));
136 values.insert("target".to_string(), json!(span.meta.target()));
137
138 match span.completed_at.duration_since(span.initialized_at) {
139 Ok(d) => {
140 values.insert(
142 "duration_ms".to_string(),
143 json!(d.as_secs_f64() * MILLIS_PER_SECOND),
144 );
145 }
146 Err(e) => {
147 eprintln!("error comparing system times in tracing-honeycomb, indicates possible clock skew: {:?}", e);
148 }
149 }
150
151 (values, span.initialized_at.into())
152}