Files
talkscore-asr/app/logbuffer.py
T
Vladimir BryzgalovandClaude Opus 5 710fc8b90b Оценка разделения больше не роняет задачу, журнал доступен через API
Полный трейс показал настоящую причину сбоя: падало не распознавание,
а метрика separation_quality из 0.5.0 - она скармливала модели отпечатков
реплики целиком, и на 190-секундной та не выдержала. Теперь берётся кусок
из середины реплики, а сбой оценки лишь обнуляет её, не трогая расшифровку.

Добавлен /v1/logs: последние записи журнала с фильтром по уровню, чтобы
разбирать сбои без копирования консоли вручную.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-15 23:44:09 +05:00

59 lines
2.1 KiB
Python

"""Кольцевой буфер последних записей журнала.
Нужен, чтобы смотреть логи через API, а не копировать их из окна консоли.
Хранится в памяти: файл на диске пришлось бы чистить, а история глубже
последних сотен строк для разбора сбоя не нужна.
"""
import logging
import threading
from collections import deque
__all__ = ["LogBuffer", "install"]
class LogBuffer(logging.Handler):
def __init__(self, capacity: int = 500):
super().__init__()
self._records: deque = deque(maxlen=capacity)
self._lock = threading.Lock()
def emit(self, record: logging.LogRecord) -> None:
try:
message = record.getMessage()
if record.exc_info:
message += "\n" + self.format(record).split("\n", 1)[-1]
except Exception: # noqa: BLE001 - журнал не должен падать сам
message = "не удалось разобрать запись журнала"
with self._lock:
self._records.append({
"time": record.created,
"level": record.levelname,
"logger": record.name,
"message": message,
})
def tail(self, limit: int = 100, level: str | None = None) -> list[dict]:
with self._lock:
rows = list(self._records)
if level:
wanted = level.upper()
rows = [r for r in rows if r["level"] == wanted]
return rows[-limit:]
_buffer: LogBuffer | None = None
def install(capacity: int = 500) -> LogBuffer:
"""Подключает буфер к корневому журналу. Повторный вызов вернёт тот же буфер."""
global _buffer
if _buffer is None:
_buffer = LogBuffer(capacity)
_buffer.setFormatter(logging.Formatter("%(message)s"))
logging.getLogger().addHandler(_buffer)
return _buffer
def get() -> LogBuffer:
return install()