Перейти к основному контенту
Tech Path Finder
КурсыИнтервьюКод-ревьюБлог
Tech Path Finder

Персонализированный путеводитель в IT. Квизы, мок-интервью, код ревью и аналитика прогресса.

@potapov_me

Платформа

  • Курсы
  • Прогресс
  • Мок-интервью
  • Код ревью
  • Живое ревью с ИИ
  • Тренажёр переговоров
  • Закладки

Контент

  • Блог
  • Главная
  • Обратная связь

Компания

  • О проекте
  • Тарифы
  • Условия использования
  • Конфиденциальность
  • Согласие на обработку данных
  • Cookie
  • Реквизиты

Аккаунт

  • Войти
  • Зарегистрироваться
  • Профиль

© 2026 Tech Path Finder. Все права защищены.

·ИП Потапов К.С.·Политика конфиденциальности·
Сделано с ❤️ в России
  1. Инструментирование приложений: первые метрики
instrumentation_basics

Инструментирование приложений: первые метрики

Добавление метрик в приложение, клиентские библиотеки, counter и gauge

Инструментирование приложений: первые метрики

«Нельзя улучшить то, что нельзя измерить»

#Что такое инструментирование

Инструментирование — это добавление кода в приложение для сбора метрик.

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

Уровни инструментирования:

  1. Автоматическое — инфраструктурные метрики (CPU, память) через экспортёры
  2. Ручное — бизнес-метрики и метрики приложения (запросы, ошибки, длительность операций)

В этой теме научимся добавлять метрики вручную.


#Клиентские библиотеки Prometheus

Prometheus предоставляет официальные клиентские библиотеки для популярных языков:

  • Python: prometheus-client
  • Go: prometheus/client_golang
  • Java: prometheus/client_java
  • Node.js: prom-client
  • Ruby: prometheus-client
  • PHP: prometheus/client_php

Библиотеки решают три задачи:

  1. Предоставляют API для создания метрик
  2. Автоматически экспортируют метрики на HTTP-эндпоинте /metrics
  3. Корректно обрабатывают потокобезопасность и производительность

#Типы метрик на практике

Вспомним типы метрик из темы про архитектуру и разберём, когда какой пользоваться.

#Counter: счётчик событий

Используйте для:

  • Количество обработанных запросов
  • Количество ошибок
  • Количество отправленных email
  • Время работы (в секундах)

Python пример:

from prometheus_client import Counter, start_http_server # Создаём counter http_requests = Counter( 'http_requests_total', # имя метрики 'Total HTTP requests', # описание ['method', 'status'] # лейблы ) def handle_request(method, status): # Инкремент на 1 http_requests.labels(method=method, status=status).inc() # Инкремент на произвольное значение # http_requests.labels(method=method, status=status).inc(5) # Запускаем HTTP сервер для экспорта метрик start_http_server(8000)

Важно:

  • Имя counter должно заканчиваться на _total (конвенция Prometheus)
  • Counter не может уменьшаться
  • Не используйте counter для значений, которые могут сбрасываться (лучше gauge)

#Gauge: датчик текущего состояния

Используйте для:

  • Использование памяти
  • Количество активных пользователей
  • Температура CPU
  • Размер очереди задач

Python пример:

from prometheus_client import Gauge import random active_users = Gauge( 'active_users', 'Number of active users' ) def update_active_users(): # Устанавливаем конкретное значение active_users.set(random.randint(0, 100)) # Инкремент/декремент # active_users.inc() # +1 # active_users.dec(5) # -5

Важно:

  • Gauge может принимать любые значения (положительные, отрицательные, ноль)
  • Используйте set() для установки абсолютного значения
  • Используйте inc()/dec() для относительных изменений

#Histogram: распределение значений

Используйте для:

  • Время ответа API
  • Размер запросов/ответов
  • Длительность операций БД

Python пример:

from prometheus_client import Histogram import time # Создаём histogram с кастомными бакетами request_latency = Histogram( 'http_request_duration_seconds', 'HTTP request duration in seconds', ['method'], buckets=(0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0) ) @request_latency.time() # Декоратор автоматически замеряет время def handle_request(method): # Ваш код time.sleep(0.1) return "OK" # Или вручную: def handle_request_manual(method): start = time.time() try: # Ваш код pass finally: request_latency.labels(method=method).observe(time.time() - start)

Важно:

  • Histogram автоматически создаёт _bucket, _sum, _count метрики
  • Buckets по умолчанию подходят для времени ответа (в секундах)
  • Для других метрик (размер в байтах) укажите свои бакеты

#Summary: перцентили на клиенте

Используйте редко, когда:

  • Нужны точные перцентили на одном инстансе
  • Не нужно агрегировать across instances

Python пример:

from prometheus_client import Summary import time request_summary = Summary( 'http_request_duration_seconds', 'HTTP request duration in seconds', ['method'] ) @request_summary.time() def handle_request(method): time.sleep(0.1)

Важно:

  • Summary вычисляет перцентили на клиенте (в приложении)
  • Нельзя агрегировать summary с разных инстансов в Prometheus
  • В 95% случаев используйте histogram вместо summary

#Полный пример: Flask приложение

Рассмотрим реальное приложение с полным инструментированием.

