Перейти к основному контенту

Телеметрия использования: usage_telemetry

Для разработчиков. Состояние на 28.09.2026. Подробности и переменные — README репозитория usage_telemetry. Выкатка коллектора и дашборд лежат в репозитории infra, про него — статья «Мониторинг и автоматизация серверов: infra».

Коротко

usage_telemetry отвечает на вопрос, какими приложениями и какими их разделами пользуются живые люди. Цель — отличить приложение, которое висит мёртвым грузом, от приложения, которым пользуются редко, но по делу, и выключать только первое. Проект состоит из двух частей:

  • пакет usage-telemetry: встраивается в приложение одной строкой и считает обращения;
  • коллектор: принимает события, складывает их в PostgreSQL и раз в час пересчитывает суточные своды.

Результат смотрят в Grafana, на дашборде «Использование приложений».

приложение (middleware) ──пачками по HTTP──> коллектор ──> PostgreSQL ──> Grafana

Как подключить к проекту

  1. Добавить пакет в requirements.txt (или в pyproject.toml), закрепив тег:
    usage-telemetry @ https://github.com/Buharestskie/usage_telemetry/archive/refs/tags/v0.2.0.tar.gz
    Для отправки ошибок в GlitchTip нужен ещё sentry-sdk (extra sentry).
  2. Повесить сбор на приложение FastAPI или Starlette:
    from usage_telemetry import install_telemetry
    
    app = FastAPI()
    install_telemetry(app)
    Если задан SENTRY_DSN, install_telemetry заодно инициализирует GlitchTip. Если в проекте SDK уже поднят своим кодом, вызывайте install_telemetry(app, sentry=False).
  3. Сообщить, кто пришёл. В зависимости авторизации, где сессия или токен уже разобраны:
    from usage_telemetry import mark_user
    
    mark_user(request, user_id=session.amocrm_user_id, auth="session", session_id=session_id)
    Значения auth: session — человек в браузере; jwt — виджет amoCRM с токеном от widget_auth; telegram — бот или Mini App; basic — админки; api_key — вызов между сервисами; none — без авторизации. Без mark_user вид входа угадывается по заголовкам, но идентификатора пользователя не будет.
  4. Для бота на aiogram 3:
    from usage_telemetry import install_bot_telemetry
    
    install_bot_telemetry(dispatcher)
  5. Добавить переменные в compose проекта и выкатить в окне обслуживания.
ПеременнаяОбязательнаЧто означает
TELEMETRY_SERVICEдамашинный код приложения. Должен совпадать с project этого сервиса в status_page_services (infra)
TELEMETRY_URLдаадрес коллектора. Приложения на одном сервере с коллектором используют http://host.docker.internal:8130, с других серверов — https://donula26.ru/telemetry
TELEMETRY_ENABLEDнет0 выключает сбор целиком
TELEMETRY_QUEUE_SIZE, TELEMETRY_BATCH_SIZE, TELEMETRY_FLUSH_SECONDS, TELEMETRY_TIMEOUTнеточередь (5000), размер пачки (200), интервал отправки неполной пачки (5 с), таймаут запроса (3 с)
SENTRY_DSNнетпроект в GlitchTip; без него ошибки не отправляются

Если не задан TELEMETRY_SERVICE или TELEMETRY_URL, пакет пишет предупреждение в лог и ничего не собирает. Приложение при этом работает как обычно.

Что собирается

Одно событие на одно обращение к приложению:

ПолеЧто в нём
at, service, sourceвремя, код приложения, источник: http или bot
method, pathметод и шаблон пути из маршрута (/api/deals/{id}, а не /api/deals/451). Если маршрута нет, путь нормализуется: числа заменяются на {id}, UUID — на {uuid}, длинные непрозрачные сегменты — на {token}
status, duration_msкод ответа и длительность
auth, user_id, session_idчем запрос аутентифицирован и чей идентификатор из уже существующей авторизации: amocrm_user_id, id из JWT, telegram_id
user_agentпервые 200 символов
client_ipдоходит только до коллектора. Там из него, user-agent и общей соли считается отпечаток посетителя, а сам адрес не сохраняется
  • Не пишется никогда: строка запроса, тело, referer, имена и почта. В строке запроса ходят разовые токены, а хранилище не должно превращаться в базу утёкших секретов.
  • Отсекается на входе: OPTIONS, /health, /healthz, /metrics, /ping, /favicon.ico, /robots.txt, пути под /static/, /assets/, /_next/, /_app/ и файлы статики по расширению. Свои исключения добавляются параметрами skip_paths и skip_prefixes.
  • В ботах считаются только входящие от людей: сообщения (команда с короткой меткой вроде /start beeline или тип вложения) и нажатия кнопок. Данные кнопки сводятся к шаблону: service:1842 превращается в service:{id}. Рассылки не считаются, прочтения Telegram ботам не отдаёт.

