tracing_ohos/
layer.rs

1use fmt::Display;
2use std::{
3    fmt,
4    io::{self, Write},
5};
6use tracing::{
7    event::Event,
8    field::Field,
9    field::Visit,
10    span::{Attributes, Id, Record},
11    Metadata, Subscriber,
12};
13use tracing_subscriber::{layer::Context, registry::LookupSpan};
14
15use crate::ohos::{OHOSWriter, CappedTag};
16
17/// A `Layer` that logs events and spans to the OpenHarmony's HiLog.
18/// It implements the `tracing_subscriber`'s [`Layer`] trait.
19///
20/// [`Layer`]: tracing_subscriber::Layer
21pub struct Layer {
22    domain: u16,
23    tag: CappedTag,
24}
25
26impl Layer {
27    /// Creates a new `Layer` with the given `domain` and `tag`.
28    pub fn new(domain: u16, tag: &str) -> io::Result<Self> {
29        let tag = CappedTag::new(tag.as_bytes())?;
30        Ok(Self { domain, tag })
31    }
32}
33
34impl<S> tracing_subscriber::Layer<S> for Layer
35where
36    S: Subscriber + for<'span> LookupSpan<'span>,
37{
38    fn on_new_span(&self, attrs: &Attributes, id: &Id, ctx: Context<S>) {
39        let span = ctx.span(id).expect("unknown span");
40        let mut buf = Vec::with_capacity(256);
41
42        let depth = span.parent().into_iter().flat_map(|x| x.scope()).count();
43
44        write!(buf, "s{}_name: ", depth).unwrap();
45        write_value(&mut buf, span.name());
46        put_metadata(&mut buf, span.metadata(), Some(depth));
47
48        attrs.record(&mut SpanVisitor::new(&mut buf, depth));
49
50        span.extensions_mut().insert(SpanFields(buf));
51    }
52
53    fn on_record(&self, id: &Id, values: &Record, ctx: Context<S>) {
54        let span = ctx.span(id).expect("unknown span");
55        let depth = span.parent().into_iter().flat_map(|x| x.scope()).count();
56        let mut exts = span.extensions_mut();
57        let buf = &mut exts.get_mut::<SpanFields>().expect("missing fields").0;
58        values.record(&mut SpanVisitor::new(buf, depth));
59    }
60
61    fn on_event(&self, event: &Event, ctx: Context<S>) {
62        let mut writer = OHOSWriter::new(event.metadata().level(), self.domain, &self.tag); //PlatformLogWriter::new(event.metadata().level(), &self.tag);
63
64        // add the target
65        let _ = write!(&mut writer, "{}: ", event.metadata().target());
66
67        // Record span fields
68        let maybe_scope = ctx
69            .current_span()
70            .id()
71            .and_then(|id| ctx.span_scope(id).map(|x| x.from_root()));
72        if let Some(scope) = maybe_scope {
73            for span in scope {
74                let exts = span.extensions();
75                if let Some(fields) = exts.get::<SpanFields>() {
76                    let _ = writer.write_all(&fields.0[..]);
77                }
78            }
79        }
80
81        // Record event fields
82        // TODO: make thius configurable
83        // put_metadata(&mut writer, event.metadata(), None);
84        event.record(&mut writer);
85    }
86}
87struct SpanFields(Vec<u8>);
88
89struct SpanVisitor<'a> {
90    buf: &'a mut Vec<u8>,
91    depth: usize,
92}
93
94impl<'a> SpanVisitor<'a> {
95    fn new(buf: &'a mut Vec<u8>, depth: usize) -> Self {
96        Self { buf, depth }
97    }
98}
99
100impl Visit for SpanVisitor<'_> {
101    fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
102        write!(self.buf, "s{}_", self.depth).unwrap();
103        write_debug(&mut self.buf, field.name(), value);
104    }
105}
106
107impl Visit for OHOSWriter<'_> {
108    fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
109        if field.name() == "message" {
110            // omit message field value
111            let _ = write!(self, "{:?}", value);
112        } else {
113            let _ = write_debug(self, field.name(), value);
114        }
115    }
116}
117
118fn put_metadata(mut buf: impl io::Write, meta: &Metadata, span: Option<usize>) {
119    write_name_with_value(&mut buf, "target", meta.target(), span);
120    if let Some(file) = meta.file() {
121        write_name_with_value(&mut buf, "file", file, span);
122    }
123    if let Some(line) = meta.line() {
124        write_name_with_value(&mut buf, "line", line, span);
125    }
126}
127
128fn write_debug(mut buf: impl io::Write, name: &str, value: &dyn fmt::Debug) {
129    let _ = write!(&mut buf, "{}={:?}", name, value);
130}
131
132fn write_name_with_value<T>(mut buf: impl io::Write, name: &str, value: T, span: Option<usize>)
133where
134    T: Display,
135{
136    if let Some(n) = span {
137        let _ = write!(&mut buf, "s{}_", n);
138    }
139    let _ = write!(buf, "{}={}", name, value);
140}
141
142fn write_value<T>(mut buf: impl io::Write, value: T)
143where
144    T: Display,
145{
146    let _ = write!(&mut buf, "{}", value);
147}