АШШумилкин А. О.ОАиП · ПиТПМ
ПиТПМ · Лекция 13

Лекция №13. Инфраструктурный мониторинг развернутых модулей (Observability): Логирование, метрики и трассировка.

4 620 слов8 разделов5 иллюстраций
↓ Скачать Markdown

§13.1. Почему тестировщик должен думать о мониторинге

Мы с вами прошли долгий путь. Научились тестировать код, интеграции, интерфейсы, нагрузку, безопасность. Научились автоматизировать проверки в CI/CD. Научились искать утечки памяти и медленные методы.

Но есть один вопрос, который мы пока не закрыли: «А что происходит после того, как релиз вышел в продакшен?».

Тесты прошли. Конвейер зеленый. Релиз выкатили. Пользователи начали работать. И тут... что-то пошло не так.

Как узнать, что пошло не так? Как понять, что система работает нормально? Ответ: мониторинг.

Тесты проверяют до релиза. А что происходит после?

Весь курс был про тестирование до релиза. Мы проверяли код до того, как он попадет к пользователям. Но что происходит, когда пользователи уже работают?

Что проверялиЧто происходит после релиза
Функциональные тесты — проверяют логикуПользователи находят баги, которые мы не предусмотрели
Нагрузочные тесты — проверяют производительностьНагрузка может быть выше, чем мы тестировали
Интеграционные тесты — проверяют связиВнешний сервис может упасть или измениться
Безопасность — проверяем уязвимостиПоявляются новые уязвимости, которых не было

Тесты не могут гарантировать, что система будет работать вечно. Они проверяют только то, что мы запланировали проверить. А в реальном мире происходит много непредсказуемого.

Вот, например, вы проверили машину перед выездом: давление в шинах, масло, тормоза. Всё хорошо. Вы выехали на трассу. Через час на дороге яма, вы пробили колесо. Как вы узнаете, что колесо спущено? Вы почувствуете вибрацию, услышите звук, увидите предупреждение на панели приборов. Это и есть мониторинг — наблюдение за системой в процессе работы.

Мониторинг

— это «тесты». на работающей системе Тесты мы запускаем до релиза. Мониторинг работает после релиза — постоянно, 24/7.

Мониторинг

— это наблюдение за работающей системой: сбор данных о том, что происходит, и анализ этих данных, чтобы понять, всё ли работает нормально.

Что мониторинг показывает:

Что показываетПример
Работает ли система?Сервер отвечает на запросы?
Как быстро работает?Время ответа не выросло?
Есть ли ошибки?Появились новые исключения в логах?
Хватает ли ресурсов?Память не заканчивается? CPU не перегружен?

Мониторинг

— это как приборная панель в самолете. Пилот не может проверить каждый винт перед полетом. Но он видит показатели на панели и понимает, всё ли в порядке.

Тестирование и мониторинг часто путают, хотя они решают разные задачи и работают на разных этапах жизни приложения. Наглядно сопоставить их ключевые отличия поможет таблица ниже:

ТестированиеМониторинг
Проверяет до релизаПроверяет после релиза
Запускается периодическиРаботает постоянно
Проверяет конкретные сценарииНаблюдает за всем
Находит багиНаходит проблемы в работе

Мониторинг

— это командная работа. Кто-то должен смотреть на данные и реагировать.

Кто участвует:

КтоЧто делает
РазработчикПишет код, добавляет логи, исправляет ошибки, найденные через мониторинг
ТестировщикПроверяет, что мониторинг показывает корректные данные, анализирует тренды, помогает находить проблемы
DevOps / SREНастраивает сбор метрик, строит дашборды, обеспечивает работу инфраструктуры

Почему тестировщи должен участвовать в мониторинге:

1. Тестировщик знает систему лучше всех. Он тестировал её, знает, как она должна работать.

2. Тестировщик видит проблему со стороны пользователя. Если пользователь жалуется, тестировщик может проверить логи и понять, что произошло.

3. Тестировщик помогает улучшать мониторинг. Если в логах не хватает данных для анализа — тестировщик скажет разработчикам, что добавить.

4. Тестировщик — связующее звено. Он переводит технические данные (логи, метрики) на язык бизнеса («пользователи не могут оплатить заказ»).

Как же мониторинг помогает тестировщику? Ответить на этот вопрос поможет таблица, которая показана ниже:

