from __future__ import annotations
import argparse
import json
from pathlib import Path
def format_body(value: str | None, limit: int = 180) -> str:
if value is None:
return ""
single = " ".join(value.split())
if len(single) <= limit:
return single
return single[: limit - 1] + "…"
def main() -> int:
parser = argparse.ArgumentParser(prog="http-audit-summary.py")
parser.add_argument("logs", nargs="+", type=Path, help="HTTP audit JSONL logs")
args = parser.parse_args()
seen_domains: set[str] = set()
for log_path in args.logs:
print(f"== {log_path} ==")
if not log_path.is_file():
print("missing")
print()
continue
for line in log_path.read_text(encoding="utf-8").splitlines():
if not line.strip():
continue
event = json.loads(line)
domain = str(event.get("hostname", ""))
if domain:
seen_domains.add(domain)
phase = str(event.get("phase", ""))
if phase == "request":
print(
f"REQ {event.get('method','')} {event.get('url','')} | body={format_body(event.get('body'))}"
)
elif phase == "response":
print(
f"RESP {event.get('status','')} {event.get('url','')} | body={format_body(event.get('body'))}"
)
else:
print(json.dumps(event))
print()
if seen_domains:
print("domains:")
for domain in sorted(seen_domains):
print(f" {domain}")
return 0
if __name__ == "__main__":
raise SystemExit(main())