MidПрактика3 min

Мониторинг и логирование на практике

Application Insights + Serilog, KQL-запросы, алерты, мониторинг dashboard

Практическое руководство по настройке мониторинга приложения в Azure с Application Insights, Serilog и KQL.

Настройка Application Insights

Подключение к ASP.NET Core

// Program.cs
builder.Services.AddApplicationInsightsTelemetry();
// appsettings.json
{
  "ApplicationInsights": {
    "ConnectionString": "InstrumentationKey=xxx;IngestionEndpoint=https://westeurope-5.in.applicationinsights.azure.com/"
  }
}

Что собирается автоматически

После подключения Application Insights автоматически фиксирует:

  • Все HTTP-запросы к вашему API (URL, время ответа, код статуса)
  • Зависимости (SQL-запросы, HTTP-вызовы, Redis-операции)
  • Необработанные исключения
  • Метрики производительности (CPU, память)
  • Связи между запросами (distributed tracing)

Structured Logging с Serilog

Serilog -- библиотека для структурированного логирования, интегрированная с Application Insights:

// Program.cs
builder.Host.UseSerilog((context, configuration) =>
{
    configuration
        .ReadFrom.Configuration(context.Configuration)
        .WriteTo.Console()
        .WriteTo.ApplicationInsights(
            TelemetryConfiguration.Active,
            TelemetryConverter.Traces)
        .Enrich.FromLogContext()
        .Enrich.WithProperty("Application", "OrderManagement");
});

Правильное использование

// ПРАВИЛЬНО: structured logging с параметрами
_logger.LogInformation(
    "Creating order for customer {CustomerId} with {ItemCount} items",
    command.CustomerId,
    command.Items.Count);

// НЕПРАВИЛЬНО: строковая конкатенация (теряются метаданные)
_logger.LogInformation(
    $"Creating order for customer {command.CustomerId} with {command.Items.Count} items");

Structured logging сохраняет CustomerId и ItemCount как отдельные свойства, по которым можно фильтровать в KQL.

KQL-запросы для мониторинга

Производительность

// Топ-10 самых медленных API endpoints (P95)
requests
| where timestamp > ago(24h)
| summarize
    avgDuration = avg(duration),
    p95Duration = percentile(duration, 95),
    requestCount = count()
  by name
| order by p95Duration desc
| take 10

// Зависимости -- время отклика SQL и Redis
dependencies
| where timestamp > ago(1h)
| summarize
    avg(duration),
    percentile(duration, 95),
    count()
  by target, type
| order by avg_duration desc

Ошибки

// Ошибки за последние 24 часа по типам
exceptions
| where timestamp > ago(24h)
| summarize count() by type, outerMessage
| order by count_ desc

// Процент ошибок по эндпоинтам
requests
| where timestamp > ago(1h)
| summarize
    total = count(),
    failed = countif(success == false)
  by name
| extend errorRate = round(100.0 * failed / total, 2)
| where errorRate > 0
| order by errorRate desc

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

// Количество заказов в час
customEvents
| where name == "OrderCreated" and timestamp > ago(24h)
| summarize orderCount = count() by bin(timestamp, 1h)
| render timechart

// End-to-end трассировка запроса
let operationId = "abc123";
union requests, dependencies, exceptions, traces
| where operation_Id == operationId
| order by timestamp asc
| project timestamp, itemType, name, duration, success, message

Настройка алертов

# Алерт: > 10 ошибок 5xx за 5 минут
az monitor metrics alert create \
  --name "HighErrorRate" \
  --resource-group rg-orderapp-dev \
  --scopes "/subscriptions/{sub}/resourceGroups/rg-orderapp-dev/providers/Microsoft.Web/sites/orderapp-dev-app" \
  --condition "count requests/failed > 10" \
  --window-size 5m \
  --evaluation-frequency 1m \
  --severity 1 \
  --action "/subscriptions/{sub}/resourceGroups/rg-orderapp-dev/providers/microsoft.insights/actionGroups/team-alerts"

# Алерт: среднее время ответа > 3 секунды
az monitor metrics alert create \
  --name "HighLatency" \
  --resource-group rg-orderapp-dev \
  --scopes "..." \
  --condition "avg requests/duration > 3000" \
  --window-size 5m

Availability Tests

Проверка доступности вашего приложения из нескольких точек мира:

az monitor app-insights web-test create \
  --resource-group rg-orderapp-dev \
  --app-insights-name orderapp-dev-insights \
  --web-test-name "Health Check" \
  --location "West Europe" \
  --url "https://orderapp-dev-app.azurewebsites.net/health" \
  --frequency 300 \
  --timeout 30

Health Checks

Endpoint /health проверяет все зависимости вашего приложения:

builder.Services.AddHealthChecks()
    .AddSqlServer(connectionString, name: "sql")
    .AddAzureBlobStorage(blobConnectionString, name: "blob")
    .AddRedis(redisConnectionString, name: "redis");

app.MapHealthChecks("/health", new HealthCheckOptions
{
    ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
});

Dashboard

Создание мониторинг-панели в Azure Portal:

  1. Azure Portal -> Dashboard -> New Dashboard
  2. Добавить виджеты:
    • Application Map -- визуальная карта зависимостей
    • Request Rate & Duration -- количество и время запросов
    • Failed Requests -- количество ошибок
    • Server Response Time -- время ответа сервера
    • Dependencies Duration -- время зависимостей (SQL, Redis)
    • Custom Metrics -- бизнес-метрики (OrderCreated count)

Рекомендации для production

  1. Structured Logging -- всегда параметры через {Placeholder}, не строковая конкатенация
  2. Distributed Tracing -- включите W3C Trace Context для отслеживания запросов между сервисами
  3. Sampling -- настройте сэмплирование для снижения объема данных и стоимости
  4. Retention -- по умолчанию 90 дней, настройте под ваши требования
  5. Alerts -- настройте алерты на ключевые метрики ДО появления проблем
  6. Health Checks -- endpoint /health с проверкой всех зависимостей

Проверь себя

Почему в Serilog нужно использовать {CustomerId} вместо $"{customerId}"?

Availability Test проверяет:

Какой KQL-оператор используется для визуализации данных в виде графика?