From f7ed2c69f3840f54bd3e54973821b308a998b063 Mon Sep 17 00:00:00 2001 From: Lars Wirzenius Date: Mon, 25 Mar 2019 09:19:01 +0200 Subject: Add: initial commit --- debuglog.py | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 debuglog.py (limited to 'debuglog.py') diff --git a/debuglog.py b/debuglog.py new file mode 100644 index 0000000..7b34270 --- /dev/null +++ b/debuglog.py @@ -0,0 +1,77 @@ +import collections +import json + + +class DebugLog(object): + + '''Debug logging class. + + The Python standard library contains the library called logging, + which is fine for general purpose logging. For logs meant to help + developers analyse problems, they are less than ideal. + + * Log files are essentially free-form text, with only minimal + structure (timestamps), and that is unreliable to parse when + log messages may contain newlines. + * It is not very efficient. + * Typically, a log grows quite large, making it use a lot of disk + space. This is wasteful when most developers would only need + the end of the log, at the point of a crash, to solve most problems. + (But sometimes the whole log from the whole runtime would be good.) + + This class provides a different kind of logging. The log file is only + written when requested, not continously, and is stored in a ring buffer, + meaning only the last messages are written, with earlier ones forgotten. + This is fine for crash logs. The logs are written in a format that is + easily machine parseable (JSON). + + ''' + + DEFAULT_RING_BUFFER_SIZE = 1000 + + def __init__(self): + self._max_buffer_size = self.DEFAULT_RING_BUFFER_SIZE + self.clear() + + def set_ring_buffer_size(self, num_entries): + self._max_buffer_size = num_entries + while len(self._ring_buffer) > self._max_buffer_size: + self._ring_buffer.popleft() + + def add_to_preamble(self, **kwargs): + self._preamble.append(kwargs) + + def log(self, **kwargs): + self._ring_buffer.append(kwargs) + + def write_ring_buffer(self, filename_or_handle): + + def write(f): + f.write('[\n') + first = True + for q in [self._preamble, self._ring_buffer]: + for entry in q: + if first: + first = False + else: + f.write(',\n') + json.dump(entry, f, indent=4) + f.write('\n]\n') + + if hasattr(filename_or_handle, 'write'): + write(filename_or_handle) + else: + with open(filename_or_handle, 'a') as f: + write(f) + + def clear(self): + self._preamble = collections.deque([], self._max_buffer_size) + self._ring_buffer = collections.deque([], self._max_buffer_size) + + +if __name__ == '__main__': + x = DebugLog() + x.add_to_preamble(version='1.2') + x.log(msg='yoyoyo', url='foobar') + x.log(msg='blahblah', data=123) + x.write_ring_buffer('/dev/stdout') -- cgit v1.2.1