Дата: 2026-06-20
Задачи: LAN-67 (OTEL), LAN-68 (Sentry/Prometheus), LAN-69 (influx→prom-client), LAN-70 (Grafana)
| Слой | On-prem | Cloud/SaaS |
|---|---|---|
| Traces | Jaeger / Grafana Tempo (OTLP HTTP) | Cloudflare Workers Observability |
| Metrics | Prometheus + Grafana | Managed Prometheus (Grafana Cloud) |
| Errors | Self-hosted Sentry | Sentry.io |
| LLM observability | Self-hosted Langfuse | Langfuse Cloud |
| Logs | pino → fluentd/Loki | Grafana Loki |
# Включить OTEL трассировку
OTEL_ENABLED=true
# Имя сервиса в трассах — задаётся для каждого процесса
OTEL_SERVICE_NAME=smarty-api # api-rest
# OTEL_SERVICE_NAME=smarty-dialog # smarty-dialog
# OTEL_SERVICE_NAME=smarty-sip # smarty-sip / smarty-conference
# ... и т.д. для каждого из 18+ сервисов
# OTLP endpoint (Jaeger / Tempo)
OTEL_EXPORTER_OTLP_ENDPOINT=http://tempo:4318
# Sampling ratio (0.0–1.0; 0.1 = 10% запросов)
OTEL_TRACES_SAMPLER_ARG=0.1
Обязательно загружать трассировку первым:
# В ecosystem.config.js для pm2:
node_args: '-r ./lib/tracing.js'
# Или через NODE_OPTIONS:
NODE_OPTIONS='-r /app/lib/tracing.js' node api-rest/service.js
# Включить /metrics endpoint
METRICS_ENABLED=true
# Опциональный токен защиты (заголовок X-Metrics-Token)
METRICS_TOKEN=your-internal-token
Endpoint: GET /metrics → Prometheus text format.
Prometheus scrape config (prometheus.yml):
scrape_configs:
- job_name: 'smarty-api'
static_configs:
- targets: ['smarty-api:3000']
metrics_path: /metrics
params:
format: ['prometheus']
# При использовании токена:
# authorization:
# type: Bearer
# credentials: your-internal-token
SENTRY_DSN=https://xxxx@sentry.io/yyyy
SENTRY_ENVIRONMENT=production
SENTRY_RELEASE=2.93.0-git-abc123 # рекомендуется: npm_package_version + git SHA
SENTRY_TRACES_RATE=0.05
Sentry инициализируется автоматически при наличии SENTRY_DSN. При отсутствии — работает в no-op режиме.
LANGFUSE_ENABLED=true
LANGFUSE_PUBLIC_KEY=pk-...
LANGFUSE_SECRET_KEY=sk-...
LANGFUSE_BASEURL=https://langfuse.your-domain.com # self-hosted
При включённом OTEL, каждый startTrace() автоматически добавляет otelTraceId в metadata — это позволяет перейти из Langfuse trace в Jaeger/Tempo span.
| Метрика | Тип | Описание |
|---|---|---|
smarty_http_request_duration_ms |
Histogram | Latency HTTP запросов (buckets: 5..5000 ms) |
smarty_http_requests_total |
Counter | Всего HTTP запросов |
smarty_http_errors_total |
Counter | HTTP ошибки 4xx/5xx |
smarty_mq_messages_processing |
Gauge | RabbitMQ сообщений в обработке |
smarty_mq_messages_consumed_total |
Counter | Всего обработано MQ сообщений |
smarty_bot_lock_active |
Gauge | Активных bot-execution-lock |
smarty_agent_loop_iterations_total |
Counter | Итераций agent loop |
smarty_business_events_total |
Counter | Бизнес-события (заменяет InfluxDB) |
smarty_process_* |
various | Node.js process метрики (CPU, memory) |
const { mqMessagesProcessing, botLockActive, recordBusinessEvent } = require('./lib/metrics');
// MQ gauge
mqMessagesProcessing.inc({ queue: 'calls-webrtc' });
// ... обработка ...
mqMessagesProcessing.dec({ queue: 'calls-webrtc' });
// Bot lock
botLockActive.inc({ ws_id: wsId.toString() });
// ... unlock ...
botLockActive.dec({ ws_id: wsId.toString() });
// Business event (заменяет influxWritePoints)
recordBusinessEvent('call_events', 'zadarma send call');
influxWritePoints(measurement, event, startTime, metric) → recordBusinessEvent(measurement, event).
Сигнатура обратно совместима: старые калlers (callSend.js, ocrPerformed.js, rateConfirm.js, smsSend.js) не изменены. Лишние аргументы (startTime, metric) игнорируются — они использовались только для telegraf/influx, которого больше нет.
Пакет influx ^5.6.3 удалён из package.json.
Файл: docs/grafana/smarty-nfr-dashboard.json
Импорт: Grafana → Dashboards → Import → Upload JSON file.
Панели:
# prometheus/alerts/smarty.yml
groups:
- name: smarty_nfr
rules:
- alert: HighP95Latency
expr: histogram_quantile(0.95, sum(rate(smarty_http_request_duration_ms_bucket[5m])) by (le)) > 500
for: 5m
labels: { severity: warning }
annotations:
summary: "HTTP p95 latency > 500ms"
- alert: HighErrorRate
expr: 100 * sum(rate(smarty_http_errors_total{error_type="server_error"}[5m])) / clamp_min(sum(rate(smarty_http_requests_total[5m])), 1) > 1
for: 2m
labels: { severity: critical }
annotations:
summary: "HTTP 5xx error rate > 1%"
- alert: BotLockStuck
expr: sum(smarty_bot_lock_active) > 20
for: 10m
labels: { severity: warning }
annotations:
summary: "More than 20 active bot locks for >10m — possible stuck loop"
- alert: MQOverload
expr: sum(smarty_mq_messages_processing) > 50
for: 5m
labels: { severity: warning }
annotations:
summary: "MQ consumer overloaded (>50 messages in-process)"
mqMessagesProcessing в smarty-db/db/mq.js (инкремент/декремент в subscribe handler)botLockActive в lib/durableExecution/temporalAdapter.js (inc/dec вокруг acquireLock)agentLoopIterations в smarty-dialog/lib/employeeBots/agentLoop.jsOTEL_SERVICE_NAME в каждый ecosystem.config.js / docker-compose service