[object Object]

← back to Exo

add log rotation for .exo/exo.log (#1438)

009b43c662fd33c210bad90e7c432ae3e9c73505 · 2026-02-10 18:55:06 +0000 · rltakashige

## Motivation

.exo.log currently contains all past history. This just makes it hard to
read and is unnecessarily expensive even on disk.

## Why It Works

Just uses loguru's rotation.

## Test Plan

### Manual Testing
exo.log is new. 
<img width="1992" height="706" alt="image"
src="https://github.com/user-attachments/assets/9b293993-1141-43e7-b58e-0ddd2d4eda2e"
/>

Files touched

Diff

commit 009b43c662fd33c210bad90e7c432ae3e9c73505
Author: rltakashige <rl.takashige@gmail.com>
Date:   Tue Feb 10 18:55:06 2026 +0000

    add log rotation for .exo/exo.log (#1438)
    
    ## Motivation
    
    .exo.log currently contains all past history. This just makes it hard to
    read and is unnecessarily expensive even on disk.
    
    ## Why It Works
    
    Just uses loguru's rotation.
    
    ## Test Plan
    
    ### Manual Testing
    exo.log is new.
    <img width="1992" height="706" alt="image"
    src="https://github.com/user-attachments/assets/9b293993-1141-43e7-b58e-0ddd2d4eda2e"
    />
---
 src/exo/shared/logging.py | 24 +++++++++++++++++++++++-
 1 file changed, 23 insertions(+), 1 deletion(-)

diff --git a/src/exo/shared/logging.py b/src/exo/shared/logging.py
index a42864e7..e08fe2c5 100644
--- a/src/exo/shared/logging.py
+++ b/src/exo/shared/logging.py
@@ -1,11 +1,30 @@
 import logging
 import sys
+from collections.abc import Iterator
 from pathlib import Path
 
+import zstandard
 from hypercorn import Config
 from hypercorn.logging import Logger as HypercornLogger
 from loguru import logger
 
+_MAX_LOG_ARCHIVES = 5
+
+
+def _zstd_compress(filepath: str) -> None:
+    source = Path(filepath)
+    dest = source.with_suffix(source.suffix + ".zst")
+    cctx = zstandard.ZstdCompressor()
+    with open(source, "rb") as f_in, open(dest, "wb") as f_out:
+        cctx.copy_stream(f_in, f_out)
+    source.unlink()
+
+
+def _once_then_never() -> Iterator[bool]:
+    yield True
+    while True:
+        yield False
+
 
 class InterceptLogger(HypercornLogger):
     def __init__(self, config: Config):
@@ -53,13 +72,16 @@ def logger_setup(log_file: Path | None, verbosity: int = 0):
             enqueue=True,
         )
     if log_file:
+        rotate_once = _once_then_never()
         logger.add(
             log_file,
             format="[ {time:YYYY-MM-DD HH:mm:ss.SSS} | {level: <8} | {name}:{function}:{line} ] {message}",
             level="INFO",
             colorize=False,
             enqueue=True,
-            rotation="1 week",
+            rotation=lambda _, __: next(rotate_once),
+            retention=_MAX_LOG_ARCHIVES,
+            compression=_zstd_compress,
         )
 
 

← 1f242e8e gossipsub: stop silent message dropping and warn (#1434)  ·  back to Exo  ·  standardise logs (#1442) 1699fcfb →