| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212 | use serde::ser::{SerializeMap, Serializer};use serde_json::Value;use std::{fmt, io::Write};use tracing::{Event, Id, Subscriber};use tracing_bunyan_formatter::JsonStorage;use tracing_core::{metadata::Level, span::Attributes};use tracing_subscriber::{fmt::MakeWriter, layer::Context, registry::SpanRef, Layer};const LEVEL: &str = "level";const TIME: &str = "time";const MESSAGE: &str = "msg";const LOG_MODULE_PATH: &str = "log.module_path";const LOG_TARGET_PATH: &str = "log.target";const FLOWY_RESERVED_FIELDS: [&str; 3] = [LEVEL, TIME, MESSAGE];const IGNORE_FIELDS: [&str; 2] = [LOG_MODULE_PATH, LOG_TARGET_PATH];pub struct FlowyFormattingLayer<W: MakeWriter + 'static> {    make_writer: W,    with_target: bool,}impl<W: MakeWriter + 'static> FlowyFormattingLayer<W> {    pub fn new(make_writer: W) -> Self {        Self {            make_writer,            with_target: false,        }    }    fn serialize_flowy_folder_fields(        &self,        map_serializer: &mut impl SerializeMap<Error = serde_json::Error>,        message: &str,        _level: &Level,    ) -> Result<(), std::io::Error> {        map_serializer.serialize_entry(MESSAGE, &message)?;        // map_serializer.serialize_entry(LEVEL, &format!("{}", level))?;        // map_serializer.serialize_entry(TIME, &chrono::Utc::now().timestamp())?;        Ok(())    }    fn serialize_span<S: Subscriber + for<'a> tracing_subscriber::registry::LookupSpan<'a>>(        &self,        span: &SpanRef<S>,        ty: Type,    ) -> Result<Vec<u8>, std::io::Error> {        let mut buffer = Vec::new();        let mut serializer = serde_json::Serializer::new(&mut buffer);        let mut map_serializer = serializer.serialize_map(None)?;        let message = format_span_context(span, ty);        self.serialize_flowy_folder_fields(&mut map_serializer, &message, span.metadata().level())?;        if self.with_target {            map_serializer.serialize_entry("target", &span.metadata().target())?;        }        map_serializer.serialize_entry("line", &span.metadata().line())?;        map_serializer.serialize_entry("file", &span.metadata().file())?;        let extensions = span.extensions();        if let Some(visitor) = extensions.get::<JsonStorage>() {            for (key, value) in visitor.values() {                if !FLOWY_RESERVED_FIELDS.contains(key) && !IGNORE_FIELDS.contains(key) {                    map_serializer.serialize_entry(key, value)?;                } else {                    tracing::debug!("{} is a reserved field in the bunyan log format. Skipping it.", key);                }            }        }        map_serializer.end()?;        Ok(buffer)    }    fn emit(&self, mut buffer: Vec<u8>) -> Result<(), std::io::Error> {        buffer.write_all(b"\n")?;        self.make_writer.make_writer().write_all(&buffer)    }}/// The type of record we are dealing with: entering a span, exiting a span, an/// event.#[derive(Clone, Debug)]pub enum Type {    EnterSpan,    ExitSpan,    Event,}impl fmt::Display for Type {    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {        let repr = match self {            Type::EnterSpan => "START",            Type::ExitSpan => "END",            Type::Event => "EVENT",        };        write!(f, "{}", repr)    }}fn format_span_context<S: Subscriber + for<'a> tracing_subscriber::registry::LookupSpan<'a>>(    span: &SpanRef<S>,    ty: Type,) -> String {    format!("[⛳ {} - {}]", span.metadata().name().to_uppercase(), ty)}fn format_event_message<S: Subscriber + for<'a> tracing_subscriber::registry::LookupSpan<'a>>(    current_span: &Option<SpanRef<S>>,    event: &Event,    event_visitor: &JsonStorage<'_>,) -> String {    // Extract the "message" field, if provided. Fallback to the target, if missing.    let mut message = event_visitor        .values()        .get("message")        .map(|v| match v {            Value::String(s) => Some(s.as_str()),            _ => None,        })        .flatten()        .unwrap_or_else(|| event.metadata().target())        .to_owned();    // If the event is in the context of a span, prepend the span name to the    // message.    if let Some(span) = ¤t_span {        message = format!("{} {}", format_span_context(span, Type::Event), message);    }    message}impl<S, W> Layer<S> for FlowyFormattingLayer<W>where    S: Subscriber + for<'a> tracing_subscriber::registry::LookupSpan<'a>,    W: MakeWriter + 'static,{    fn on_event(&self, event: &Event<'_>, ctx: Context<'_, S>) {        // Events do not necessarily happen in the context of a span, hence        // lookup_current returns an `Option<SpanRef<_>>` instead of a        // `SpanRef<_>`.        let current_span = ctx.lookup_current();        let mut event_visitor = JsonStorage::default();        event.record(&mut event_visitor);        // Opting for a closure to use the ? operator and get more linear code.        let format = || {            let mut buffer = Vec::new();            let mut serializer = serde_json::Serializer::new(&mut buffer);            let mut map_serializer = serializer.serialize_map(None)?;            let message = format_event_message(¤t_span, event, &event_visitor);            self.serialize_flowy_folder_fields(&mut map_serializer, &message, event.metadata().level())?;            // Additional metadata useful for debugging            // They should be nested under `src` (see https://github.com/trentm/node-bunyan#src )            // but `tracing` does not support nested values yet            if self.with_target {                map_serializer.serialize_entry("target", event.metadata().target())?;            }            // map_serializer.serialize_entry("line", &event.metadata().line())?;            // map_serializer.serialize_entry("file", &event.metadata().file())?;            // Add all the other fields associated with the event, expect the message we            // already used.            for (key, value) in event_visitor.values().iter().filter(|(&key, _)| {                key != "message" && !FLOWY_RESERVED_FIELDS.contains(&key) && !IGNORE_FIELDS.contains(&key)            }) {                map_serializer.serialize_entry(key, value)?;            }            // Add all the fields from the current span, if we have one.            if let Some(span) = ¤t_span {                let extensions = span.extensions();                if let Some(visitor) = extensions.get::<JsonStorage>() {                    for (key, value) in visitor.values() {                        if !FLOWY_RESERVED_FIELDS.contains(key) && !IGNORE_FIELDS.contains(key) {                            map_serializer.serialize_entry(key, value)?;                        } else {                            tracing::debug!("{} is a reserved field in the flowy log format. Skipping it.", key);                        }                    }                }            }            map_serializer.end()?;            Ok(buffer)        };        let result: std::io::Result<Vec<u8>> = format();        if let Ok(formatted) = result {            let _ = self.emit(formatted);        }    }    fn new_span(&self, _attrs: &Attributes, id: &Id, ctx: Context<'_, S>) {        let span = ctx.span(id).expect("Span not found, this is a bug");        if let Ok(serialized) = self.serialize_span(&span, Type::EnterSpan) {            let _ = self.emit(serialized);        }    }    fn on_close(&self, id: Id, ctx: Context<'_, S>) {        let span = ctx.span(&id).expect("Span not found, this is a bug");        if let Ok(serialized) = self.serialize_span(&span, Type::ExitSpan) {            let _ = self.emit(serialized);        }    }}
 |