341 lines
9.9 KiB
Markdown
341 lines
9.9 KiB
Markdown
# Мониторинг
|
||
|
||
## Обзор
|
||
|
||
Мониторинг Quoter включает в себя логирование, метрики производительности и отслеживание состояния системы.
|
||
|
||
## Логирование
|
||
|
||
### Уровни логирования
|
||
|
||
Quoter использует библиотеку `log` с различными уровнями:
|
||
|
||
- **error** - Критические ошибки, требующие немедленного внимания
|
||
- **warn** - Предупреждения, которые могут указывать на проблемы
|
||
- **info** - Информационные сообщения о нормальной работе
|
||
- **debug** - Отладочная информация для разработчиков
|
||
- **trace** - Максимальная детализация для глубокой отладки
|
||
|
||
### Настройка логирования
|
||
|
||
```bash
|
||
# Только ошибки
|
||
RUST_LOG=error cargo run
|
||
|
||
# Предупреждения и ошибки
|
||
RUST_LOG=warn cargo run
|
||
|
||
# Информационные сообщения (рекомендуется для продакшена)
|
||
RUST_LOG=info cargo run
|
||
|
||
# Отладка
|
||
RUST_LOG=debug cargo run
|
||
|
||
# Максимальная детализация
|
||
RUST_LOG=trace cargo run
|
||
```
|
||
|
||
### Структура логов
|
||
|
||
#### Загрузка файла
|
||
```
|
||
[INFO] Started
|
||
[WARN] file abc123.jpg uploaded to storj, incrementing quota by 1048576 bytes
|
||
[WARN] New quota for user user123: 2097152 bytes
|
||
```
|
||
|
||
#### Получение файла
|
||
```
|
||
[WARN] >>> GET image_300.jpg [START]
|
||
[WARN] detected file extension: jpg
|
||
[WARN] base_filename: image
|
||
[WARN] requested width: 300
|
||
[WARN] Found stored path in DB: production/image/image.jpg
|
||
[WARN] File exists in Storj: production/image/image.jpg
|
||
[WARN] Processing image file with width: 300
|
||
[WARN] Calculated closest width: 300 for requested: 300
|
||
[WARN] serve existed thumb file: image_300.jpg
|
||
```
|
||
|
||
#### Ошибки
|
||
```
|
||
[ERROR] Failed to upload to Storj: image.jpg - Error: Network error
|
||
[ERROR] Database error while getting path: image.jpg - Full error: Connection timeout
|
||
[ERROR] unsupported file format
|
||
```
|
||
|
||
## Метрики
|
||
|
||
### Основные метрики для мониторинга
|
||
|
||
#### Производительность
|
||
- **Requests per second (RPS)** - количество запросов в секунду
|
||
- **Response time** - время ответа API
|
||
- **Error rate** - процент ошибок
|
||
- **Upload success rate** - процент успешных загрузок
|
||
|
||
#### Ресурсы
|
||
- **Memory usage** - использование памяти
|
||
- **CPU usage** - использование процессора
|
||
- **Disk I/O** - операции с диском
|
||
- **Network I/O** - сетевой трафик
|
||
|
||
#### Бизнес-метрики
|
||
- **Files uploaded** - количество загруженных файлов
|
||
- **Quota usage** - использование квот пользователями
|
||
- **Thumbnail generation** - количество сгенерированных миниатюр
|
||
- **Storage usage** - использование хранилища
|
||
|
||
### Prometheus метрики
|
||
|
||
Добавьте в `Cargo.toml`:
|
||
|
||
```toml
|
||
[dependencies]
|
||
prometheus = "0.13"
|
||
actix-web-prom = "0.6"
|
||
```
|
||
|
||
Настройте в `main.rs`:
|
||
|
||
```rust
|
||
use actix_web_prom::{PrometheusMetrics, PrometheusMetricsBuilder};
|
||
|
||
#[actix_web::main]
|
||
async fn main() -> std::io::Result<()> {
|
||
let prometheus = PrometheusMetricsBuilder::new("quoter")
|
||
.endpoint("/metrics")
|
||
.build()
|
||
.unwrap();
|
||
|
||
HttpServer::new(move || {
|
||
App::new()
|
||
.wrap(prometheus.clone())
|
||
// ... остальные настройки
|
||
})
|
||
.bind(addr)?
|
||
.run()
|
||
.await
|
||
}
|
||
```
|
||
|
||
### Кастомные метрики
|
||
|
||
```rust
|
||
use prometheus::{Counter, Histogram, Registry};
|
||
|
||
lazy_static! {
|
||
pub static ref UPLOAD_COUNTER: Counter = Counter::new(
|
||
"quoter_uploads_total",
|
||
"Total number of file uploads"
|
||
).unwrap();
|
||
|
||
pub static ref UPLOAD_SIZE: Histogram = Histogram::new(
|
||
"quoter_upload_size_bytes",
|
||
"File upload size in bytes"
|
||
).unwrap();
|
||
|
||
pub static ref QUOTA_USAGE: Histogram = Histogram::new(
|
||
"quoter_quota_usage_bytes",
|
||
"Author quota usage in bytes"
|
||
).unwrap();
|
||
}
|
||
```
|
||
|
||
## Алерты
|
||
|
||
### Критические алерты
|
||
|
||
- **Service down** - сервис недоступен
|
||
- **High error rate** - высокий процент ошибок (>5%)
|
||
- **High response time** - медленные ответы (>2s)
|
||
- **Memory usage high** - высокое использование памяти (>80%)
|
||
- **Redis connection failed** - потеря соединения с Redis
|
||
|
||
### Предупреждения
|
||
|
||
- **Quota usage high** - пользователи приближаются к лимиту квоты
|
||
- **Storage usage high** - высокое использование хранилища
|
||
- **Thumbnail generation slow** - медленная генерация миниатюр
|
||
|
||
### Настройка алертов в Prometheus
|
||
|
||
```yaml
|
||
groups:
|
||
- name: quoter
|
||
rules:
|
||
- alert: QuoterServiceDown
|
||
expr: up{job="quoter"} == 0
|
||
for: 1m
|
||
labels:
|
||
severity: critical
|
||
annotations:
|
||
summary: "Quoter service is down"
|
||
|
||
- alert: HighErrorRate
|
||
expr: rate(http_requests_total{job="quoter",status=~"5.."}[5m]) > 0.05
|
||
for: 2m
|
||
labels:
|
||
severity: warning
|
||
annotations:
|
||
summary: "High error rate detected"
|
||
|
||
- alert: HighResponseTime
|
||
expr: histogram_quantile(0.95, rate(http_request_duration_seconds_bucket{job="quoter"}[5m])) > 2
|
||
for: 5m
|
||
labels:
|
||
severity: warning
|
||
annotations:
|
||
summary: "High response time detected"
|
||
```
|
||
|
||
## Дашборды
|
||
|
||
### Grafana дашборд
|
||
|
||
Создайте дашборд с панелями:
|
||
|
||
#### Обзор системы
|
||
- Статус сервиса (up/down)
|
||
- Количество запросов в секунду
|
||
- Время ответа (p50, p95, p99)
|
||
- Процент ошибок
|
||
|
||
#### Загрузка файлов
|
||
- Количество загрузок в час/день
|
||
- Размер загружаемых файлов
|
||
- Успешность загрузок
|
||
- Использование квот
|
||
|
||
#### Ресурсы
|
||
- Использование CPU и памяти
|
||
- Сетевой трафик
|
||
- Операции с диском
|
||
- Соединения с Redis
|
||
|
||
#### Бизнес-метрики
|
||
- Топ пользователей по использованию квоты
|
||
- Популярные размеры миниатюр
|
||
- Использование хранилища по типам файлов
|
||
|
||
### Пример запроса для Grafana
|
||
|
||
```sql
|
||
-- Количество загрузок по часам
|
||
SELECT
|
||
time_bucket('1 hour', timestamp) AS time,
|
||
COUNT(*) as uploads
|
||
FROM quoter_uploads
|
||
WHERE timestamp > NOW() - INTERVAL '24 hours'
|
||
GROUP BY time
|
||
ORDER BY time;
|
||
```
|
||
|
||
## Здоровье системы
|
||
|
||
### Health check endpoint
|
||
|
||
Добавьте endpoint для проверки здоровья:
|
||
|
||
```rust
|
||
async fn health_check() -> HttpResponse {
|
||
// Проверка Redis
|
||
let redis_ok = check_redis_connection().await;
|
||
|
||
// Проверка S3
|
||
let s3_ok = check_s3_connection().await;
|
||
|
||
if redis_ok && s3_ok {
|
||
HttpResponse::Ok().json(json!({
|
||
"status": "healthy",
|
||
"timestamp": chrono::Utc::now(),
|
||
"services": {
|
||
"redis": "ok",
|
||
"s3": "ok"
|
||
}
|
||
}))
|
||
} else {
|
||
HttpResponse::ServiceUnavailable().json(json!({
|
||
"status": "unhealthy",
|
||
"timestamp": chrono::Utc::now(),
|
||
"services": {
|
||
"redis": if redis_ok { "ok" } else { "error" },
|
||
"s3": if s3_ok { "ok" } else { "error" }
|
||
}
|
||
}))
|
||
}
|
||
}
|
||
```
|
||
|
||
### Kubernetes liveness/readiness probes
|
||
|
||
```yaml
|
||
livenessProbe:
|
||
httpGet:
|
||
path: /health
|
||
port: 8080
|
||
initialDelaySeconds: 30
|
||
periodSeconds: 10
|
||
timeoutSeconds: 5
|
||
failureThreshold: 3
|
||
|
||
readinessProbe:
|
||
httpGet:
|
||
path: /health
|
||
port: 8080
|
||
initialDelaySeconds: 5
|
||
periodSeconds: 5
|
||
timeoutSeconds: 3
|
||
failureThreshold: 3
|
||
```
|
||
|
||
## Трассировка
|
||
|
||
### Distributed tracing
|
||
|
||
Для отслеживания запросов через микросервисы:
|
||
|
||
```toml
|
||
[dependencies]
|
||
opentelemetry = "0.20"
|
||
tracing = "0.1"
|
||
tracing-opentelemetry = "0.20"
|
||
```
|
||
|
||
### Логирование с контекстом
|
||
|
||
```rust
|
||
use tracing::{info, warn, error, instrument};
|
||
|
||
#[instrument(skip(state))]
|
||
async fn upload_handler(
|
||
req: HttpRequest,
|
||
payload: Multipart,
|
||
state: web::Data<AppState>,
|
||
) -> Result<HttpResponse> {
|
||
let user_id = get_user_id(&req).await?;
|
||
info!(user_id = %user_id, "Starting file upload");
|
||
|
||
// ... логика загрузки
|
||
|
||
info!(user_id = %user_id, filename = %filename, "File uploaded successfully");
|
||
Ok(response)
|
||
}
|
||
```
|
||
|
||
## Рекомендации
|
||
|
||
### Продакшен
|
||
|
||
1. **Логирование**: Используйте структурированные логи в JSON формате
|
||
2. **Метрики**: Настройте Prometheus + Grafana
|
||
3. **Алерты**: Настройте уведомления для критических событий
|
||
4. **Ротация логов**: Настройте logrotate или отправку в ELK stack
|
||
5. **Мониторинг ресурсов**: Отслеживайте CPU, память, диск, сеть
|
||
|
||
### Разработка
|
||
|
||
1. **Локальное логирование**: Используйте `RUST_LOG=debug`
|
||
2. **Отладка**: Включите trace логи для детальной отладки
|
||
3. **Тестирование**: Создайте тесты для проверки метрик
|
||
4. **Документация**: Документируйте все кастомные метрики |