Skip to content

Commit 0fc28d3

Browse files
committed
port over hierarchical layer/tree
1 parent 296818b commit 0fc28d3

File tree

3 files changed

+266
-38
lines changed

3 files changed

+266
-38
lines changed

Cargo.toml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ edition = "2018"
77
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
88

99
[dependencies]
10-
tracing = "0.1.11"
11-
tracing-subscriber = { git = "https://github.com/tokio-rs/tracing" }
10+
tracing = "0.1.12"
11+
tracing-subscriber = "0.2.0-alpha.5"
1212
quanta = "0.3.1"
1313
termcolor = "1.0.5"
14+
ansi_term = "0.12.1"
15+
chrono = "0.4.10"

examples/basic.rs

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,44 @@
1-
use tracing::{info, instrument, span, Level};
2-
use tracing_subscriber::layer::SubscriberExt;
3-
use tracing_subscriber::{registry::Registry, Layer};
4-
use tracing_tree::TreeLayer;
1+
use tracing::{debug, info, instrument, span, warn, Level};
2+
use tracing_subscriber::{layer::SubscriberExt, registry::Registry};
3+
use tracing_tree::HierarchicalLayer;
54

65
fn main() {
7-
let subscriber = Registry::default().with(TreeLayer::default());
8-
tracing::subscriber::set_global_default(subscriber).expect("Unable to set a global default");
9-
call_a("david");
6+
let subscriber = Registry::default().with(HierarchicalLayer::new(2));
7+
tracing::subscriber::set_global_default(subscriber).unwrap();
8+
9+
let app_span = span!(Level::TRACE, "hierarchical-example", version = %0.1);
10+
let _e = app_span.enter();
11+
12+
let server_span = span!(Level::TRACE, "server", host = "localhost", port = 8080);
13+
let _e2 = server_span.enter();
14+
info!("starting");
15+
std::thread::sleep(std::time::Duration::from_millis(300));
16+
info!("listening");
17+
let peer1 = span!(Level::TRACE, "conn", peer_addr = "82.9.9.9", port = 42381);
18+
peer1.in_scope(|| {
19+
debug!("connected");
20+
std::thread::sleep(std::time::Duration::from_millis(300));
21+
debug!(length = 2, "message received");
22+
});
23+
let peer2 = span!(Level::TRACE, "conn", peer_addr = "8.8.8.8", port = 18230);
24+
peer2.in_scope(|| {
25+
std::thread::sleep(std::time::Duration::from_millis(300));
26+
debug!("connected");
27+
});
28+
peer1.in_scope(|| {
29+
warn!(algo = "xor", "weak encryption requested");
30+
std::thread::sleep(std::time::Duration::from_millis(300));
31+
debug!(length = 8, "response sent");
32+
debug!("disconnected");
33+
});
34+
peer2.in_scope(|| {
35+
debug!(length = 5, "message received");
36+
std::thread::sleep(std::time::Duration::from_millis(300));
37+
debug!(length = 8, "response sent");
38+
debug!("disconnected");
39+
});
40+
warn!("internal error");
41+
info!("exit");
1042
}
1143

1244
#[instrument]

src/lib.rs

Lines changed: 223 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,247 @@
1-
use quanta::Clock;
2-
use std::fmt::Debug;
1+
use ansi_term::{Color, Style};
2+
use chrono::{DateTime, Local};
3+
use std::{fmt, io, io::Write as _};
34
use tracing::{
4-
span::{Attributes, Id, Record},
5-
Event, Level, Metadata, Subscriber,
5+
field::{Field, Visit},
6+
span::{Attributes, Id},
7+
Event, Level, Subscriber,
68
};
79
use tracing_subscriber::{
810
layer::{Context, Layer},
911
registry::LookupSpan,
1012
};
1113

