2626import threading
2727import time
2828import uuid
29+ from datetime import datetime
2930from functools import partial
3031from pathlib import Path
3132from typing import ClassVar
3940logger = logging .getLogger (__name__ )
4041
4142
43+ _G_MONOTIME_DELTA = time .time_ns () - time .monotonic_ns ()
44+ """Approximate delta between monotonic and wall-clock time in nanoseconds. See
45+ monotime_to_datetime() for more details.
46+ """
47+
48+
49+ def monotime_to_datetime (monotime_ns : int ) -> datetime :
50+ """Monotonic clock has an undefined starting point. To convert to human readable timestamp,
51+ we can add a constant delta to any monotonic timestamp to get an approximate equivalent wall-clock
52+ timestamp. Note that the result will not be completely accurate, but it will be a consistent
53+ offset from the real time, as long as this function is called in the same process. Any durations
54+ and deltas calculated from resulting datetimes will be accurate, but absolute times will not be.
55+
56+ Args:
57+ monotime_ns: The monotonic timestamp in nanoseconds.
58+
59+ Returns:
60+ The datetime object corresponding to the approximate wall-clock timestamp.
61+ """
62+ wall_time = (monotime_ns + _G_MONOTIME_DELTA ) / 1e9
63+ return datetime .fromtimestamp (wall_time )
64+
65+
4266@contextlib .contextmanager
4367def sqlite3_cursor (path : Path ):
4468 """Context manager for SQLite cursor that properly handles connection lifecycle.
@@ -272,7 +296,11 @@ def commit_buffer():
272296 if item [1 ] == SampleEvent .FIRST_CHUNK .value :
273297 # In post-processing, we use this to validate that the first chunk is the response output is the same as the data in the FIRST_CHUNK_RECEIVED event
274298 output_buffer .append (
275- {"s_uuid" : item [0 ], "first_chunk" : item [- 1 ]}
299+ {
300+ "timestamp" : str (monotime_to_datetime (item [2 ])),
301+ "s_uuid" : item [0 ],
302+ "first_chunk" : item [- 1 ],
303+ }
276304 )
277305 elif item [1 ] == SampleEvent .COMPLETE .value :
278306 output_data = item [- 1 ]
@@ -282,13 +310,15 @@ def commit_buffer():
282310 )
283311 output_buffer .append (
284312 {
313+ "timestamp" : str (monotime_to_datetime (item [2 ])),
285314 "s_uuid" : item [0 ],
286315 "output" : output_data ,
287316 }
288317 )
289318 elif item [1 ] == SessionEvent .ERROR .value :
290319 output_buffer .append (
291320 {
321+ "timestamp" : str (monotime_to_datetime (item [2 ])),
292322 "s_uuid" : item [0 ],
293323 "error_type" : item [1 ],
294324 "error_message" : item [- 1 ],
0 commit comments