from flask import Flask, request, jsonify from prometheus_client import Counter, Histogram, Gauge, generate_latest, CONTENT_TYPE_LATEST import time import random app = Flask(__name__) # === МЕТРИКИ === # Counter: количество запросов http_requests_total = Counter( 'http_requests_total', 'Total HTTP requests', ['method', 'endpoint', 'status'] ) # Histogram: время ответа http_request_duration = Histogram( 'http_request_duration_seconds', 'HTTP request duration in seconds', ['method', 'endpoint'], buckets=(0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0) ) # Gauge: количество запросов в обработке requests_in_progress = Gauge( 'http_requests_in_progress', 'Number of HTTP requests currently being processed', ['method'] ) # === MIDDLEWARE === @app.before_request def before_request(): # Засекаем время начала request.start_time = time.time() # Инкремент запросов в обработке requests_in_progress.labels(method=request.method).inc() @app.after_request def after_request(response): # Декремент запросов в обработке requests_in_progress.labels(method=request.method).dec() # Записываем метрики duration = time.time() - request.start_time http_request_duration.labels( method=request.method, endpoint=request.endpoint or 'unknown' ).observe(duration) http_requests_total.labels( method=request.method, endpoint=request.endpoint or 'unknown', status=response.status_code ).inc() return response # === ЭНДПОИНТ МЕТРИК === @app.route('/metrics') def metrics(): return generate_latest(), 200, {'Content-Type': CONTENT_TYPE_LATEST} # === БИЗНЕС-ЛОГИКА === @app.route('/api/users') def get_users(): # Имитация работы time.sleep(random.uniform(0.01, 0.1)) return jsonify({'users': []}) @app.route('/api/orders', methods=['POST']) def create_order(): # Имитация ошибки 10% запросов if random.random() < 0.1: return jsonify({'error': 'Internal error'}), 500 return jsonify({'order_id': 123}), 201 if __name__ == '__main__': app.run(host='0.0.0.0', port=5000)

Что измеряем:

  1. http_requests_total — все запросы с разбивкой по методу, эндпоинту, статусу
  2. http_request_duration_seconds — время ответа для анализа перцентилей
  3. http_requests_in_progress — текущая нагрузка на сервер

#Настройка Prometheus для скрапинга приложения

Добавьте приложение в конфигурацию Prometheus:

scrape_configs: - job_name: 'myapp' static_configs: - targets: ['localhost:5000'] metrics_path: /metrics # Путь к эндпоинту метрик (по умолчанию /metrics) scrape_interval: 15s # Частота опроса

Перезапустите Prometheus и проверьте в UI:

# Количество запросов в секунду rate(http_requests_total[5m]) # 95-й перцентиль времени ответа histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m])) # Запросов в обработке прямо сейчас http_requests_in_progress

#Бизнес-метрики

Не ограничивайтесь техническими метриками. Добавляйте метрики, важные для бизнеса.

Примеры бизнес-метрик:

from prometheus_client import Counter, Histogram # Количество зарегистрированных пользователей user_registrations_total = Counter( 'user_registrations_total', 'Total user registrations', ['source'] # источник: email, google, github ) # Количество заказов orders_total = Counter( 'orders_total', 'Total orders', ['status', 'payment_method'] ) # Сумма выручки revenue_total = Counter( 'revenue_total', 'Total revenue in cents', ['currency'] ) # Время обработки заказа order_processing_time = Histogram( 'order_processing_seconds', 'Order processing time in seconds', buckets=(1, 5, 10, 30, 60, 120, 300) )

Зачем: чтобы связывать технические проблемы с бизнес-последствиями. Если упала база данных — это техническая проблема. Если из-за этого упала выручка — это проблема бизнеса.


#Best practices инструментирования

#1. Используйте осмысленные имена

# ПЛОХО requests = Counter('req', 'Requests') # ХОРОШО http_requests_total = Counter( 'http_requests_total', 'Total HTTP requests' )

Конвенции:

  • Counter: ..._total
  • Histogram: ..._seconds, ..._bytes
  • Используйте snake_case

#2. Не переусердствуйте с лейблами

# ПЛОХО: слишком много лейблов (cardinality explosion!) Counter('requests', 'Requests', ['user_id', 'request_id', 'timestamp']) # ХОРОШО: разумные лейблы Counter('requests', 'Requests', ['method', 'endpoint', 'status'])

Проблема: каждая уникальная комбинация лейблов создаёт новый временной ряд. user_id с миллионами пользователей = миллионы рядов = проблемы с производительностью.

#3. Документируйте метрики

http_requests_total = Counter( 'http_requests_total', 'Total HTTP requests', ['method', 'endpoint', 'status'], unit='requests' # В новых версиях клиентских библиотек )

Добавляйте HELP текст, который объясняет, что измеряет метрика.

#4. Измеряйте то, что важно

Не измеряйте всё подряд. Сфокусируйтесь на:

  • Четырёх золотых сигналах (latency, traffic, errors, saturation)
  • Бизнес-метриках
  • Точках отказа (БД, внешние API)

#5. Тестируйте метрики

Добавьте тесты, которые проверяют:

  • Метрики создаются и экспортируются
  • Значения обновляются корректно
  • Лейблы имеют ожидаемые значения
def test_metrics_exported(): response = client.get('/metrics') assert response.status_code == 200 assert 'http_requests_total' in response.data.decode()

#Отладка метрик

#Проверка эндпоинта

curl http://localhost:5000/metrics

Должны увидеть текст в формате Prometheus:

# HELP http_requests_total Total HTTP requests
# TYPE http_requests_total counter
http_requests_total{method="GET",endpoint="get_users",status="200"} 42.0

#Проверка в Prometheus UI

  1. Откройте Prometheus (http://localhost:9090)
  2. Введите имя метрики в строку запроса
  3. Убедитесь, что видите данные

#Частые проблемы

Проблема: метрики не появляются.

Причины:

  • Приложение не запущено или не слушает порт
  • Неправильный metrics_path в конфигурации Prometheus
  • Фаервол блокирует соединение

Проблема: слишком много временных рядов.

Причины:

  • Слишком много уникальных комбинаций лейблов
  • Лейблы с высокими кардинальностями (user_id, request_id)

Решение: уберите проблемные лейблы.

Далее: Grafana: создание первых дашбордов