summaryrefslogtreecommitdiff
path: root/debuglog.py
diff options
context:
space:
mode:
Diffstat (limited to 'debuglog.py')
-rw-r--r--debuglog.py77
1 files changed, 77 insertions, 0 deletions
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')