12-
#[derive(Debug, Default)]
13-
pub struct TreeLayer {
14-
clock: Clock,
14+
#[derive(Debug)]
15+
pub struct HierarchicalLayer {
16+
stdout: io::Stdout,
17+
indent_amount: usize,
1518
}
1619

17-
#[derive(Debug)]
1820
struct Data {
19-
start: u64,
20-
level: Level,
21+
start: DateTime<Local>,
22+
kvs: Vec<(&'static str, String)>,
23+
}
24+
25+
struct FmtEvent<'a> {
26+
stdout: io::StdoutLock<'a>,
27+
comma: bool,
28+
}
29+
30+
impl Data {
31+
fn new(attrs: &tracing::span::Attributes<'_>) -> Self {
32+
let mut span = Self {
33+
start: Local::now(),
34+
kvs: Vec::new(),
35+
};
36+
attrs.record(&mut span);
37+
span
38+
}
39+
}
40+
41+
impl Visit for Data {
42+
fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
43+
self.kvs.push((field.name(), format!("{:?}", value)))
44+
}
45+
}
46+
47+
impl<'a> Visit for FmtEvent<'a> {
48+
fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
49+
write!(
50+
&mut self.stdout,
51+
"{comma} ",
52+
comma = if self.comma { "," } else { "" },
53+
)
54+
.unwrap();
55+
let name = field.name();
56+
if name == "message" {
57+
write!(&mut self.stdout, "{:?}", value).unwrap();
58+
self.comma = true;
59+
} else {
60+
write!(&mut self.stdout, "{}={:?}", name, value).unwrap();
61+
self.comma = true;
62+
}
63+
}
64+
}
65+
66+
struct ColorLevel<'a>(&'a Level);
67+
68+
impl<'a> fmt::Display for ColorLevel<'a> {
69+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
70+
match *self.0 {
71+
Level::TRACE => Color::Purple.bold().paint("TRACE"),
72+
Level::DEBUG => Color::Blue.bold().paint("DEBUG"),
73+
Level::INFO => Color::Green.bold().paint(" INFO"),
74+
Level::WARN => Color::RGB(252, 234, 160).bold().paint(" WARN"), // orange
75+
Level::ERROR => Color::Red.bold().paint("ERROR"),
76+
}
77+
.fmt(f)
78+
}
2179
}
2280

