Новый модуль trace

This commit is contained in:
2026-03-03 10:41:39 +03:00
parent 1b287a9550
commit 0f984fa42a
13 changed files with 614 additions and 7 deletions

149
README.md
View File

@@ -1,6 +1,11 @@
# Config Manager
## Описание
Пакет предназначен для запуска приложений с периодическим выполнением логики, перезагрузкой конфига и управлением по HTTP API.
Пакет предназначен как базовое приложение для проектов, в которых нужно периодически запускать одну и ту же функцию в одном потоке, с возможностью перезагрузки конфига и сервисным контуром вокруг прикладной логики.
Под сервисным контуром здесь понимаются:
- логирование;
- трассировка бизнес-процессов и связанных сущностей;
- управление приложением через каналы управления (например, HTTP API).
**Контракт:** приложение наследует **ConfigManagerV2**, переопределяет **execute()** (периодическая работа). Управление (старт/стоп, health) — через каналы, которые создаются снаружи и передаются в конструктор в **control_channels** (в т.ч. HttpControlChannel для API).
@@ -12,6 +17,7 @@
- **ConfigLoader** — читает конфиг из файла (YAML/JSON), считает хеш и отдаёт конфиг только при изменении; при ошибке парсинга возвращает последний валидный конфиг.
- **WorkerLoop** — в отдельном потоке циклически вызывает ваш метод `execute()` с паузой между вызовами; реагирует на событие остановки и колбэки успеха/ошибки.
- **LogManager** — применяет секцию `log` из конфига к логированию (dictConfig).
- **TraceManager** — управляет структурированной трассировкой процессов, контекстов и сообщений.
- **HealthAggregator** — собирает состояние: жизненный цикл (idle/starting/running/…), время последнего успешного `execute()` и таймаут здоровья; формирует единый ответ для health (ok/unhealthy).
- **ControlChannelBridge** — один мост для всех каналов: обработчики on_start/on_stop/on_status (сброс/установка halt, текст статуса).
@@ -134,6 +140,54 @@ classDiagram
+apply_config(config) None
}
class TraceManager {
+bind_context(alias, parent_id, type, attrs) str
+open_context(alias, parent_id, type, attrs) contextmanager
+current_trace_id() str
+step(name) None
+info(message, status, attrs) None
+warning(message, status, attrs) None
+error(message, status, attrs) None
}
class TraceContextStore {
+current() ActiveTraceContext
+current_trace_id() str
+push(record) ActiveTraceContext
+pop() ActiveTraceContext
+set_step(step) ActiveTraceContext
}
class TraceContextRecord {
+str trace_id
+str parent_id
+str alias
+str type
+datetime event_time
+dict attrs
}
class TraceLogMessage {
+str trace_id
+str step
+str status
+str level
+str message
+datetime event_time
+dict attrs
}
class TraceTransport {
<<protocol>>
+write_context(record) None
+write_message(record) None
}
class MySqlTraceTransport {
+write_context(record) None
+write_message(record) None
}
class ControlChannel {
<<абстрактный>>
+start(on_start, on_stop, on_status) async*
@@ -182,10 +236,16 @@ classDiagram
ConfigManagerV2 --|> _RuntimeController : наследует
ConfigManagerV2 --> ConfigLoader : использует
ConfigManagerV2 --> LogManager : использует
ConfigManagerV2 --> TraceManager : использует
ConfigManagerV2 --> HealthAggregator : использует
ConfigManagerV2 --> ControlChannelBridge : использует
ConfigManagerV2 ..> ControlChannel : список каналов
_RuntimeController ..> WorkerLoop : создаёт в _worker_loop
TraceManager --> TraceContextStore : использует
TraceManager --> TraceTransport : использует
TraceManager ..> TraceContextRecord : создаёт
TraceManager ..> TraceLogMessage : создаёт
MySqlTraceTransport --|> TraceTransport : реализует
TelegramControlChannel --|> ControlChannel : реализует
HttpControlChannel --|> ControlChannel : реализует
HttpControlChannel --> UvicornServerRunner : использует
@@ -246,10 +306,95 @@ sequenceDiagram
- Убедитесь, что в конфиге есть ключ `log` с `version: 1`, `handlers` и `loggers` (пример — `tests/config.yaml`).
- После старта в логе должно появиться сообщение уровня INFO: `"Logging configuration applied"` (из `config_manager.v2.core.log_manager`). Если его нет, либо секция `log` отсутствует (будет предупреждение), либо уровень root/пакета выше INFO.
## Trace
Модуль `trace` предназначен для структурированной трассировки прикладных процессов и иерархически связанных сущностей.
Базовая идея:
- есть `TraceContextRecord` — логический контекст, который группирует сообщения;
- есть `TraceLogMessage` — отдельное событие внутри текущего контекста;
- контексты могут быть вложенными: один родительский контекст и много дочерних;
- активный контекст хранится в `TraceContextStore`, а при выходе из дочернего `with` автоматически восстанавливается родитель.
### Архитектура
Основные части модуля:
- `TraceManager` — публичный API для приложений;
- `TraceContextStore` — хранение активного контекста и стека вложенности;
- `TraceContextRecord` — описание контекста;
- `TraceLogMessage` — описание сообщения;
- `TraceTransport` — интерфейс транспорта;
- `MySqlTraceTransport` — запись контекстов и сообщений в MySQL.
Сущности:
`TraceContextRecord`
- `trace_id`
- `parent_id`
- `alias`
- `type`
- `event_time`
- `attrs`
`TraceLogMessage`
- `trace_id`
- `event_time`
- `step`
- `status`
- `level`
- `message`
- `attrs`
### Принцип использования
1. На старте процесса создаётся контекст через `bind_context()` или `open_context()`.
2. Для серии сообщений выставляется текущий `step()`.
3. Сообщения пишутся через `info()/warning()/error()/exception()`.
4. При использовании `open_context()` дочерний контекст автоматически закрывается по выходу из `with`, а родительский становится текущим снова.
### Пример: корневой контекст
```python
from config_manager.v2.trace import TraceManager
trace = TraceManager()
trace_id = trace.bind_context(
alias="job-123",
type="task",
attrs={"source": "scheduler"},
)
trace.step("prepare")
trace.info("Подготовка завершена", status="completed", attrs={"items_count": 2})
```
### Пример: дочерний контекст
```python
with trace.open_context(
alias="subtask-1",
type="subtask",
parent_id=trace_id,
attrs={"segment": "phase-a"},
) as child_trace_id:
trace.step("execute")
trace.info("Подзадача запущена", status="started")
trace.info("Подзадача завершена", status="completed", attrs={"duration_ms": 120})
# Здесь снова активен родительский контекст
trace.step("finish")
trace.info("Обработка завершена", status="completed")
```
### Хранение в MySQL
Для MySQL предусмотрен `MySqlTraceTransport`. Он пишет две сущности в отдельные таблицы:
- `trace_contexts`
- `trace_messages`
Это позволяет:
- отдельно хранить структуру процесса;
- отдельно хранить историю шагов и сообщений;
- строить отчёты и трассировку без завязки на `logging`.
## Установка
``pip install git+https://git.lesha.spb.ru/alex/config_manager.git``
## Контакты
- **e-mail**: lesha.spb@gmail.com
- **telegram**: https://t.me/lesha_spb