СитуацияБез мониторингаС мониторингом
Пользователь жалуется на ошибкуНепонятно, что случилосьСмотрим логи → видим ошибку → понимаем, что произошло
Система стала медленнееПользователи жалуются, мы не знаем, почемуСмотрим метрики → видим, что время ответа выросло → ищем причину
Сервер упал ночьюУзнаем утром от пользователейУведомление приходит сразу → исправляем до того, как пользователи заметили
Новый релиз сломал что-тоНепонятно, что именно и гдеСравниваем метрики до и после релиза → видим, что изменилось

В этой лекции мы разберем три столпа Observability:

1. Логи — записи о событиях («что случилось»).

2. Метрики — числовые показатели («сколько чего»).

3. Трассировка — путь запроса через систему («где случилось»).

Простая аналогия:

  • Логи — это как дневник событий («в 15:23 пользователь Иван нажал кнопку»).
  • Метрики — это как приборная панель («сейчас 1000 пользователей, время ответа 200 мс»).
  • Трассировка — это как трекинг посылки («запрос прошел через сервисы А, Б, В, в сервисе Б упал»).

§13.2. Три столпа Observability: логи, метрики, трассы

Observability (наблюдаемость)

— это способность понять, что происходит внутри системы, просто наблюдая за ней снаружи.

Представьте, что вы смотрите на работающий автомобиль. Вы не можете заглянуть внутрь двигателя. Но вы видите:

  • Скорость на спидометре (метрики).
  • Слышите звук двигателя и видите дым из выхлопной трубы (логи).
  • Видите, что машина виляет вправо (трассировка).

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

Представьте, что в офисе произошла кража. Вы — детектив. Вам нужно понять, что случилось.

Что вы делаетеАналогия с Observability
Смотрите записи с камерЛоги — записи событий
Смотрите статистику: сколько людей заходило, во сколькоМетрики — числовые показатели
Восстанавливаете путь вора: вход → коридор → кабинет → выходТрассировка — путь запроса через систему

Только вместе эти три источника дают полную картину.

Столп №1. Логи (что случилось?)

Логи

— это записи о событиях, которые происходят в системе. Каждое событие — это строчка в логе.

Что содержит лог:

wireframe

2024-01-15 15:23:45 [INFO] User Ivan logged in from IP 192.168.1.1

2024-01-15 15:23:47 [INFO] User Ivan created order #12345

2024-01-15 15:23:48 [ERROR] Payment failed: insufficient funds for user 456

2024-01-15 15:23:50 [INFO] User Ivan logged out

Что мы видим? Иван залогинился, создал заказ, оплата не прошла (недостаточно средств), вышел из системы.

СитуацияЧто дают логи
Ошибка в системеВидим, какая ошибка произошла
АудитКто и что делал в системе
Расследование инцидентаВосстанавливаем последовательность событий

Столп №2. Метрики (сколько чего?)

Метрики

— это числовые показатели работы системы. Это цифры, которые можно измерить.

Какие метрики собирают:

МетрикаЧто показываетПример
RPSЗапросов в секунду100 RPS
LatencyВремя ответа200 мс
Error RateПроцент ошибок0.5%
CPUЗагрузка процессора75%
MemoryИспользование памяти4 ГБ из 8 ГБ

Как выглядят метрики:

wireframe

Метрики за последний час:

- RPS: 95 → 100 → 120 → 110 → 90

- Latency (p95): 150ms → 160ms → 200ms → 300ms → 450ms

- Error Rate: 0% → 0% → 0% → 0.5% → 2%

Что мы видим? Нагрузка выросла (RPS), время ответа увеличилось, появились ошибки. Возможно, нагрузка слишком высокая.

Когда метрики нужны:

СитуацияЧто дают метрики
Мониторинг в реальном времениВидим текущее состояние системы
Обнаружение аномалийВидим, когда показатели выходят за норму
Анализ трендовВидим, как меняется система со временем

Столп №3. Трассировка (где была проблема?)

Трассировка

— это отслеживание пути одного запроса через все сервисы системы.

В микросервисах это особенно важно. Запрос может проходить через 5-10 сервисов. Если что-то упало — нужно понять, в каком именно.

Пример трассировки:

bash

Запрос: GET /api/order/12345
├── API Gateway (5ms)
│   ├── Auth Service (2ms)
│   │   └── Проверка токена ✅
│   ├── Order Service (15ms)
│   │   ├── Проверка заказа ✅
│   │   └── Запрос к БД (10ms) ✅
│   ├── Payment Service (FAILED)
│   │   ├── Проверка статуса платежа ✅
│   │   └── Запрос к платежному шлюзу ❌ ТАЙМАУТ!
│   └── User Service (3ms)
│       └── Получение данных пользователя ✅
└── Ответ пользователю: 500 Internal Server Error