23-
impl<S> Layer<S> for TreeLayer
81+
impl HierarchicalLayer {
82+
pub fn new(indent_amount: usize) -> Self {
83+
Self {
84+
indent_amount,
85+
stdout: io::stdout(),
86+
}
87+
}
88+
89+
fn print_kvs<'a, I, K, V>(
90+
&self,
91+
writer: &mut impl io::Write,
92+
kvs: I,
93+
leading: &str,
94+
) -> io::Result<()>
95+
where
96+
I: IntoIterator<Item = (K, V)>,
97+
K: AsRef<str> + 'a,
98+
V: fmt::Display + 'a,
99+
{
100+
let mut kvs = kvs.into_iter();
101+
if let Some((k, v)) = kvs.next() {
102+
write!(
103+
writer,
104+
"{}{}={}",
105+
leading,
106+
// Style::new().fg(Color::Purple).bold().paint(k.as_ref()),
107+
k.as_ref(),
108+
v
109+
)?;
110+
}
111+
for (k, v) in kvs {
112+
write!(
113+
writer,
114+
", {}={}",
115+
// Style::new().fg(Color::Purple).bold().paint(k.as_ref()),
116+
k.as_ref(),
117+
v
118+
)?;
119+
}
120+
Ok(())
121+
}
122+
123+
fn print_indent(&self, writer: &mut impl io::Write, indent: usize) -> io::Result<()> {
124+
for _ in 0..(indent * self.indent_amount) {
125+
write!(writer, " ")?;
126+
}
127+
Ok(())
128+
}
129+
}
130+
131+
impl<S> Layer<S> for HierarchicalLayer
24132
where
25-
S: Subscriber + for<'span> LookupSpan<'span> + Debug,
133+
S: Subscriber + for<'span> LookupSpan<'span> + fmt::Debug,
26134
{
27135
fn new_span(&self, attrs: &Attributes, id: &Id, ctx: Context<S>) {
28-
let start = self.clock.now();
29-
let level = attrs.metadata().level();
30-
dbg!(attrs);
31-
let data = Data {
32-
start,
33-
level: level.clone(),
34-
};
136+
let data = Data::new(attrs);
35137
let span = ctx.span(id).expect("in new_span but span does not exist");
36138
span.extensions_mut().insert(data);
37139
}
38140

39-
fn on_event(&self, event: &Event<'_>, _ctx: Context<S>) {
40-
dbg!(event);
141+
fn on_enter(&self, id: &tracing::Id, ctx: Context<S>) {
142+
let mut stdout = self.stdout.lock();
143+
let span = ctx.span(&id).expect("in on_enter but span does not exist");
144+
let ext = span.extensions();
145+
let data = ext.get::<Data>().expect("span does not have data");
146+
147+
let indent = ctx.scope().collect::<Vec<_>>().len() - 1;
148+
self.print_indent(&mut stdout, indent)
149+
.expect("Unable to write to stdout");
150+
151+
write!(
152+
&mut stdout,
153+
"{name}",
154+
name = Style::new()
155+
.fg(Color::Green)
156+
.bold()
157+
.paint(span.metadata().name())
158+
)
159+
.unwrap();
160+
write!(
161+
&mut stdout,
162+
"{}",
163+
Style::new().fg(Color::Green).paint("{") // Style::new().fg(Color::Green).dimmed().paint("{")
164+
)
165+
.unwrap();
166+
self.print_kvs(&mut stdout, data.kvs.iter().map(|(k, v)| (k, v)), "")
167+
.unwrap();
168+
write!(
169+
&mut stdout,
170+
"{}",
171+
Style::new().fg(Color::Green).bold().paint("}") // Style::new().dimmed().paint("}")
172+
)
173+
.unwrap();
174+
writeln!(&mut stdout).unwrap();
175+
}
176+
177+
fn on_event(&self, event: &Event<'_>, ctx: Context<S>) {
178+
let mut stdout = self.stdout.lock();
179+
// printing the indentation
180+
if let Some(_) = ctx.current_span().id() {
181+
// size hint isn't implemented on Scope.
182+
let indent = ctx.scope().collect::<Vec<_>>().len();
183+
self.print_indent(&mut stdout, indent)
184+
.expect("Unable to write to stdout");
185+
}
186+
187+
// check if this event occurred in the context of a span.
188+
// if it has, get the start time of this span.
189+
let start = match ctx.current_span().id() {
190+
Some(id) => match ctx.span(id) {
191+
// if the event is in a span, get the span's starting point.
192+
Some(ctx) => {
193+
let ext = ctx.extensions();
194+
let data = ext
195+
.get::<Data>()
196+
.expect("Data cannot be found in extensions");
197+
Some(data.start)
198+
}
199+
None => None,
200+
},
201+
None => None,
202+
};
203+
let now = Local::now();
204+
if let Some(start) = start {
205+
let elapsed = now - start;
206+
write!(
207+
&mut stdout,
208+
"{timestamp}{unit} {level}",
209+
timestamp = Style::new()
210+
.dimmed()
211+
.paint(elapsed.num_milliseconds().to_string()),
212+
unit = Style::new().dimmed().paint("ms"),
213+
level = ColorLevel(event.metadata().level())
214+
)
215+
.expect("Unable to write to stdout");
216+
}
217+
let mut visitor = FmtEvent {
218+
stdout,
219+
comma: false,
220+
};
221+
event.record(&mut visitor);
222+
writeln!(&mut visitor.stdout).unwrap();
41223
}
42224

43-
fn on_close(&self, id: Id, ctx: Context<S>) {
44-
let end = self.clock.now();
45-
let span = ctx.span(&id).expect("in on_close but span does not exist");
46-
let mut ext = span.extensions_mut();
47-
let data = ext
48-
.get_mut::<Data>()
49-
.expect("span does not have metric data");
225+
fn on_close(&self, _: Id, _: Context<S>) {
226+
// let end = Local::now();
227+
// let span = ctx.span(&id).expect("in on_close but span does not exist");
228+
// let ext = span.extensions();
229+
// let data = ext.get::<Data>().expect("span does not have metric data");
230+
231+
// let indent = ctx.scope().collect::<Vec<_>>().len();
232+
// let mut stdout = self.stdout.lock();
233+
// self.print_indent(&mut stdout, indent)
234+
// .expect("Unable to write to stdout");
50235

51-
let elapsed = self.clock.delta(data.start, end);
236+
// let elapsed = end - data.start;
237+
// writeln!(
238+
// &mut stdout,
239+
// "Elapsed: {timestamp}{unit}",
240+
// timestamp = Style::new()
241+
// .dimmed()
242+
// .paint(elapsed.num_milliseconds().to_string()),
243+
// unit = Style::new().dimmed().paint("ms"),
244+
// )
245+
// .expect("Unable to write to stdout");
52246
}
53247
}

0 commit comments

Comments
 (0)