1use serde::Serialize;
8use std::collections::VecDeque;
9use std::sync::{Arc, Mutex};
10use tracing::Subscriber;
11use tracing_subscriber::Layer;
12
13const MAX_LOG_ENTRIES: usize = 1000;
14
15#[derive(Debug, Clone, Serialize)]
16pub struct LogEntry {
17 pub timestamp: String,
18 pub level: String,
19 pub message: String,
20}
21
22#[derive(Clone, Debug)]
23pub struct InMemoryLogStore {
24 pub entries: Arc<Mutex<VecDeque<LogEntry>>>,
25}
26
27impl Default for InMemoryLogStore {
28 fn default() -> Self {
29 Self::new()
30 }
31}
32
33impl InMemoryLogStore {
34 pub fn new() -> Self {
35 Self {
36 entries: Arc::new(Mutex::new(VecDeque::with_capacity(MAX_LOG_ENTRIES))),
37 }
38 }
39}
40
41pub struct InMemoryLoggerLayer {
42 store: InMemoryLogStore,
43}
44
45impl InMemoryLoggerLayer {
46 pub fn new(store: InMemoryLogStore) -> Self {
47 Self { store }
48 }
49}
50
51struct LogVisitor {
53 message: String,
54}
55
56impl tracing::field::Visit for LogVisitor {
57 fn record_debug(&mut self, field: &tracing::field::Field, value: &dyn std::fmt::Debug) {
58 if field.name() == "message" {
59 self.message = format!("{:?}", value);
60 }
61 }
62}
63
64impl<S> Layer<S> for InMemoryLoggerLayer
65where
66 S: Subscriber,
67{
68 fn on_event(
69 &self,
70 event: &tracing::Event<'_>,
71 _ctx: tracing_subscriber::layer::Context<'_, S>,
72 ) {
73 let mut visitor = LogVisitor {
74 message: String::new(),
75 };
76 event.record(&mut visitor);
77
78 let metadata = event.metadata();
79 let entry = LogEntry {
80 timestamp: chrono::Utc::now().to_rfc3339(),
81 level: metadata.level().to_string(),
82 message: visitor.message,
83 };
84
85 if let Ok(mut entries) = self.store.entries.lock() {
86 if entries.len() >= MAX_LOG_ENTRIES {
87 entries.pop_front();
88 }
89 entries.push_back(entry);
90 }
91 }
92}