|
1 | 1 | use serde::{de::Error, Deserialize, Serialize}; |
| 2 | +use std::collections::BTreeMap; |
2 | 3 | use std::io::Write; |
3 | 4 |
|
4 | 5 | pub mod decode; |
@@ -91,34 +92,62 @@ where |
91 | 92 | } |
92 | 93 | } |
93 | 94 |
|
94 | | -// new_tracing_dispatch_handler returns a log handler that |
95 | | -// writes tracing events using the given dispatcher. |
96 | | -pub fn new_tracing_dispatch_handler( |
97 | | - dispatcher: ::tracing::Dispatch, |
98 | | -) -> impl Fn(&Log) + Send + Sync + Clone + 'static { |
99 | | - move |log| ::tracing::dispatcher::with_default(&dispatcher, || tracing_log_handler(log)) |
100 | | -} |
101 | | - |
102 | 95 | /// tracing_log_handler is a log handler that writes logs |
103 | 96 | /// as tracing events. |
104 | 97 | pub fn tracing_log_handler( |
105 | 98 | Log { |
106 | 99 | level, |
107 | | - fields_json_map: fields, |
| 100 | + fields_json_map, |
108 | 101 | message, |
109 | 102 | .. |
110 | 103 | }: &Log, |
111 | 104 | ) { |
| 105 | + let fields = DebugJson( |
| 106 | + fields_json_map |
| 107 | + .iter() |
| 108 | + .map(|(k, v)| { |
| 109 | + ( |
| 110 | + k.clone(), |
| 111 | + serde_json::value::RawValue::from_string(v.clone()).unwrap(), |
| 112 | + ) |
| 113 | + }) |
| 114 | + .collect::<BTreeMap<_, _>>(), |
| 115 | + ); |
| 116 | + |
112 | 117 | match LogLevel::from_i32(*level).unwrap_or_default() { |
113 | | - LogLevel::Trace => ::tracing::trace!(?fields, message), |
114 | | - LogLevel::Debug => ::tracing::debug!(?fields, message), |
115 | | - LogLevel::Info => ::tracing::info!(?fields, message), |
116 | | - LogLevel::Warn => ::tracing::warn!(?fields, message), |
117 | | - LogLevel::Error => ::tracing::error!(?fields, message), |
| 118 | + LogLevel::Trace => ::tracing::trace!(message, ?fields), |
| 119 | + LogLevel::Debug => ::tracing::debug!(message, ?fields), |
| 120 | + LogLevel::Info => ::tracing::info!(message, ?fields), |
| 121 | + LogLevel::Warn => ::tracing::warn!(message, ?fields), |
| 122 | + LogLevel::Error => ::tracing::error!(message, ?fields), |
118 | 123 | LogLevel::UndefinedLevel => (), |
119 | 124 | } |
120 | 125 | } |
121 | 126 |
|
| 127 | +/// DebugJson is a new-type wrapper around any Serialize implementation |
| 128 | +/// that wishes to support the Debug trait via JSON encoding itself. |
| 129 | +/// If stderr is a terminal, it colorizes and styles its output for legibility. |
| 130 | +pub struct DebugJson<S: Serialize>(pub S); |
| 131 | + |
| 132 | +impl<S: Serialize> std::fmt::Debug for DebugJson<S> { |
| 133 | + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
| 134 | + use colored_json::{ColorMode, ColoredFormatter, CompactFormatter, Output, Styler}; |
| 135 | + |
| 136 | + let value = ColoredFormatter::with_styler( |
| 137 | + CompactFormatter {}, |
| 138 | + // This can be customized, but it's default already matches `jq` 👍. |
| 139 | + Styler::default(), |
| 140 | + ) |
| 141 | + .to_colored_json( |
| 142 | + &serde_json::to_value(&self.0).unwrap(), |
| 143 | + ColorMode::Auto(Output::StdErr), |
| 144 | + ) |
| 145 | + .unwrap(); |
| 146 | + |
| 147 | + f.write_str(&value) |
| 148 | + } |
| 149 | +} |
| 150 | + |
122 | 151 | #[cfg(test)] |
123 | 152 | mod test { |
124 | 153 | use super::{Log, LogLevel}; |
|
0 commit comments