From cee518f4233bb700962197243c245d3eac4c17c9 Mon Sep 17 00:00:00 2001 From: Hermes Lab Date: Sun, 5 Jul 2026 11:17:26 -0700 Subject: [PATCH] Optimize log buffer tail reads --- app/log_buffer.py | 8 ++++---- tests/test_log_buffer.py | 21 +++++++++++++++++++++ 2 files changed, 25 insertions(+), 4 deletions(-) create mode 100644 tests/test_log_buffer.py diff --git a/app/log_buffer.py b/app/log_buffer.py index 1d9ec8f..583ccab 100644 --- a/app/log_buffer.py +++ b/app/log_buffer.py @@ -2,6 +2,7 @@ In-memory log buffer for AI engine output. Used to stream live logs to frontend. """ from datetime import datetime +from itertools import islice from typing import List, Literal from collections import deque @@ -32,10 +33,9 @@ def clear() -> None: def get_logs(limit: int = 500) -> List[dict]: """Return last `limit` log entries, newest last.""" - items = list(_buffer) - if limit and len(items) > limit: - items = items[-limit:] - return items + if not limit or limit >= len(_buffer): + return list(_buffer) + return list(reversed(list(islice(reversed(_buffer), limit)))) def get_logs_response(running: bool) -> dict: diff --git a/tests/test_log_buffer.py b/tests/test_log_buffer.py new file mode 100644 index 0000000..4978d16 --- /dev/null +++ b/tests/test_log_buffer.py @@ -0,0 +1,21 @@ +from app import log_buffer + + +def test_get_logs_returns_tail_in_order(): + log_buffer.clear() + for index in range(10): + log_buffer.emit("tick", f"message {index}") + + logs = log_buffer.get_logs(limit=3) + + assert [entry["message"] for entry in logs] == ["message 7", "message 8", "message 9"] + + +def test_get_logs_zero_limit_preserves_existing_all_logs_behavior(): + log_buffer.clear() + for index in range(3): + log_buffer.emit("tick", f"message {index}") + + logs = log_buffer.get_logs(limit=0) + + assert [entry["message"] for entry in logs] == ["message 0", "message 1", "message 2"]