|
14 | 14 | //! [`Level`] field. Each module may have its own Logger or share one. |
15 | 15 |
|
16 | 16 | use bitcoin::secp256k1::PublicKey; |
| 17 | +use tracing::Event; |
| 18 | +use tracing::Subscriber; |
| 19 | +use tracing_subscriber::layer::Context; |
| 20 | +use tracing_subscriber::registry::LookupSpan; |
| 21 | +use tracing_subscriber::Layer; |
17 | 22 |
|
18 | 23 | use core::cmp; |
19 | 24 | use core::fmt; |
@@ -261,6 +266,81 @@ impl<T: fmt::Display, I: core::iter::Iterator<Item = T> + Clone> fmt::Display fo |
261 | 266 | } |
262 | 267 | } |
263 | 268 |
|
| 269 | +/// A tracing `Layer` that forwards tracing events to a given `Logger`. |
| 270 | +pub struct TracingToLogger<L: Deref> |
| 271 | +where |
| 272 | + L::Target: Logger, |
| 273 | +{ |
| 274 | + logger: L, |
| 275 | +} |
| 276 | + |
| 277 | +impl<L: Deref> TracingToLogger<L> |
| 278 | +where |
| 279 | + L::Target: Logger, |
| 280 | +{ |
| 281 | + pub fn new(logger: L) -> Self { |
| 282 | + Self { logger } |
| 283 | + } |
| 284 | +} |
| 285 | + |
| 286 | +impl<S, L> Layer<S> for TracingToLogger<L> |
| 287 | +where |
| 288 | + S: Subscriber + for<'lookup> LookupSpan<'lookup>, |
| 289 | + L: Deref + 'static, |
| 290 | + L::Target: Logger, |
| 291 | +{ |
| 292 | + fn on_event(&self, event: &Event<'_>, _ctx: Context<'_, S>) { |
| 293 | + let meta = event.metadata(); |
| 294 | + let level = *meta.level(); |
| 295 | + |
| 296 | + // Extract the "message" field from the event |
| 297 | + let mut visitor = MessageVisitor::new(); |
| 298 | + event.record(&mut visitor); |
| 299 | + let message = visitor.message.unwrap_or_else(|| "<no message>".to_string()); |
| 300 | + |
| 301 | + self.logger.log(Record::new( |
| 302 | + match level { |
| 303 | + tracing::Level::ERROR => Level::Error, |
| 304 | + tracing::Level::WARN => Level::Warn, |
| 305 | + tracing::Level::INFO => Level::Info, |
| 306 | + tracing::Level::DEBUG => Level::Debug, |
| 307 | + tracing::Level::TRACE => Level::Trace, |
| 308 | + }, |
| 309 | + None, |
| 310 | + None, |
| 311 | + format_args!("{}", message), |
| 312 | + meta.module_path().unwrap_or("<unknown>"), |
| 313 | + meta.file().unwrap_or("<unknown>"), |
| 314 | + meta.line().unwrap_or(0), |
| 315 | + None, |
| 316 | + )); |
| 317 | + } |
| 318 | +} |
| 319 | + |
| 320 | +struct MessageVisitor { |
| 321 | + message: Option<String>, |
| 322 | +} |
| 323 | + |
| 324 | +impl MessageVisitor { |
| 325 | + fn new() -> Self { |
| 326 | + Self { message: None } |
| 327 | + } |
| 328 | +} |
| 329 | + |
| 330 | +impl tracing::field::Visit for MessageVisitor { |
| 331 | + fn record_debug(&mut self, field: &tracing::field::Field, value: &dyn fmt::Debug) { |
| 332 | + if field.name() == "message" { |
| 333 | + self.message = Some(format!("{:?}", value)); |
| 334 | + } |
| 335 | + } |
| 336 | + |
| 337 | + fn record_str(&mut self, field: &tracing::field::Field, value: &str) { |
| 338 | + if field.name() == "message" { |
| 339 | + self.message = Some(value.to_string()); |
| 340 | + } |
| 341 | + } |
| 342 | +} |
| 343 | + |
264 | 344 | #[cfg(test)] |
265 | 345 | mod tests { |
266 | 346 | use crate::ln::types::ChannelId; |
|
0 commit comments