rotate-log.py 1.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354
  1. #!/usr/bin/env python3
  2. from __future__ import annotations
  3. import os
  4. import sys
  5. import time
  6. from pathlib import Path
  7. def rotate(path: Path, backups: int) -> None:
  8. if backups <= 0:
  9. path.write_text("")
  10. return
  11. oldest = path.with_name(f"{path.name}.{backups}")
  12. if oldest.exists():
  13. oldest.unlink()
  14. for index in range(backups - 1, 0, -1):
  15. source = path.with_name(f"{path.name}.{index}")
  16. target = path.with_name(f"{path.name}.{index + 1}")
  17. if source.exists():
  18. source.replace(target)
  19. if path.exists():
  20. path.replace(path.with_name(f"{path.name}.1"))
  21. def main() -> int:
  22. if len(sys.argv) != 4:
  23. print("usage: rotate-log.py <log_path> <max_bytes> <backups>", file=sys.stderr)
  24. return 1
  25. log_path = Path(sys.argv[1])
  26. max_bytes = int(sys.argv[2])
  27. backups = int(sys.argv[3])
  28. log_path.parent.mkdir(parents=True, exist_ok=True)
  29. log_path.touch(exist_ok=True)
  30. stream = sys.stdin.buffer
  31. while True:
  32. chunk = stream.readline()
  33. if not chunk:
  34. break
  35. chunk = f"[{int(time.time() * 1000)}] ".encode() + chunk
  36. with log_path.open("ab") as handle:
  37. handle.write(chunk)
  38. try:
  39. if log_path.stat().st_size > max_bytes:
  40. rotate(log_path, backups)
  41. log_path.touch(exist_ok=True)
  42. except FileNotFoundError:
  43. log_path.touch(exist_ok=True)
  44. return 0
  45. if __name__ == "__main__":
  46. raise SystemExit(main())