rotate-log.py 1.4 KB

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