English translation is not available yet. Showing Russian content.
Настроить distributed tracing через OpenTelemetry
ТЕХНИЧЕСКОЕ ЗАДАНИЕ: Настроить distributed tracing через OpenTelemetry
1. Цель задачи
Разработать и развернуть систему распределённого трассирования (distributed tracing) для многокомпонентной агентной системы с использованием OpenTelemetry. В результате инженер получит визуализацию потоков выполнения меж-агентного взаимодействия, сможет измерять latency отдельных вызовов и отслеживать ошибки. Ключевой результат работающий дашборд в Grafana, который показывает задержки (latency) и частоту ошибок (errors) для ключевых операций агентов.
2. Исходные данные
| Что нужно | Откуда взять |
|---|---|
| Агентная система (рабочая или тестовая) | Собранный пет-проект (например, Multi-Agent Assistant на LangChain/AutoGen) или существующая система с вызовами между агентами |
| OpenTelemetry SDK (Python) | pip install opentelemetry-api opentelemetry-sdk opentelemetry-exporter-jaeger |
| Jaeger (хранилище трейсов и UI) | Docker-образ jaegertracing/all-in-one:1.60 |
| Grafana (визуализация) | Docker-образ grafana/grafana:latest |
| OpenTelemetry Collector (опционально) | otel/opentelemetry-collector-contrib:0.108.0 (может быть пропущен) |
| Готовый дашборд для Jaeger в Grafana | JSON-экспорт из дашбордов сообщества или создание с нуля |
Если нет реального инструмента — симулируем:
- Создать простой агент на Python, который обращается к LLM (например, через dummy-функцию, возвращающую фиксированный ответ) и выполняет цепочку вызовов нескольких суб-агентов.
- Каждый вызов обёрнуть в span с помощью OpenTelemetry.
- Запустить Jaeger и Grafana на локальной машине через Docker Compose.
3. Технологический стек
| Компонент | Инструменты | Назначение |
|---|---|---|
| Язык программирования | Python 3.11+ | Реализация агента |
| OpenTelemetry SDK | opentelemetry-api, opentelemetry-sdk, opentelemetry-exporter-jaeger | Инструментирование кода, создание и экспорт трейсов |
| Jaeger | Jaeger All-In-One (Docker) | Приём, хранение и визуализация трейсов |
| Grafana | Grafana (Docker) | Построение дашбордов с latency и errors |
| Контейнеризация | Docker + Docker Compose | Запуск Jaeger и Grafana |
| LLM (симуляция) | Fake LLM-класс (возвращает задержку и ошибку с вероятностью) | Имитация реальных вызовов |
| Python-библиотеки | random, time, uvicorn (если веб-сервер), httpx | Генерация трейсов и HTTP-транспорт |
4. Этапы выполнения
Этап 1: Подготовка окружения (30-40 минут)
Действия
- Создать директорию проекта
distributed-tracing-labи инициализировать Poetry / requirements.txt. - Установить зависимости
pip install opentelemetry-api opentelemetry-sdk opentelemetry-exporter-jaeger - Подготовить Docker Compose для Jaeger и Grafana:
version: '3.8' services: jaeger: image: jaegertracing/all-in-one:1.60 ports: - "16686:16686" # UI - "4317:4317" # OTLP gRPC - "4318:4318" # OTLP HTTP environment: - COLLECTOR_OTLP_ENABLED=true grafana: image: grafana/grafana:latest ports: - "3000:3000" environment: - GF_AUTH_ANONYMOUS_ENABLED=true - GF_INSTALL_PLUGINS=jaeger-datasource - Запустить контейнеры docker compose up -d
Ожидаемый результат этапа Jaeger UI доступен на http://localhost:16686, Grafana UI на http://localhost:3000. В Grafana установлен плагин Jaeger.
Этап 2: Инструментирование агентной системы (1–1.5 часа)
Действия
-
Создать Tracer Provider в корневом модуле tracing.py:
from opentelemetry import trace from opentelemetry.exporter.jaeger.thrift import JaegerExporter from opentelemetry.sdk.resources import SERVICE_NAME, Resource from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import BatchSpanProcessor resource = Resource.create({SERVICE_NAME: "multi-agent-system"}) provider = TracerProvider(resource=resource) processor = BatchSpanProcessor(JaegerExporter( agent_host_name="localhost", agent_port=6831, )) provider.add_span_processor(processor) trace.set_tracer_provider(provider) tracer = trace.get_tracer(__name__) -
Написать агент с несколькими этапами:
import time import random class Agent: def __init__(self, name, delay_range=(0.1, 0.5)): self.name = name self.delay_range = delay_range def process(self, input_data): with tracer.start_as_current_span(f"{self.name}.process") as span: span.set_attribute("agent.name", self.name) time.sleep(random.uniform(*self.delay_range)) if random.random() < 0.1: # 10% error span.set_status(trace.Status(trace.StatusCode.ERROR)) raise RuntimeError(f"{self.name} failed") return f"{self.name} processed: {input_data}" -
Создать главный оркестратор
main.py, который вызывает нескольких агентов последовательно:from tracing import tracer from agent import Agent def orchestrate(): with tracer.start_as_current_span("orchestrate") as span: agent_a = Agent("AgentA", delay_range=(0.2, 0.4)) agent_b = Agent("AgentB", delay_range=(0.3, 0.6)) # Последовательный вызов span.add_event("Starting AgentA") result_a = agent_a.process("Task1") span.add_event("Starting AgentB") result_b = agent_b.process(result_a) span.set_attribute("result", result_b) return result_b if __name__ == "__main__": import random random.seed(42) orchestrate() -
Запустить скрипт несколько раз для генерации трейсов: python main.py
Ожидаемый результат этапа В Jaeger UI появляются трейсы с иерархией спанов orchestrate → AgentA.process → AgentB.process. Видны задержки и метки ошибок.
Этап 3: Подключение к Grafana (30–40 минут)
Действия
- Войти в Grafana (login: admin/admin, при первом входе пропустить смену пароля или указать свои).
- Добавить источник данных Jaeger
- Установить дашборд (опционально): импортировать готовый шаблон
13323(Jaeger System Dashboard) из сообщества. - Создать простой дашборд вручную
Ожидаемый результат этапа В Grafana отображаются трейсы, можно просматривать отдельные spans.
Этап 4: Построение дашборда latency и errors (45–60 минут)
Действия
-
Добавить панель «Latency»:
- Тип: Time series.
- Query: {service_name="multi-agent-system"} → метрика
trace:span:duration_seconds(через Prometheus style, если настроен OTel Collector) или используйте встроенные переменные Grafana для Jaeger. Примечание: для метрик latency проще всего использовать экспорт в Prometheus через OTel Collector. На этом этапе допустимо использовать Jaeger’s built-in metrics (Grafana плагин Jaeger поддерживает метрики из трейсов). - Альтернативно: добавить панель Trace list, отфильтрованную по service, и визуализировать среднее время выполнения.
-
Добавить панель «Error rate»:
-
Создать переменные дашборда (опционально):
-
Настроить временной диапазон (последние 15 минут или 1 час).
-
Сохранить дашборд с именем «Multi-Agent Tracing».
Ожидаемый результат этапа Дашборд показывает:
- График latency по спанам с процентилями (p50, p95, p99).
- График error rate в процентах или absolute count.
- Возможность drill-down до конкретного трейса.
Этап 5: Тестирование и верификация (20–30 минут)
Действия
- Запустить скрипт многократно (например, 50 раз) с разными seed, чтобы накопить данные.
- Проверить Grafana-дашборд визуально убедиться, что latency колеблется, ошибки видны (около 10%).
- Проверить Jaeger UI найти трейс с ошибкой, посмотреть атрибуты спана.
- Экспортировать дашборд (JSON) в файл
grafana-dashboard.jsonдля сохранения в репозитории. - Закоммитить код, Docker Compose и дашборд в Git.
Ожидаемый результат этапа Полная воспроизводимость: docker compose up + python main.py даёт трейсы, дашборд отображается без дополнительных настроек.
5. Критерии приемки (Definition of Done)
- В Jaeger UI видны трейсы с иерархией спанов от оркестратора к суб-агентам.
- Каждый span содержит атрибуты (имя агента, результат, статус).
- Ошибочные спаны помечены статусом
ERRORи отображаются в Jaeger. - В Grafana настроен источник данных Jaeger.
- Создан дашборд с панелями «Latency» (хотя бы p95) и «Error rate».
- Дашборд экспортирован в JSON и добавлен в репозиторий.
- Docker Compose поднимает оба сервиса (Jaeger, Grafana) без ошибок.
- Код агента содержит инструкции по инструментированию (обёртка span).
- При запуске
main.pyтрейсы отправляются в Jaeger без потерь (все вызовы зафиксированы).
6. Ожидаемый результат
Основные артефакты
tracing.py— конфигурация TracerProvider и экспортёра.agent.py— класс агента с созданием вложенных спанов.main.py— оркестратор, запускающий цепочку вызовов.docker-compose.yml— описание Jaeger + Grafana.grafana-dashboard.json— экспорт дашборда.
Содержимое дашборда панели latency (гистограмма/график) и error rate (процент/число) с возможностью фильтрации по сервису и операции.
Дополнительно инструкция README.md с шагами запуска.
7. Возможные сложности и их решение
| Сложность | Решение |
|---|---|
| Jaeger не принимает трейсы (ошибка подключения) | Проверить порты в Docker Compose, использовать gRPC (4317) вместо Thrift compact. В JaegerExporter указать agent_host_name="localhost" и agent_port=6831 (Thrift UDP) или collector_endpoint="http://localhost:14268/api/traces" (HTTP). |
| Трейсы не отображаются в Jaeger UI | Убедиться, что resource содержит правильный SERVICE_NAME. Проверить, что BatchSpanProcessor успешно передаёт данные. Увеличить BATCH_TIMEOUT (по умолч. 5 сек) или вызвать provider.force_flush(). |
| Grafana не может подключиться к Jaeger | Использовать имя контейнера jaeger внутри Docker Compose; указать URL http://jaeger:16686. При запуске Grafana с хоста — http://localhost:16686. Возможно, требуется отключить авторизацию (уже сделано через GF_AUTH_ANONYMOUS_ENABLED=true). |
| Панели latency/errors пусты | Убедиться, что плагин Jaeger установлен. Для метрик можно использовать встроенный редактор «TraceQL» или переключиться на Prometheus метрики через OpenTelemetry Collector (дополнительная настройка). |
| Трейсы с ошибками не маркируются как ERROR | Явно вызывать span.set_status(trace.Status(StatusCode.ERROR)) в блоке except. Учесть, что исключение может быть перехвачено на верхнем уровне. |
| В дашборде отображаются только последние трейсы | Настроить временной диапазон дашборда на «last 5 minutes» или увеличить количество прогонов. |
8. Бюджет времени (оценка)
| Этап | Время |
|---|---|
| Этап 1: Подготовка окружения | 30-40 мин |
| Этап 2: Инструментирование | 60-90 мин |
| Этап 3: Подключение к Grafana | 30-40 мин |
| Этап 4: Дашборд latency и errors | 45-60 мин |
| Этап 5: Тестирование и верификация | 20-30 мин |
| Итого | 3-4 часа |
Примечание Для первого раза может потребоваться 4-5 часов, особенно при отладке сетевых настроек Jaeger-Grafana. Рекомендуется выполнять задачу в один подход или разбить на 2 сессии.
9. Связанные вопросы из базы знаний
| Вопрос | Тема |
|---|---|
| 1 | Основы OpenTelemetry (spans, traces, context propagation) |
| 5 | Настройка Jaeger All-In-One |
| 89 | Инструментирование Python-приложений с OpenTelemetry |
| 234 | Объединение трейсов из нескольких микросервисов |
| 511 | Best practices для naming spans |
| 613 | Связывание логов и трейсов через trace_id |
| 722 | Dashboards as Code (Grafana JSON-модели) |
| 801 | Мониторинг latency с процентилями (p50, p95, p99) |
| 855 | Использование OpenTelemetry Collector как proxy |
| 900 | Troubleshooting: трейсы не отображаются |
10. Чек-лист самопроверки
- Я проверил, что Jaeger UI показывает хотя бы один трейс с моим service name.
- Я убедился, что при возникновении exception span помечается как ERROR.
- Я добавил в дашборд график latency с p95 и error rate.
- Я экспортировал дашборд в JSON и сохранил рядом с docker-compose.yml.
- Я запустил
python main.pyне менее 5 раз после настройки дашборда и убедился, что данные обновляются.