1use qlog::events::http3::Http3Frame;
28use qlog::events::quic::QuicFrame;
29use qlog::events::EventData;
30use tabled::Table;
31use tabled::Tabled;
32
33use crate::category_and_type_from_event;
34use crate::category_and_type_from_name;
35
36macro_rules! printy {
37 ($k:expr, $value:expr, $s:expr) => {{
38 $s += &format!("{}={}, ", $k, $value);
39 }};
40}
41
42macro_rules! printyo {
43 ($k:expr, $value:expr, $s:expr) => {{
44 if let Some(v) = $value {
45 $s += &format!("{}={}, ", $k, v);
46 }
47 }};
48}
49
50macro_rules! printy_json {
51 ($k:expr, $value:expr, $s:expr) => {{
52 $s += &format!(
53 "{}={}, ",
54 $k,
55 &serde_json::to_string(&$value).unwrap().replace("\"", "")
56 );
57 }};
58}
59
60macro_rules! printyo_json {
61 ($k:expr, $value:expr, $s:expr) => {{
62 if let Some(v) = $value {
63 $s += &format!(
64 "{}={}, ",
65 $k,
66 &serde_json::to_string(&v).unwrap().replace("\"", "")
67 );
68 }
69 }};
70}
71
72#[derive(Debug, Default, Tabled)]
73struct PrintableEvent {
74 pub time: f64,
75 pub category: String,
76 #[tabled(rename = "Type")]
77 pub ty: String,
78 pub details: String,
79}
80
81pub fn frames_to_string(frames: &[QuicFrame]) -> String {
82 let mut s = String::new();
83 for f in frames {
84 match f {
85 QuicFrame::Padding { raw, .. } => {
86 s += &format!(" PADDING {{raw={raw:?}}}");
87 },
88 QuicFrame::Ping { .. } => {
89 s += " PING";
90 },
91 QuicFrame::Ack { acked_ranges, .. } => {
92 s += " ACK {";
93 if let Some(acked_ranges) = acked_ranges {
94 for range in acked_ranges {
95 s += &format!("{}, ", range);
96 }
97 }
98 s += "}";
99 },
100 QuicFrame::ResetStream { stream_id, error, error_code, final_size, .. } => {
101 s += &format!(" RESET_STREAM {{id={stream_id}, error={error:?}, error_code={error_code:?}, final_size={final_size}}}");
102 },
103 QuicFrame::StopSending { stream_id, error, error_code, ..} => {
104 s += &format!(" STOP_SENDING {{id={stream_id}, error={error:?}, error_code={error_code:?}}}");
105 },
106 QuicFrame::Crypto { offset, raw } => {
107 s += &format!(" CRYPTO {{off={offset}, raw={raw:?}}}");
108 },
109 QuicFrame::NewToken { token , ..} => {
110 s += " NEW_TOKEN ";
111 if let Some(ty) = &token.ty {
112 s += &format!("{{ty={ty:?}}}");
113 }
114 },
115 QuicFrame::Stream { stream_id, offset, fin, raw } => {
116 s += &format!(" STREAM {{id={stream_id}, off={offset:?}, raw={raw:?}");
117 if let Some(f) = fin {
118 s += &format!(", fin={f}")
119 }
120 s += "}";
121 },
122 QuicFrame::MaxData { maximum, .. } => {
123 s += &format!(" MAX_DATA {{max={maximum}}}");
124 },
125 QuicFrame::MaxStreamData { stream_id, maximum, .. } => {
126 s += &format!(" MAX_STREAM_DATA {{id={stream_id}, max={maximum}}}");
127 },
128 QuicFrame::MaxStreams { stream_type, maximum, .. } => {
129 s += &format!(" MAX_STREAMS {{ty={stream_type:?}, max={maximum}}}");
130 },
131 QuicFrame::DataBlocked { limit, .. } => {
132 s += &format!(" DATA_BLOCKED {{limit={limit}}}");
133 },
134 QuicFrame::StreamDataBlocked { stream_id, limit, .. } => {
135 s += &format!(" STREAM_DATA_BLOCKED {{id={stream_id}, limit={limit}}}");
136 },
137 QuicFrame::StreamsBlocked { stream_type, limit , ..} => {
138 s += &format!(" STREAMS_BLOCKED {{ty={stream_type:?}, limit={limit}}}");
139 },
140 QuicFrame::NewConnectionId { .. } => {
141 s += " NEW_CONNECTION_ID {{todo='todo'}}";
142 },
143 QuicFrame::RetireConnectionId { sequence_number , ..} => {
144 s += &format!(" RETIRE_CONNECION_ID {{sn={sequence_number}}}");
145 },
146 QuicFrame::PathChallenge { .. } => {
147 s += " PATH_CHALLENGE {{todo='todo'}}";
148 },
149 QuicFrame::PathResponse { .. } => {
150 s += " PATH_RESPONSE {{todo='todo'}}";
151 },
152 QuicFrame::ConnectionClose { error_space, error_code, reason, .. } => {
153 s += " CONNECTION_CLOSE {";
154 if let Some(es) = error_space {
155 s += &format!(" ty={es:?},");
156 }
157 printyo!(" code", error_code, s);
158 printyo!(" reason", reason, s);
159 s += "}";
160 },
161 QuicFrame::HandshakeDone { .. } => {
162 s += " HANDSHAKE_DONE";
163 },
164 QuicFrame::Datagram { raw, .. } => {
165 s += &format!(" DATAGRAM {{raw={raw:?}}}");
166 },
167 QuicFrame::Unknown { frame_type_bytes, .. } => {
168 s += &format!(" UNKNOWN {{frame_type_bytes={frame_type_bytes:?}}}");
169 },
170 }
171 }
172
173 s
174}
175
176fn http_frame_to_string(frame: &Http3Frame) -> String {
177 let mut s = String::new();
178
179 match frame {
180 Http3Frame::Data { raw } =>{
181 s += " DATA";
182 if let Some(r) = raw {
183 printyo!("len", r.length, s);
184 }
185 },
186 Http3Frame::Headers { headers, .. } => {
187 s += " HEADERS {";
188
189 for header in headers {
190 let name = header.name.as_deref().unwrap_or("<binary>");
191 let value = header.value.as_deref().unwrap_or("<binary>");
192 s += &format!("{}: {}, ", name, value);
193 }
194
195 s += "}";
196 },
197 Http3Frame::CancelPush { push_id , ..} => {
198 s += &format!(" CANCEL_PUSH {{id={push_id}}}");
199 },
200 Http3Frame::Settings { ..} => {
201 s += " SETTINGS {{todo}}";
202 }
203 Http3Frame::PushPromise { ..} => {
204 s += " PUSH_PROMISE {{todo}}";
205 }
206 Http3Frame::Goaway { id , ..} => {
207 s += &format!(" GOAWAY {{id={id}}}");
208 }
209 Http3Frame::MaxPushId { push_id , ..} => {
210 s += &format!(" MAX_PUSH_ID {{id={push_id}}}");
211 }
212 Http3Frame::PriorityUpdate { .. } => {
213 s += " PRIORITY_UPDATE {{todo}}";
214 },
215 Http3Frame::Reserved { .. } => {
216 s += " GREASE {{todo}}";
217 },
218 Http3Frame::Unknown { frame_type_bytes, .. } => {
219 s += &format!(" UNKNOWN {{ty={frame_type_bytes}}}");
220 }
221 }
222
223 s
224}
225
226pub fn sqlog_event_list(
227 events: &[qlog::reader::Event],
228) -> tabled::builder::Builder {
229 let mut pp = vec![];
230
231 for event in events {
232 match event {
233 qlog::reader::Event::Qlog(ev) => {
234 let (cat, ty) = category_and_type_from_event(ev);
235
236 let mut p = PrintableEvent {
237 time: ev.time,
238 ty,
239 category: cat,
240 ..Default::default()
241 };
242
243 match &ev.data {
244 EventData::QuicConnectionStarted(v) => {
245 printyo!("local_ip_v4", &v.local.ip_v4, p.details);
246 printyo!("local_port_v4", &v.local.port_v4, p.details);
247 printyo!("local_ip_v6", &v.local.ip_v6, p.details);
248 printyo!("local_port_v6", &v.local.port_v6, p.details);
249 printy!(
250 "local_cids",
251 format!("{:?}", &v.local.connection_ids),
252 p.details
253 );
254 printyo!("remote_ip_v4", &v.remote.ip_v4, p.details);
255 printyo!("remote_port_v4", &v.remote.port_v4, p.details);
256 printyo!("remote_ip_v6", &v.remote.ip_v6, p.details);
257 printyo!("remote_port_v6", &v.remote.port_v6, p.details);
258 printy!(
259 "remote_cid",
260 format!("{:?}", &v.local.connection_ids),
261 p.details
262 );
263 },
264 EventData::QuicConnectionClosed(v) => {
265 printyo_json!("initiator", &v.initiator, p.details);
266 printyo_json!(
267 "connection_code",
268 &v.connection_error,
269 p.details
270 );
271 printyo_json!(
272 "application_error",
273 &v.application_error,
274 p.details
275 );
276 printyo!("internal_code", &v.internal_code, p.details);
277 printyo!("reason", &v.reason, p.details);
278 printyo_json!("trigger", &v.trigger, p.details);
279 },
280 EventData::QuicParametersSet(v) => {
281 printyo_json!("initiator", &v.initiator, p.details);
282 printyo!(
283 "resumption_allowed",
284 &v.resumption_allowed,
285 p.details
286 );
287 printyo!(
288 "early_data_enabled",
289 &v.early_data_enabled,
290 p.details
291 );
292 printyo!("tls_cipher", &v.tls_cipher, p.details);
293 printyo!(
294 "odcid",
295 &v.original_destination_connection_id,
296 p.details
297 );
298 printyo!(
299 "initial_scid",
300 &v.initial_source_connection_id,
301 p.details
302 );
303 printyo!(
304 "retry_scid",
305 &v.retry_source_connection_id,
306 p.details
307 );
308 printyo!(
309 "stateless_reset_token",
310 &v.stateless_reset_token,
311 p.details
312 );
313 printyo!(
314 "disable_active_migration",
315 &v.disable_active_migration,
316 p.details
317 );
318 printyo!(
319 "max_idle_timeout",
320 &v.max_idle_timeout,
321 p.details
322 );
323 printyo!(
324 "max_udp_payload_size",
325 &v.max_udp_payload_size,
326 p.details
327 );
328 printyo!("max_ack_delay", &v.max_ack_delay, p.details);
329 printyo!(
330 "active_connection_id_limit",
331 &v.active_connection_id_limit,
332 p.details
333 );
334 printyo!(
335 "initial_max_data",
336 &v.initial_max_data,
337 p.details
338 );
339 printyo!(
340 "initial_max_stream_data_bidi_local",
341 &v.initial_max_stream_data_bidi_local,
342 p.details
343 );
344 printyo!(
345 "initial_max_stream_data_bidi_remote",
346 &v.initial_max_stream_data_bidi_remote,
347 p.details
348 );
349 printyo!(
350 "initial_max_stream_data_uni",
351 &v.initial_max_stream_data_uni,
352 p.details
353 );
354 printyo!(
355 "initial_max_streams_bidi",
356 &v.initial_max_streams_bidi,
357 p.details
358 );
359 printyo!(
360 "initial_max_streams_uni",
361 &v.initial_max_streams_uni,
362 p.details
363 );
364 printyo_json!(
365 "preferred_address",
366 &v.preferred_address,
367 p.details
368 );
369 },
371 EventData::QuicPacketSent(v) => {
372 p.details +=
373 &serde_json::to_string(&v.header.packet_type)
374 .unwrap()
375 .replace("\"", "");
376 printyo!(" pn", v.header.packet_number, p.details);
377
378 if let Some(frames) = &v.frames {
379 p.details += &frames_to_string(frames);
380 }
381 },
382 EventData::QuicPacketReceived(v) => {
383 p.details +=
384 &serde_json::to_string(&v.header.packet_type)
385 .unwrap()
386 .replace("\"", "");
387 printyo!(" pn", v.header.packet_number, p.details);
388
389 if let Some(frames) = &v.frames {
390 p.details += &frames_to_string(frames);
391 }
392 },
393 EventData::QuicStreamDataMoved(v) => {
394 printyo!("id", v.stream_id, p.details);
395 printyo!("off", v.offset, p.details);
396 if let Some(raw) = &v.raw {
397 printyo!("len", raw.length, p.details);
398 }
399 printyo_json!("from", &v.from, p.details);
400 printyo_json!("to", &v.to, p.details);
401 },
402 EventData::QuicMetricsUpdated(v) => {
403 printyo!("min_rtt", v.min_rtt, p.details);
404 printyo!("smoothed_rtt", v.smoothed_rtt, p.details);
405 printyo!("latest_rtt", v.latest_rtt, p.details);
406 printyo!("rtt_variance", v.rtt_variance, p.details);
407 printyo!("pto_count", v.pto_count, p.details);
408 printyo!("cwnd", v.congestion_window, p.details);
409 printyo!("bytes_in_flight", v.bytes_in_flight, p.details);
410 printyo!("ssthresh", v.ssthresh, p.details);
411 printyo!(
412 "packets_in_flight",
413 v.packets_in_flight,
414 p.details
415 );
416 printyo!("pacing_rate", v.pacing_rate, p.details);
417 },
418 EventData::Http3StreamTypeSet(ev) => {
419 printy!("id", &ev.stream_id, p.details);
420 printyo_json!("initiator", &ev.initiator, p.details);
421 printy_json!("ty", &ev.stream_type, p.details);
422 },
423 EventData::Http3FrameCreated(v) => {
424 printy!("id", v.stream_id, p.details);
425 printyo!("len", v.length, p.details);
426 p.details += &http_frame_to_string(&v.frame);
427 },
428 EventData::Http3FrameParsed(v) => {
429 printy!("id", v.stream_id, p.details);
430 printyo!("len", v.length, p.details);
431 p.details += &http_frame_to_string(&v.frame);
432 },
433
434 _ => {
435 p.details += &serde_json::to_string(&ev.data).unwrap();
436 },
437 }
438
439 pp.push(p);
440 },
441
442 qlog::reader::Event::Json(ev) => {
443 let (cat, ty) = category_and_type_from_name(&ev.name);
444
445 let p = PrintableEvent {
446 time: ev.time,
447 ty,
448 category: cat,
449 details: serde_json::to_string(&ev.data).unwrap(),
450 };
451
452 pp.push(p);
453 },
454 }
455 }
456
457 Table::builder(pp)
458}