Телеметрия использования: usage_telemetry
Для разработчиков. Состояние на 28.09.2026. Подробности и переменные — README репозитория usage_telemetry. Выкатка коллектора и дашборд лежат в репозитории infra, про него — статья «Мониторинг и автоматизация серверов: infra».
Коротко
usage_telemetry отвечает на вопрос, какими приложениями и какими их разделами пользуются живые люди. Цель — отличить приложение, которое висит мёртвым грузом, от приложения, которым пользуются редко, но по делу, и выключать только первое. Проект состоит из двух частей:
- пакет
usage-telemetry: встраивается в приложение одной строкой и считает обращения; - коллектор: принимает события, складывает их в PostgreSQL и раз в час пересчитывает суточные своды.
Результат смотрят в Grafana, на дашборде «Использование приложений».
приложение (middleware) ──пачками по HTTP──> коллектор ──> PostgreSQL ──> Grafana
Как подключить к проекту
- Добавить пакет в
requirements.txt(или вpyproject.toml), закрепив тег:
Для отправки ошибок в GlitchTip нужен ещёusage-telemetry @ https://github.com/Buharestskie/usage_telemetry/archive/refs/tags/v0.2.0.tar.gzsentry-sdk(extrasentry). - Повесить сбор на приложение FastAPI или Starlette:
Если заданfrom usage_telemetry import install_telemetry app = FastAPI() install_telemetry(app)SENTRY_DSN,install_telemetryзаодно инициализирует GlitchTip. Если в проекте SDK уже поднят своим кодом, вызывайтеinstall_telemetry(app, sentry=False). - Сообщить, кто пришёл. В зависимости авторизации, где сессия или токен уже разобраны:
Значения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вид входа угадывается по заголовкам, но идентификатора пользователя не будет. - Для бота на aiogram 3:
from usage_telemetry import install_bot_telemetry install_bot_telemetry(dispatcher) - Добавить переменные в 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. Сырые события хранятся в таблице
events90 дней. Раз в час коллектор пересчитывает своды за последние трое суток и чистит устаревшее сырьё. Своды хранятся бессрочно:daily_users— человеко-дни: пара «день + человек». В этот свод попадают только обращения сauthsession,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. У односторонних ботов, которые только рассылают, входящих от людей нет, и мерить там нечего.