]> gitweb.michael.orlitzky.com - djbdns-logparse.git/blobdiff - bin/djbdns-logparse.py
bin/djbdns-logparse.py: add doctest for parse_logfile().
[djbdns-logparse.git] / bin / djbdns-logparse.py
index 5067116cce5acec4c12e7bbbf3f337314643dc65..067d9b17749cbc87b9b786dcb11f4054cb68ba79 100755 (executable)
@@ -3,7 +3,7 @@
 Convert tinydns and dnscache logs to human-readable form
 """
 
-import re
+import re, typing
 from struct import pack
 from time import strftime, gmtime
 from subprocess import Popen, PIPE
@@ -247,7 +247,31 @@ def handle_tinydns_log(line : str, match: re.Match):
                % (code, ip, port, id, type, name))
 
 
-def parse_logfile(file):
+def parse_logfile(file : typing.TextIO):
+    r"""
+    Process a single log ``file``.
+
+    Parameters
+    ----------
+
+    file : typing.TextIO
+        An open log file, or stdin.
+
+    Examples
+    --------
+
+        >>> line = "@4000000063227a320c4f3114 7f000001:9d61:be69 - 0001 www.example.com\n"
+        >>> from tempfile import NamedTemporaryFile
+        >>> with NamedTemporaryFile(mode="w", delete=False) as f:
+        ...     _ = f.write(line)
+        >>> f = open(f.name, 'r')
+        >>> parse_logfile(f)
+        2022-09-14 21:04:40.206516500 dropped query (no authority) from 127.0.0.1:40289 (id 48745): a www.example.com
+        >>> f.close()
+        >>> from os import remove
+        >>> remove(f.name)
+
+    """
     # Open pipe to tai64nlocal: we will write lines of our input (the
     # raw log file) to it, and read log lines with readable timestamps
     # from it.
@@ -285,12 +309,19 @@ def main():
                         default=[stdin],
                         help="djbdns logfile to process (default: stdin)")
 
+    # Warning: argparse automatically opens its file arguments here,
+    # and they only get closed when the program terminates. There's no
+    # real benefit to closing them one-at-a-time after calling
+    # parse_logfile(), because the "scarce" resource of open file
+    # descriptors gets consumed immediately, before any processing has
+    # happened. In other words, if you're going to run out of file
+    # descriptors, it's going to happen right now.
+    #
+    # So anyway, don't run this on several million logfiles.
     args = parser.parse_args()
     for f in args.logfiles:
         parse_logfile(f)
 
 
-
-
 if __name__ == "__main__":
     main()