"""logreport — a deliberately legacy log summariser, kept as the subject of a tutorial. What it does Reads log lines shaped like 2026-09-05 14:03:11 ERROR auth: token expired user=42 counts lines per level, remembers the first and last timestamp seen, warns on malformed lines, and prints a short report. Inputs python add-tests-to-a-legacy-script-with-an-agent.py or, from Python, run(lines, out) where `lines` is any iterable of strings and `out` is a text stream. run() is the seam added for testing; the module-level globals it resets are the original design. Known quirks (deliberately preserved; the characterization tests pin them) * Dates are re-formatted to DD/MM/YY by string slicing. * "first" and "last" are chosen by comparing the DD/MM/YY strings, so the answer is wrong whenever the log crosses a month or year boundary. This is the latent bug the tutorial leaves in place. * Level names are matched case-sensitively; "error" and "ERROR" count apart. Tests: python -m unittest add-tests-to-a-legacy-script-with-an-agent_test.py Python 3.13, standard library only. """ import sys COUNTS = {} FIRST = None LAST = None BAD = 0 TOTAL = 0 def fmt_date(iso): # 2026-09-05 -> 05/09/26 return iso[8:10] + "/" + iso[5:7] + "/" + iso[2:4] def parse_line(line, out=sys.stdout): global FIRST, LAST, BAD, TOTAL TOTAL += 1 parts = line.rstrip("\n").split(" ", 3) if len(parts) < 4 or len(parts[0]) != 10 or len(parts[1]) != 8: BAD += 1 print("WARN skipping line %d: %r" % (TOTAL, line.rstrip("\n")), file=out) return stamp = fmt_date(parts[0]) + " " + parts[1] level = parts[2] COUNTS[level] = COUNTS.get(level, 0) + 1 if FIRST is None or stamp < FIRST: FIRST = stamp if LAST is None or stamp > LAST: LAST = stamp def report(out=sys.stdout): print("lines: %d (skipped %d)" % (TOTAL, BAD), file=out) for level in sorted(COUNTS, key=lambda k: (-COUNTS[k], k)): print(" %-8s %d" % (level, COUNTS[level]), file=out) if FIRST is not None: print("first: " + FIRST, file=out) print("last: " + LAST, file=out) def reset(): global COUNTS, FIRST, LAST, BAD, TOTAL COUNTS = {} FIRST = None LAST = None BAD = 0 TOTAL = 0 def run(lines, out=sys.stdout): """Seam: process `lines` and write the report to `out`. Resets the globals first.""" reset() for line in lines: parse_line(line, out) report(out) def main(argv): if len(argv) != 2: print("usage: logreport ", file=sys.stderr) return 1 with open(argv[1], encoding="utf-8") as fh: run(fh) return 0 if __name__ == "__main__": sys.exit(main(sys.argv))