Сбор событий с произвольных HTTP API (http-routes)
Плагин http-routes
HTTP-коллектор поддерживает добавление произвольных API с помощью плагина http-routes. Каждый экземпляр плагина запускает на указанном порту отдельный HTTP-сервер с заданным набором конечных точек (endpoint). Это позволяет, например, имитировать API коллекторов сторонних решений (Splunk HEC, Loki и др.) и принимать события от источников, которые умеют отправлять данные только по определенным протоколам.
Кроме порта, все остальные параметры HTTP-сервера (адрес привязки, TLS-сертификаты и т. д.) наследуются от основной конфигурации HTTP-коллектора.
Конфигурация
Корневые параметры плагина:
| Параметр | Тип | Описание |
|---|---|---|
listen-port | int | Порт, на котором запускается HTTP-сервер |
response-headers | map | Заголовки ответа, добавляемые ко всем конечным точкам |
response-body | string | Шаблон Liquid для тела ответа |
response-code | int | Код статуса ответа (по умолчанию 200) |
include-headers | string[] | Заголовки HTTP-запроса, включаемые в генерируемое событие |
routes | map | Словарь маршрутов API |
Маршруты (routes)
Каждый элемент словаря routes описывается объектом со следующими полями:
| Параметр | Тип | Описание |
|---|---|---|
response-headers | map | Дополнительные заголовки ответа (наследуются вложенными маршрутами) |
response-body | string | Шаблон тела ответа (переопределяет родительский) |
response-code | int | Код статуса ответа (переопределяет родительский) |
include-headers | string[] | Заголовки запроса для включения в событие (дополняют родительский список) |
produce-event | bool | Генерировать ли событие на основе запроса (по умолчанию true) |
routes | map | Вложенные подмаршруты |
Формат ключей маршрутов
Ключ маршрута задается строкой в одном из трех форматов:
| Формат | Пример | Описание |
|---|---|---|
/путь | /items | Задает часть URL-пути без метода. Создает недействующий endpoint, используемый для шаблонизации вложенных точек |
МЕТОД | POST | Создает действующий endpoint на полном пути родителя. Полезно, когда одному URL соответствуют разные методы |
МЕТОД /путь | GET /{id} | Создает действующий endpoint, путь формируется как сумма пути родителя и указанного подпути |
Пути поддерживают именованные параметры вида {имя} — при обращении к endpoint вместо параметра может быть передана произвольная строка. Значения параметров доступны в шаблоне тела ответа.
Шаблон тела ответа
Поле response-body использует синтаксис шаблонов Liquid. Внутри шаблона доступны следующие переменные:
| Переменная | Описание |
|---|---|
request.raw_body | Необработанное тело запроса |
request.body | Разобранное тело запроса (доступно при Content-Type: application/json) |
request.headers | Заголовки запроса |
request.path_params | Значения именованных параметров пути |
request.url.params | Query-параметры запроса |
request.url.raw | Полный URL запроса |
path | URL-путь конечной точки |
response.status_code | Код ответа из конфигурации |
Дополнительно доступен фильтр json, который преобразует значение в его JSON-представление.
Примеры
Postman Echo API
Пример реализации классического Echo API, возвращающего клиенту отправленную им информацию:
http-routes:
listen-port: 8080
response-headers:
"Content-Type": application/json
routes:
"GET /get":
response-body: |
{
"args": {{ request.url.params | json }},
"headers": {{ request.headers | json }},
"url": {{ request.url.raw | json }}
}
routes:
"GET /{id}":
response-body: |
{
"args": {{ request.url.params | json }},
"headers": {{ request.headers | json }},
"url": {{ request.url.raw | json }},
"id": {{ request.path_params.id | json }}
}
"POST /post": &body-based-endpoint
response-body: |
{
"args": {{ request.url.params | json }},
"data": {% if request.body %}{{ request.body | json }}{% else %}{{ request.raw_body | json }}{% endif %},
"headers": {{ request.headers | json }},
"json": {% if request.body %}{{ request.body | json }}{% else %}null{% endif %},
"url": {{ request.url.raw | json }}
}
"PUT /put": *body-based-endpoint
"PATCH /patch": *body-based-endpoint
"DELETE /delete": *body-based-endpoint
В этом примере используются YAML-якоря (&якорь) и псевдонимы (*якорь) для повторного использования одинаковой конфигурации конечных точек.
Endpoint GET /{id} вложен в GET /get, поэтому его итоговый путь — GET /get/{id}.
Проверка с помощью curl:
curl -X POST -d 'data' 'http://localhost:8080/post?arg=1&arg2=2&arg3=4'
Ответ сервера:
{
"args": {"arg":"1","arg2":"2","arg3":"4"},
"data": "data",
"headers": {"Accept":"*/*","Content-Length":"4","Content-Type":"application/x-www-form-urlencoded","Host":"localhost:8080","User-Agent":"curl/7.81.0"},
"json": null,
"url": "http://localhost:8080/post?arg=1&arg2=2&arg3=4"
}
При отправке JSON-данных шаблон автоматически заполняет поле json:
curl -X POST -H 'Content-Type: application/json' -d '["value1", "value2"]' \
'http://localhost:8080/post?arg=1&arg2=2&arg3=4'
{
"args": {"arg":"1","arg2":"2","arg3":"4"},
"data": ["value1","value2"],
"headers": {"Accept":"*/*","Content-Length":"20","Content-Type":"application/json","Host":"localhost:8080","User-Agent":"curl/7.81.0"},
"json": ["value1","value2"],
"url": "http://localhost:8080/post?arg=1&arg2=2&arg3=4"
}
Splunk HTTP Event Collector
Плагин http-routes позволяет имитировать API существующих коллекторов событий. Пример ниже воспроизводит Splunk HTTP Event Collector, что дает возможность принимать события от систем, настроенных на отправку данных в Splunk.
Конфигурация плагина:
http-routes:
listen-port: 8088
routes:
"POST /services/collector":
response-body: '{"text":"Success","code":0}'
routes:
"POST /event": {}
"POST /event/1.0": {}
"POST /raw": {}
"POST /raw/1.0": {}
"GET /health":
produce-event: false
"GET /health/1.0":
produce-event: false
Предоставляемые конечные точки:
| Метод и путь | Описание |
|---|---|
POST /services/collector | Отправка события без указания типа |
POST /services/collector/event | Отправка события с временной отметкой |
POST /services/collector/event/1.0 | То же (версионированный путь) |
POST /services/collector/raw | Отправка события в сыром виде |
POST /services/collector/raw/1.0 | То же (версионированный путь) |
GET /services/collector/health | Проверка работоспособности (событие не создается) |
GET /services/collector/health/1.0 | То же (версионированный путь) |
Для проверки можно использовать Vector с целью назначения типа splunk_hec_logs:
sources:
generator:
type: demo_logs
format: json
sinks:
splunkhec:
type: splunk_hec_logs
inputs: [generator]
endpoint: http://localhost:8088
endpoint_target: event
default_token: token
encoding:
codec: json
Loki
Пример имитации API приема событий системы агрегации логов Loki:
http-routes:
listen-port: 3100
routes:
"POST /loki/api/v1/push":
response-code: 204
"POST /otlp/v1/logs":
response-code: 204
Loki при приеме событий не возвращает тела ответа, поэтому используется код 204 (No Content).
Конфигурация Vector для отправки событий:
sources:
generator:
type: demo_logs
format: json
sinks:
loki:
type: loki
inputs: [generator]
endpoint: http://localhost:3100
compression: none
labels:
source: vector
encoding:
codec: json
Для извлечения полей из событий Loki, поступающих на /loki/api/v1/push, можно использовать следующий конвейер processors:
processors:
- module: split
type: json_array
path: streams
- module: json
patterns:
- expr: stream.source
to: ECS.Event.Module
- module: split
type: json_array
path: values
- module: json
patterns:
- expr: 1
to: ECS.Event.Original