Как устроено внутри

  • Приложение ничего не ждёт. Middleware кладёт событие в очередь в памяти, фоновая задача отправляет пачки в POST /events. Если коллектор недоступен, пачка выбрасывается без повторов. Если очередь переполнилась, она сбрасывается целиком. При остановке приложения остаток отправляется.
  • Коллектор — FastAPI с PostgreSQL. Сырые события хранятся в таблице events 90 дней. Раз в час коллектор пересчитывает своды за последние трое суток и чистит устаревшее сырьё. Своды хранятся бессрочно:
    • daily_users — человеко-дни: пара «день + человек». В этот свод попадают только обращения с auth session, jwt, telegram или basic и с известным user_id. Вызовы между сервисами сюда не входят;
    • daily_paths — разделы по дням: число обращений, людей, посетителей по отпечатку, ошибок 5xx и 95-й перцентиль длительности.
  • Справочник приложений (таблица services) собирается из status_page_services и telemetry_extra_services в инвентаре infra. Коллектор читает его только при старте. По отметке первого события видно, раскатан ли сбор в приложение.
  • Ручки коллектора: POST /events (ответ {"accepted": N}), GET /health, GET /stats — сколько накоплено и когда был последний свод. Коллектор слушает только внутренний интерфейс сервера. С других серверов события идут через путь /telemetry/ на donula26.ru, куда пускают только адреса из списка в роли web_proxy.

Где смотреть

Grafana, grafana.donula26.ru → папка «Инфраструктура» → дашборд «Использование приложений». Период по умолчанию — 30 дней.

ПанельЧто показывает
Приложений под наблюдениемсколько приложений в справочнике
Сбор не раскатанприложения, от которых не пришло ни одного события. Пока здесь не ноль, выводы о неиспользуемых делать рано
Без единого обращения за периодсбор работает, а обращений не было — кандидаты на выключение
Приложения по живостиглавная таблица: обращения, люди, посетители (оценка), человеко-дни, последний заход и замечание: «сбор не подключён», «никто не заходил», «люди не опознаются» или «только оценка по отпечатку»
Человеко-дни по приложениямграфик по дням
Разделы и данныеразделы выбранного приложения (переменная «Приложение»)
Кто пользуетсяидентификаторы пользователей выбранного приложения, без имён: нужны, чтобы предупредить людей перед выключением
Медленное и ошибающеесяразделы с ошибками или с 95-м перцентилем больше 3 секунд

Дашборд генерируется скриптом roles/monitoring_server/files/dashboards/generate_usage.py в infra. В браузере он не редактируется.

Выкатка

  • Коллектор выкатывается из репозитория infra: ansible-playbook playbooks/telemetry_collector.yml. Роль забирает код из ветки main этого репозитория, выпускает самоподписанный сертификат для базы, один раз создаёт соль отпечатка, раскладывает справочник приложений и поднимает compose. Пароль базы берётся из Vault (telemetry_collector_db_password), без него роль останавливается. База входит в ежедневные бэкапы.
  • Пакет приезжает в приложения тегом в зависимостях. Новая версия пакета — это новый тег здесь и правка строки в каждом проекте.
  • Проверки: python tests/test_telemetry.py проверяет пакет без базы и сети. COLLECTOR_TEST_DSN=… python collector/tests/test_collector.py проверяет коллектор и требует настоящий PostgreSQL: тест работает в отдельной схеме и удаляет её за собой.

На что наступают

  • TELEMETRY_SERVICE не совпал с project в status_page_services. События пишутся, но приложение не попадает в список ожидаемых и на дашборде в таблице живости не видно. Приложениям без пробы на статус-странице код прописывают в telemetry_extra_services.
  • После правки справочника в инвентаре коллектор нужно перезапустить. Роль telemetry_collector делает это сама.
  • События теряются осознанно. Коллектор лежал — в данных дыра. Приложение, которое молчит, и приложение, которым не пользуются, на сводах выглядят одинаково. Различают их по колонке «Замечание».
  • Отпечаток — оценка, а не счёт людей. Сотрудники из офиса сидят за одним адресом, и различает их только user-agent: одинаковые браузеры схлопнутся в одного посетителя.
  • Приложение на другом сервере шлёт в пустоту, если адреса этого сервера нет в списке для /telemetry/ в роли web_proxy: nginx отвечает 403, пакет молча выбрасывает события.
  • Без привязки к завершению приложения последняя пачка теряется при каждом перезапуске. install_telemetry привязывается к lifespan, а если не получилось, пишет предупреждение в лог. Его не игнорируйте.
  • Не у каждого бота есть Dispatcher. У односторонних ботов, которые только рассылают, входящих от людей нет, и мерить там нечего.