1use std::collections::VecDeque;
4use std::fmt::{self, Debug, Display};
5use std::time::{Duration, Instant};
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
9pub struct TraceLevel(u8);
10
11impl TraceLevel {
12 pub const NONE: TraceLevel = TraceLevel(0);
14 pub const COMMANDS: TraceLevel = TraceLevel(1);
16 pub const MESSAGES: TraceLevel = TraceLevel(2);
18 pub const EVENTS: TraceLevel = TraceLevel(4);
20 pub const METRICS: TraceLevel = TraceLevel(8);
22 pub const ALL: TraceLevel = TraceLevel(15);
24
25 pub fn contains(&self, other: TraceLevel) -> bool {
27 self.0 & other.0 != 0
28 }
29
30 #[must_use]
32 pub fn combine(&self, other: TraceLevel) -> TraceLevel {
33 TraceLevel(self.0 | other.0)
34 }
35
36 pub fn parse(s: &str) -> TraceLevel {
38 let mut level = TraceLevel::NONE;
39 for part in s.split(',') {
40 match part.trim().to_lowercase().as_str() {
41 "commands" | "cmd" => level = level.combine(TraceLevel::COMMANDS),
42 "messages" | "msg" => level = level.combine(TraceLevel::MESSAGES),
43 "events" | "evt" => level = level.combine(TraceLevel::EVENTS),
44 "metrics" | "perf" => level = level.combine(TraceLevel::METRICS),
45 "all" => return TraceLevel::ALL,
46 _ => {}
47 }
48 }
49 level
50 }
51}
52
53impl Default for TraceLevel {
54 fn default() -> Self {
55 TraceLevel::NONE
56 }
57}
58
59#[derive(Debug, Clone)]
61pub enum TraceEvent {
62 CommandStart {
64 id: u64,
66 name: String,
68 timestamp: Instant,
70 },
71 CommandEnd {
73 id: u64,
75 duration: Duration,
77 result: String,
79 },
80 MessageSent {
82 id: u64,
84 message: String,
86 timestamp: Instant,
88 },
89 MessageReceived {
91 id: u64,
93 message: String,
95 timestamp: Instant,
97 },
98 EventProcessed {
100 event_type: String,
102 timestamp: Instant,
104 },
105 FrameRendered {
107 duration: Duration,
109 fps: f32,
111 },
112 Custom {
114 label: String,
116 data: String,
118 },
119}
120
121impl Display for TraceEvent {
122 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
123 match self {
124 TraceEvent::CommandStart { id, name, .. } => {
125 write!(f, "[CMD_START #{:04}] {}", id, name)
126 }
127 TraceEvent::CommandEnd {
128 id,
129 duration,
130 result,
131 } => {
132 write!(f, "[CMD_END #{:04}] {:?} - {}", id, duration, result)
133 }
134 TraceEvent::MessageSent { id, message, .. } => {
135 write!(f, "[MSG_SENT #{:04}] {}", id, message)
136 }
137 TraceEvent::MessageReceived { id, message, .. } => {
138 write!(f, "[MSG_RECV #{:04}] {}", id, message)
139 }
140 TraceEvent::EventProcessed { event_type, .. } => {
141 write!(f, "[EVENT ] {}", event_type)
142 }
143 TraceEvent::FrameRendered { duration, fps } => {
144 write!(f, "[FRAME ] {:?} @ {:.1} FPS", duration, fps)
145 }
146 TraceEvent::Custom { label, data } => {
147 write!(f, "[{}] {}", label, data)
148 }
149 }
150 }
151}
152
153pub struct Tracer {
155 level: TraceLevel,
156 buffer: VecDeque<TraceEvent>,
157 buffer_size: usize,
158 next_id: u64,
159 start_time: Instant,
160}
161
162impl Tracer {
163 pub fn new(level: TraceLevel) -> Self {
165 Self {
166 level,
167 buffer: VecDeque::with_capacity(1000),
168 buffer_size: 1000,
169 next_id: 1,
170 start_time: Instant::now(),
171 }
172 }
173
174 pub fn next_id(&mut self) -> u64 {
176 let id = self.next_id;
177 self.next_id += 1;
178 id
179 }
180
181 pub fn trace(&mut self, event: TraceEvent) {
183 let should_trace = match &event {
185 TraceEvent::CommandStart { .. } | TraceEvent::CommandEnd { .. } => {
186 self.level.contains(TraceLevel::COMMANDS)
187 }
188 TraceEvent::MessageSent { .. } | TraceEvent::MessageReceived { .. } => {
189 self.level.contains(TraceLevel::MESSAGES)
190 }
191 TraceEvent::EventProcessed { .. } => self.level.contains(TraceLevel::EVENTS),
192 TraceEvent::FrameRendered { .. } => self.level.contains(TraceLevel::METRICS),
193 TraceEvent::Custom { .. } => true,
194 };
195
196 if should_trace {
197 let elapsed = self.start_time.elapsed();
199 eprintln!("[{:>8.3}s] {}", elapsed.as_secs_f32(), event);
200
201 if self.buffer.len() >= self.buffer_size {
203 self.buffer.pop_front();
204 }
205 self.buffer.push_back(event);
206 }
207 }
208
209 pub fn get_buffer(&self) -> Vec<TraceEvent> {
211 self.buffer.iter().cloned().collect()
212 }
213
214 pub fn clear_buffer(&mut self) {
216 self.buffer.clear();
217 }
218
219 pub fn flush(&mut self) {
221 }
224}