Что мы видим? Запрос прошел через 4 сервиса. В Payment Service произошел таймаут при запросе к платежному шлюзу. Вот где проблема!

Когда трассировка нужна:

СитуацияЧто дает трассировка
Запрос упал в микросервисахВидим, какой сервис упал
Запрос выполняется долгоВидим, какой сервис тормозит
Расследование инцидентаВосстанавливаем путь запроса

Когда в системе случается сбой, разработчик превращается в детектива. Разберем наглядный пример классического расследования, где три столпа — метрики, логи и трассировка — помогают пошагово выйти на след проблемы. Представим ситуацию – пользователи жалуются, что заказы не проходят.

Шаг №1. Смотрим метрики

wireframe

Error Rate: 0% → 0.5% → 2% → 5% (растет!)

Вывод: что-то пошло не так. Проблема началась примерно 15 минут назад.

Шаг№ 2. Смотрим логи

wireframe

15:23:48 [ERROR] Payment failed: timeout calling payment gateway

15:24:12 [ERROR] Payment failed: timeout calling payment gateway

15:24:56 [ERROR] Payment failed: timeout calling payment gateway

Вывод: Платежный шлюз не отвечает. Ошибка в Payment Service.

Шаг №3. Смотрим трассировку

bash

Запрос: POST /api/order
├── API Gateway (5ms) ✅
├── Order Service (10ms) ✅
├── Payment Service (TIMEOUT)
│   └── Запрос к платежному шлюзу ❌ ТАЙМАУТ!
└── Response: 500 Internal Server Error

Вывод: Платежный шлюз не отвечает. Нужно проверить его доступность.

Метрики показали рост ошибок. Логи показали конкретную ошибку. Трассировка показала, где именно (в Payment Service). Всё вместе — понятно, что делать.

§13.3. Логирование: запись событий

Логи

— это записи о том, что происходило в системе. Каждое событие — одна строчка в логе.

Логи

— это как дневник, который ведет программа. В нём записано всё, что с ней происходило: кто приходил, что делал, что сломалось.

Логи незаменимы при разборе инцидентов, когда нужно восстановить картину произошедшего по шагам. Вот как это работает на практике при появлении ошибки в системе.

В логах есть уровни. Они показывают, насколько важное событие произошло.

УровеньКогда использоватьПример
DebugДля отладки (только в разработке)[DEBUG] UserService.GetUser called with id=123
InfoОбычные события[INFO] User Ivan logged in
WarningЧто-то не так, но не критично[WARNING] Database connection slow: 200ms
ErrorОшибка, но система работает[ERROR] Payment failed: insufficient funds
CriticalСистема может упасть[CRITICAL] Database connection lost!

Простая аналогия:

  • Debug — ваши заметки (никто не читает, только вы).
  • Info — новости («Иван зашел в офис»).
  • Warning — «В офисе стало душно, нужно открыть окно».
  • Error — «Сломался принтер, но работа продолжается».
  • Critical — «Пожар в здании, нужно эвакуироваться».

Чтобы логи не превращались в сплошной и бесполезный поток текста, важно строго разделять события по степени их важности. Понять, какому событию какой уровень логгирования соответствует на практике, поможет таблица ниже:

СитуацияКакой уровень
«Запрос пришел»Info
«Пользователь создал заказ»Info
«База данных ответила медленно»Warning
«Платеж не прошел»Error
«Сервер не отвечает»Critical
«Внутренняя логика метода»Debug

В продакшене включают Info и выше. Debug — только на тестовой среде, потому что его слишком много.

Хороший лог содержит всю информацию, чтобы понять, что произошло. Что должно быть в каждой записи:

ЧтоЗачемПример
ВремяКогда произошло2024-01-15 15:23:48
УровеньНасколько важно[ERROR]
СообщениеЧто произошлоPayment failed: insufficient funds
КонтекстКто, что, гдеUser Ivan (ID: 456), Order #12345

Плохой лог:

wireframe

Error occurred

Хороший лог:

wireframe

2024-01-15 15:23:48 [ERROR] Payment failed for user id=456, order #12345: insufficient funds, payment gateway response: decline

