Документация

Sentry Integration API

Версия v2.3.1 · Обновлено

Sentry integration API#

Этот документ описывает поведение бэкенд-API IncidentRelay для входящей интеграции с Sentry.

Эндпоинт#

POST /api/integrations/sentry/{route_id}

Этот эндпоинт принимает вебхуки Sentry Internal Integration.

В отличие от интеграций Alertmanager, Zabbix и Generic Webhook, эндпоинт Sentry не использует токен приёма IncidentRelay. Аутентификация основана на идентификаторе маршрута и проверке Sentry-Hook-Signature.

Обязательные заголовки#

ЗаголовокОбязателенОписание
Content-Type: application/jsonДаSentry отправляет полезные нагрузки вебхуков в формате JSON.
Sentry-Hook-SignatureДаHMAC-подпись, сгенерированная Sentry с использованием Client Secret внутренней интеграции.
Sentry-Hook-ResourceРекомендуетсяИмя ресурса Sentry, например event_alert, metric_alert, issue.

Требования к маршруту#

Маршрут, определяемый по {route_id}, должен:

  • существовать;
  • иметь source=sentry;
  • быть включённым;
  • принадлежать активной команде и активной группе;
  • иметь настроенный integration_config.sentry.webhook_secret.

Пример сохранённой конфигурации маршрута:

{
  "sentry": {
    "webhook_secret": "client-secret-from-sentry"
  }
}

Сериализация API не должна возвращать секрет. Она должна возвращать только:

{
  "sentry": {
    "has_webhook_secret": true,
    "webhook_path": "/api/integrations/sentry/42"
  }
}

Проверка подписи#

IncidentRelay валидирует запрос, вычисляя дайджест HMAC-SHA256 по сырому телу запроса с использованием секрета вебхука Sentry для данного маршрута.

Псевдокод:

expected = hmac.new(
    secret.encode("utf-8"),
    raw_body,
    hashlib.sha256,
).hexdigest()

valid = hmac.compare_digest(expected, request.headers["Sentry-Hook-Signature"])

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

Коды ответов#

СтатусОшибкаЗначение
404route_not_foundДля {route_id} не существует маршрута.
400route_source_mismatchМаршрут существует, но не имеет source=sentry.
403route_disabledМаршрут отключён или удалён.
403route_team_inactiveКоманда маршрута удалена или неактивна.
403route_group_inactiveГруппа маршрута удалена или неактивна.
409sentry_secret_not_configuredУ маршрута нет Client Secret для Sentry.
403sentry_signature_missingЗапрос не содержит Sentry-Hook-Signature.
403sentry_signature_invalidПодпись не совпадает с телом и секретом.
400validation_errorТело запроса не является корректной полезной нагрузкой Sentry в формате JSON.

Нормализованный вывод алерта#

Нормализатор возвращает список с одним объектом алерта IncidentRelay.

Пример нормализованного вывода для event_alert.triggered:

{
  "source": "sentry",
  "team_slug": null,
  "external_id": "12345",
  "dedup_key": "sentry:issue:12345",
  "title": "ZeroDivisionError",
  "message": "division by zero",
  "severity": "critical",
  "status": "firing",
  "labels": {
    "alertname": "SentryIssueAlert",
    "severity": "critical",
    "sentry_resource": "event_alert",
    "sentry_action": "triggered",
    "organization_slug": "acme",
    "organization_name": "Acme",
    "project_slug": "backend-api",
    "project_name": "Backend API",
    "issue_id": "12345",
    "issue_short_id": "BACKEND-1",
    "event_id": "event-abc",
    "environment": "production",
    "level": "error",
    "sentry_url": "https://sentry.example.com/issues/12345/"
  },
  "payload": {}
}

Сопоставление серьёзности#

Уровень/статус SentryСерьёзность IncidentRelay
fatalcritical
criticalcritical
errorcritical
warningwarning
warnwarning
infoinfo
debuginfo
resolvedinfo
okinfo
unknownwarning

Сопоставление статусов#

Ресурс/действие SentryСтатус IncidentRelay
event_alert.triggeredfiring
metric_alert.criticalfiring
metric_alert.warningfiring
metric_alert.resolvedresolved
issue.createdfiring
issue.unresolvedfiring
issue.resolvedresolved
issue.ignoredresolved
issue.archivedresolved

Ключи дедупликации#

Алерты на основе issue:

sentry:issue:<issue_id>

Метрические алерты:

sentry:metric:<sentry_alert_id>

Запасной вариант:

make_dedup_key("sentry", external_id, title, labels)

Полезная нагрузка создания/обновления маршрута#

Создание маршрута без секрета разрешено, чтобы пользователь мог сначала получить URL вебхука:

{
  "team_id": 1,
  "name": "Sentry Backend",
  "source": "sentry",
  "rotation_id": null,
  "escalation_policy_id": null,
  "channel_ids": [],
  "matchers": {},
  "group_by": ["project_slug", "issue_id"],
  "integration_config": {},
  "enabled": true
}

Сохранение секрета позже:

{
  "team_id": 1,
  "name": "Sentry Backend",
  "source": "sentry",
  "rotation_id": null,
  "escalation_policy_id": null,
  "channel_ids": [],
  "matchers": {},
  "group_by": ["project_slug", "issue_id"],
  "integration_config": {
    "sentry": {
      "webhook_secret": "client-secret-from-sentry"
    }
  },
  "enabled": true
}

При обновлении пустой секрет Sentry означает: сохранить существующий сохранённый секрет.

Переключение маршрута с source=sentry на другой источник должно очищать integration_config.