В хорошем логе есть всё, чтобы понять проблему без дополнительных вопросов. Пример кода (C# с Serilog):

csharp

public class OrderService
{
    private readonly ILogger _logger;
    public OrderService(ILogger logger)
        => _logger = logger;
    public async Task<bool> ProcessOrder(Order order)
    {
        _logger.Information("Processing order {OrderId} for user {UserId}", 
                            order.Id, 
                            order.UserId);
        
        try
        {
            var result = await _paymentService.Pay(order);
            if (result.Success)
            {
                _logger.Information("Payment succeeded for order {OrderId}", 
                                    order.Id);
                return true;
            }
            else
            {
                _logger.Warning("Payment declined for order {OrderId}: {Reason}",    
                                order.Id, 
                                result.Reason);
                return false;
            }
        }
        catch (Exception ex)
        {
            _logger.Error(ex, "Payment failed for order {OrderId}", 
                          order.Id);
            throw;
        }
    }
}

Что мы получаем:

wireframe

[INFO] Processing order 12345 for user 456

[INFO] Payment succeeded for order 12345

Или если ошибка:

wireframe

[ERROR] Payment failed for order 12345: System.TimeoutException: Payment gateway timeout

Тестировщик смотрит на эти логи и понимает, что произошло.

Место хранения логов напрямую зависит от того, на каком этапе жизненного цикла находится приложение. Сориентироваться в том, где искать диагностические данные для разных сред, поможет следующая таблица:

СредаГде логи
Разработка (локально)В консоли или в файле logs/app.log
Тестовая среда (staging)В файлах на сервере или в ELK/Splunk
ПродакшенВ централизованной системе (ELK, Application Insights, Splunk)

В продакшене логи хранятся в централизованном месте. Не нужно заходить на каждый сервер — можно посмотреть всё в одном месте.

§13.4. Метрики: измерения производительности

Метрики

— это числовые показатели работы системы. Это цифры, которые можно измерить, записать и проанализировать.

Метрики

— это приборная панель в машине. Вы видите скорость, обороты двигателя, уровень топлива, температуру. Вы не смотрите под капот, но понимаете, что происходит с машиной. Пример метрик:

Текущее состояние системы:

wireframe

- Запросов в секунду: 150

- Среднее время ответа: 200 мс

- Процент ошибок: 0.5%

- Загрузка CPU: 65%

- Использование памяти: 4.2 ГБ из 8 ГБ

Метрики делятся на несколько категорий. Вот самые важные:

1. Метрики нагрузки (сколько запросов)

МетрикаЧто показываетПример
RPS (Requests Per Second)Количество запросов в секунду150 RPS
Active UsersСколько пользователей сейчас работает1 234 пользователя
ThroughputСколько данных передается50 МБ/с

Эти метрики необходимо смотреть тогда, когда нужно понять, насколько нагружена система.

2. Метрики производительности (как быстро)

МетрикаЧто показываетПример
Latency (p50, p95, p99)Время ответа в процентиляхp95 = 300 мс
TTFB (Time To First Byte)Время до первого байта150 мс
Response TimeПолное время ответа200 мс

Эти метрики необходимо смотреть тогда, когда нужно понять, не стала ли система медленнее.

3. Метрики ошибок (всё ли хорошо)

МетрикаЧто показываетПример
Error RateПроцент запросов с ошибками0.5%
5xx ErrorsКоличество серверных ошибок12 в минуту
4xx ErrorsКоличество клиентских ошибок5 в минуту

Эти метрики необходимо смотреть тогда, когда нужно понять, не начала ли система падать.

4. Метрики ресурсов (хватает ли мощности)

МетрикаЧто показываетПример
CPU UsageЗагрузка процессора65%
Memory UsageИспользование памяти4.2 ГБ
Disk UsageИспользование диска200 ГБ из 500 ГБ
Network I/OСетевой трафик50 МБ/с

Эти метрики необходимо смотреть тогда, когда нужно понять, не нужно ли добавить ресурсов.

График метрик за час выглядит примерно следующим образом:

Что мы видим:

  • В 15:20 нагрузка выросла (RPS) → время ответа увеличилось (Latency) → появились ошибки (Error Rate).
  • В 15:40 нагрузка упала → время ответа вернулось к норме → ошибки исчезли.

Система не справляется с пиковой нагрузкой в 15:20. Нужно либо оптимизировать код, либо добавить ресурсы.

Метрики дают мгновенный срез состояния системы «здесь и сейчас». Сравним три состояния: когда приложение чувствует себя отлично и когда в нем начинают назревать проблемы, ну и анализ трендов.

Простая аналогия:

  • Профилирование — это как МРТ (разовый, глубокий анализ).
  • Метрики — это как термометр и тонометр (постоянный, поверхностный контроль).

Сам по себе сбор цифр не имеет смысла, если их неудобно анализировать. Для построения полноценной системы мониторинга используется классический стек инструментов, чьи роли распределены в таблице ниже:

ИнструментЧто делает
PrometheusСбор и хранение метрик
GrafanaВизуализация метрик (графики, дашборды)
Application InsightsМониторинг для .NET (Azure)
CloudWatchМониторинг для AWS

Метрики нужны не только разработчикам и системным администраторам для круглосуточного дежурства, но и тестировщикам. Понять, как QA-инженер использует графики и цифры на разных этапах своей работы, поможет таблица ниже:

Что делает тестировщикКак метрики помогают
Проверяет работу системы после релизаСмотрит, не выросли ли ошибки после релиза
Анализирует проблемы пользователейВидит, когда началась проблема (по графику)
Планирует нагрузочные тестыВидит пиковые нагрузки и тестирует именно их
Проверяет, что оптимизация сработалаВидит, упало ли время ответа после оптимизации

§13.5. Трассировка: отслеживание запроса по всей системе

Трассировка

— это отслеживание пути одного запроса через все сервисы системы.

Простая аналогия: трассировка — это как трекинг посылки. Вы видите, где посылка:

  • «Покинула склад».
  • «Прибыла в сортировочный центр».
  • «Отправлена в ваш город».
  • «Задержана на таможне».

Вы точно знаете, на каком этапе проблема.

В микросервисах трассировка становится критически важной. Запрос может проходить через 5, 10, даже 20 сервисов. Если что-то упало — без трассировки непонятно, где именно.

Почему трассировка нужна именно в микросервисах? В монолите всё просто: «Запрос → Монолитное приложение → Ответ».

Если что-то упало — ошибка в одном месте. Понятно, где искать.

В микросервисах сложно: «Запрос → API Gateway → Сервис А → Сервис Б → Сервис В → Сервис Г → Ответ».

Если что-то упало — непонятно, в каком из 5 сервисов ошибка.

Простая аналогия:

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

Чтобы увидеть, сколько времени уходит на каждый внутренний вызов системы при обработке одного действия, используют распределенную трассировку. Посмотрим на примере, как выглядит путь клиентского запроса «создать заказ»:

bash

Запрос: POST /api/order
Trace ID: abc-123-def-456

├── API Gateway (5ms)
│   ├── Проверка токена (2ms) ✅
│   └── Маршрутизация (3ms) ✅
│
├── Auth Service (3ms)
│   └── Проверка прав пользователя (3ms) ✅
│
├── Order Service (15ms)
│   ├── Проверка заказа (5ms) ✅
│   └── Запрос к БД (10ms) ✅
│
├── Payment Service (FAILED)
│   ├── Проверка статуса платежа (2ms) ✅
│   └── Запрос к платежному шлюзу (TIMEOUT) ❌
│
└── User Service (4ms)
    └── Получение данных пользователя (4ms) ✅

Результат: 500 Internal Server Error
Проблема: Payment Service → таймаут при запросе к платежному шлюзу

Что мы видим:

  • Запрос прошел через 5 сервисов.
  • В 4 сервисах всё хорошо.
  • В Payment Service произошел таймаут.
  • Мы точно знаем, где проблема!

Чтобы сквозной мониторинг работал корректно, каждый запрос обрастает специальными служебными метками. Сводка основных компонентов трассировки с примерами и назначением представлена в таблице:

ЧтоПримерЗачем
Trace IDabc-123-def-456Идентификатор всего запроса. Одинаковый для всех сервисов
Span IDspan-001, span-002Идентификатор одного шага внутри сервиса
Service NamePayment ServiceНазвание сервиса
OperationЗапрос к платежному шлюзуЧто делали
DurationTIMEOUT или 2msСколько времени заняло
Status✅ или ❌Успешно или ошибка

Трассировка превращает долгие поиски виноватого микросервиса в точечную диагностику. Посмотрим на реальных примерах, как она решает проблемы с ошибками, медленной работой и расследованием инцидентов.

Чтобы собирать и анализировать пути запросов между сервисами, применяются как независимые open-source системы, так и комплексные облачные решения. Посмотрим на ключевые инструменты:

ИнструментЧто делает
JaegerПопулярный инструмент для трассировки (OpenTracing)
ZipkinЕще один инструмент для трассировки
Application InsightsТрассировка + логи + метрики в Azure
OpenTelemetryСтандарт для сбора трассировок

В руках тестировщика трассировка превращается в инструмент сквозного контроля микросервисной архитектуры.

Посмотрим, как она помогает находить сбои интеграции и медленные участки:

Что делает тестировщикКак трассировка помогает
Находит, какой сервис упалВидит в трассировке, где ошибка
Проверяет, что запрос прошел все сервисыВидит полный путь запроса
Анализирует медленные запросыВидит, какой сервис тормозит
Проверяет корректность интеграцииВидит, что запрос прошел через все нужные сервисы

§13.6. Логи + Метрики + Трассы = Полная картина

Логи, метрики и трассировка

— это не три разных инструмента, которые работают по отдельности. Это три части одного целого. Каждый дает свой кусочек картины, а вместе они дают полное понимание того, что происходит в системе.

Простая аналогия – это детективное расследование.

ИнструментЧто даетАналогия в детективе
Метрики«Что-то пошло не так»«В доме кто-то был»
Трассировка«Где именно»«Вор прошел через окно»
Логи«Что именно случилось»«Вор украл картину»

По отдельности каждый тип данных отвечает лишь на часть вопросов, но вместе они дают полную картину состояния системы. Посмотрим, как логи, метрики и трассировка дополняют друг друга на практике.

Чтобы закрепить концепцию Observability на практике, проследим за слаженной работой всех трех компонентов в реальном сценарии. Увидеть пошаговый алгоритм расследования сложного инцидента от первого сигнала до точной причины поможет разбор ниже.

Шаг №1. Метрики показали проблему

wireframe

Метрики за последние 10 минут:

- Error Rate: 0% → 5% (резкий рост!)

- RPS: 100 → 200 (нагрузка выросла)

- Latency: 200ms → 500ms (время ответа выросло)

Вывод: Что-то пошло не так. Началось примерно в 15:20.

Шаг №2. Трассировка показала, где

wireframe

Trace ID: abc-123-def-456

Запрос: POST /api/order (15:23:45)

├── API Gateway (5ms) ✅

├── Auth Service (3ms) ✅

├── Order Service (15ms) ✅

├── Payment Service (FAILED) ❌ ← ПРОБЛЕМА ЗДЕСЬ!

└── User Service (4ms) ✅

Вывод: Проблема в Payment Service. Запрос дошел до него и упал.

Шаг №3. Логи показали, почему

wireframe

Логи Payment Service в 15:23:45:

[ERROR] Payment failed for order #12345: insufficient funds

[ERROR] User 456 has balance 50.00, attempted to pay 100.00

[WARNING] Order #12345 status changed to "payment_failed"

Какой мы можем сделать вывод? У пользователя недостаточно средств. Ошибка не в системе, а в данных.

Итоговая схема наглядно объединяет все три компонента Observability в единый замкнутый контур. Увидеть, как метрики, трассировка и логи собираются в единую карту инцидента, поможет итоговая визуализация ниже:

Для тестировщика связка метрик, трассировки и логов — это способ быстро отделить баги системы от ошибок в пользовательских сценариях. Посмотрим на примере, как выглядит этот процесс расследования. Для примера возьмем ситуацию, когда пользователь сообщает, что не может оплатить заказ.

Тестировщик:

1. Смотрю метрики. Error Rate вырос с 0% до 5% в последние 15 минут. Значит, проблема массовая, не у одного пользователя.

2. Смотрю трассировку. Нахожу один из упавших запросов. Вижу, что проблема в Payment Service — запрос дошел до него и упал.

3. Смотрю логи в Payment Service. Вижу конкретную ошибку: «insufficient funds». У пользователя недостаточно средств.

4. Пишу отчет: «Проблема не в системе. Пользователи пытаются оплатить заказы, но у них недостаточно средств. Возможно, в приложении не отображается ошибка понятно для пользователя. Нужно улучшить сообщение об ошибке.».

Чтобы всегда держать в голове назначение каждого инструмента, удобно использовать простую матрицу соответствия вопросов и ответов. Сводная таблица ниже наглядно закрепляет эту логику представлена ниже:

ИнструментВопросОтвет
Метрики«Что-то не так?»«Да, ошибок стало больше»
Трассировка«Где?»«В Payment Service»
Логи«Почему?»«Недостаточно средств»

Без одного из них — картина неполная.

Чего нетЧто теряем
Нет метрикНе знаем, что проблема началась
Нет трассировкиНе знаем, в каком сервисе проблема
Нет логовНе знаем, почему проблема произошла

§13.7. Инструменты мониторинга для .NET

В мире .NET есть несколько инструментов для мониторинга. Они делятся на две категории:

КатегорияЧто делаютПримеры
Библиотеки для кодаДобавляют логи, метрики, трассировку в кодSerilog, OpenTelemetry
Системы для сбора и храненияСобирают и хранят данныеELK Stack, Prometheus, Application Insights
Системы для визуализацииПоказывают данные в виде графиковGrafana, Kibana, Application Insights

Простая аналогия:

  • Библиотека (Serilog) — это как ручка, которой вы пишете.
  • Система сбора (ELK, Prometheus) — это как сейф, где вы храните записи.
  • Система визуализации (Grafana, Kibana) — это как стол, на котором вы раскладываете записи, чтобы их прочитать.

Переходя от теоретических основ Observability к практической реализации в экосистеме .NET, начнем с инструментов логирования.

Библиотека №1. Serilog

Serilog

  • это популярная библиотека для логирования в .NET. Она простая и гибкая.

Как она выглядит:

csharp

using Serilog;

Log.Logger = new LoggerConfiguration()
    .WriteTo.Console()
    .WriteTo.File("logs/app.log")
    .CreateLogger();
Log.Information("User {UserId} created order {OrderId}", 
                userId, orderId);
Log.Warning("Payment declined for order {OrderId}: {Reason}", 
            orderId, reason);
Log.Error(ex, "Payment failed for order {OrderId}", orderId);

Что умеет данная библиотека:

ВозможностьЧто делает
Запись в разные местаКонсоль, файл, база данных, облако
Структурированные логиЛоги в формате JSON, легко искать
Уровни логированияDebug, Info, Warning, Error, Critical

Библиотека №2. OpenTelemetry

OpenTelemetry

  • это стандарт для сбора логов, метрик и трассировки. Поддерживается многими инструментами.

Вместо того чтобы использовать разные библиотеки для логов, метрик и трассировки, вы используете один стандарт. И данные можно отправлять в любую систему (Prometheus, Jaeger, Application Insights). Как это выглядит:

csharp

using OpenTelemetry;
using OpenTelemetry.Trace;

var tracer = tracerProvider.GetTracer("MyApp");

using var span = tracer.StartActiveSpan("ProcessOrder");
span.SetAttribute("order.id", orderId);

try
{
    // ... логика ...
    span.SetStatus(Status.Ok);
}
catch (Exception ex)
{
    span.SetStatus(Status.Error);
    span.RecordException(ex);
    throw;
}

Мало собрать и записать логи в коде — централизованная система наблюдаемости требует надежного инфраструктурного бэкенда для их хранения и анализа. Рассмотреть классический стек для работы с логами, компоненты которого закрывают весь путь от сбора до визуализации, можно в разборе ниже.

ELK Stack (Elasticsearch + Logstash + Kibana)

Это три инструмента, которые всегда работают вместе.

ИнструментЧто делает
ElasticsearchХранит и индексирует логи
LogstashСобирает логи из разных источников
KibanaВизуализация и поиск по логам

Это необходимо использовать тогда, когда у вас много логов и нужно их быстро искать. Что умеют эти инструменты:

ВозможностьЧто делает
Поиск по логамНайти все логи по пользователю, ошибке, времени
ФильтрацияПоказать только ошибки за последний час
АгрегацияСколько ошибок в час, какие ошибки чаще всего

Для работы с метриками используется промышленный стандарт мониторинга — связка Prometheus и Grafana. Изучить разделение ролей между сборщиком числовых данных и инструментом их визуализации можно в таблице ниже.

ИнструментЧто делает
PrometheusСобирает и хранит метрики
GrafanaПоказывает метрики в виде графиков

Так же инструмент Grafana имеет следующие возможности:

ВозможностьЧто делает
ДашбордыГрафики, таблицы, показатели на одной странице
АлертыУведомления, если метрика выходит за норму
Множество источниковPrometheus, Elasticsearch, SQL, и другие

Чтобы оценить, как вся собранная телеметрия выглядит на практике для инженера или тестировщика, рассмотрим визуальное представление дашборда мониторинга. Увидеть пример того, как метрики преобразуются в наглядные панели управления в Grafana, можно на схеме ниже.

§13.8. Интеграция с CI/CD: мониторинг как часть релиза

Мы привыкли думать, что мониторинг — это то, что делают после релиза. Запустили код, смотрим на графики.

Но на самом деле мониторинг должен быть частью процесса релиза. Релиз не заканчивается в момент деплоя. Релиз заканчивается, когда мы убедились, что система работает нормально.

Интеграция наблюдаемости в процесс CI/CD превращает мониторинг в активный инструмент управления качеством. Рассмотрим схему взаимодействия релизного цикла и контура обратной связи по метрикам.

Интеграция наблюдаемости в пайплайн доставки ПО превращает каждый релиз в контролируемую процедуру с четкими критериями успешности. Изучим ключевые этапы этого процесса — от CI/CD до продакшена и процедур отката.

ЭтапЧто происходит
1. Тесты прошлиCI/CD подтвердил, что код работает
2. Релиз на stagingКод развернут на тестовой среде
3. Наблюдение (1 час)Смотрим на метрики, нет ли аномалий
4. Релиз на продакшенЕсли всё хорошо — выкатываем
5. Наблюдение (еще час)Снова смотрим, нет ли проблем после релиза
6. Если проблема — откатВозвращаемся к предыдущей версии

Самое важное правило

«Если после релиза ошибок стало больше — откатываем. Если после релиза метрики ухудшились — откатываем релиз.».

Признаки проблемы:

Что видим в метрикахЧто это значит
Error Rate вырос с 0% до 5%Система начала падать
Latency выросла с 200 мс до 800 мсСистема стала медленнее
CPU вырос до 95%Система перегружена

В случае возникновения подобных проблем необходимо следовать следующим шагам:

Шаг №1. Заметили рост ошибок.

Шаг №2. Смотрим логи и трассировку (понимаем, что именно упало).

Шаг №3. Если проблема не исправляется быстро — откатываем релиз.

Шаг №4. Релиз откачен, ошибки исчезли.

Шаг №5. Разбираемся с проблемой в спокойной обстановке.

Это крайне важно, ведь если не откатить — пользователи увидят ошибки, система упадет, бизнес потеряет деньги.

Не все проблемы — это ошибки. Иногда система работает, но медленно. Представим следующий сценарий: «До релиза: Latency = 200 мс. После релиза: Latency = 500 мс.».

Что делаем:

1. Смотрим на график Latency. Когда начался рост? Сразу после релиза или постепенно?

2. Смотрим на график RPS. Нагрузка выросла или осталась той же? Если нагрузка та же — проблема в коде.

3. Смотрим на CPU и Memory. Они выросли? Возможно, код стал потреблять больше ресурсов.

4. Смотрим на логи. Нет ли новых медленных запросов?

5. Находим причину и исправляем.

В CI/CD мы научились автоматически запускать тесты при каждом push. Теперь мы добавляем мониторинг в этот процесс. Как это выглядит:

yaml

# GitHub Actions (упрощенно)
name: Release

on:
  push:
    branches: [ main ]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Deploy to staging
        run: deploy-staging.sh
      
      - name: Wait for stability (5 minutes)
        run: sleep 300
      
      - name: Check metrics
        run: check-metrics.sh
      
      - name: Deploy to production
        run: deploy-prod.sh
      
      - name: Wait for stability (5 minutes)
        run: sleep 300
      
      - name: Check metrics again
        run: check-metrics.sh

Автоматизация проверки состояния сервиса непосредственно внутри конвейера доставки исключает человеческий фактор при принятии решений о релизе. Изучить пошаговый алгоритм автоматического контроля метрик на этапах staging и production можно в таблице ниже:

ЭтапЧто происходит
Deploy to stagingВыкатываем на тестовую среду
Wait for stabilityДаем системе «прогреться» (5 минут)
Check metricsПроверяем Error Rate, Latency, CPU
Если метрики плохиеКонвейер падает, релиз не идет дальше
Deploy to productionЕсли всё хорошо — выкатываем на продакшен
Check metrics againПроверяем снова после релиза

Профилирование и мониторинг работают вместе:

ИнструментЧто делаетКогда
МониторингПостоянно смотрит на системуВсегда
ПрофилированиеГлубоко анализирует конкретную проблемуКогда мониторинг показал проблему

Завершает цикл работы с производительностью непрерывный контур обратной связи, где данные мониторинга переходят в задачи для оптимизации кода. Проследить полный жизненный цикл устранения узких мест — от обнаружения проблемы до подтверждения исправления — можно на схеме ниже.

Лучше всего суть Observability раскрывается на живых примерах. Посмотрим, как связка метрик, профилирования и исправления кода возвращает системе нормальную скорость работы.

wireframe

Мониторинг показал: Latency выросла с 200 мс до 500 мс.

Профилирование показало: метод SaveOrder() стал выполняться 2 секунды.

Разработчик исправил: оптимизировал запрос к БД.

Мониторинг снова показывает: Latency 200 мс.

Когда аномалия обнаружена прямо на продакшене, критически важно действовать по четкому алгоритму инцидент-менеджмента. Рассмотреть пошаговый план реагирования на деградацию метрик после выката новой версии можно в таблице ниже:

ШагЧто делаем
1Смотрим метрики: что именно ухудшилось? (Error Rate, Latency, CPU)
2Смотрим логи: какая конкретная ошибка?
3Смотрим трассировку: в каком сервисе проблема?
4Принимаем решение: исправляем или откатываем
5Если откатываем — возвращаемся к предыдущей версии
6Если исправляем — делаем фикс и выкатываем снова