Как работает Watcher
Вы добавляете смотрителей для автоматического выполнения действия при выполнении определённых условий. Условия обычно основаны на данных, которые вы загрузили в смотрителя, также известные как Нагрузка смотрителя. Эту нагрузку можно загрузить из разных источников — из Elasticsearch, внешней HTTP-службы или даже их комбинации.
Например, вы можете настроить смотрителя для отправки электронного письма системному администратору, когда поиск в данных журналов показывает слишком много ошибок 503 за последние 5 минут.
В этой теме описаны элементы смотрителя и как они работают.
Определение смотрителя
Смотритель состоит из триггера, ввода, условия и действий. Действия определяют, что необходимо сделать, когда условие выполнено. Кроме того, вы можете определить условия и преобразования для обработки и подготовки нагрузки смотрителя перед выполнением действий.
- Триггер
- Определяет, когда проверяется смотритель. Смотритель должен иметь триггер.
- Ввод
- Загружает данные в нагрузку смотрителя. Если ввод не указан, загружается пустая нагрузка.
- Условие
- Управляет выполнением действий смотрителя. Если условие не указано, оно по умолчанию устанавливается на
always. - Преобразование
- Обрабатывает нагрузку смотрителя, чтобы подготовить её к действиям смотрителя. Вы можете определить преобразования на уровне смотрителя или определить преобразования, специфичные для действий. Необязательно.
- Действия
- Указывают, что происходит, когда выполняется условие смотрителя.
Например, следующий фрагмент показывает запрос создания или обновления смотрителя, который определяет смотрителя, ищущего события ошибок журнала:
resp = client.watcher.put_watch(
id="log_errors",
metadata={
"color": "red"
},
trigger={
"schedule": {
"interval": "5m"
}
},
input={
"search": {
"request": {
"indices": "log-events",
"body": {
"size": 0,
"query": {
"match": {
"status": "error"
}
}
}
}
}
},
condition={
"compare": {
"ctx.payload.hits.total": {
"gt": 5
}
}
},
transform={
"search": {
"request": {
"indices": "log-events",
"body": {
"query": {
"match": {
"status": "error"
}
}
}
}
}
},
actions={
"my_webhook": {
"webhook": {
"method": "POST",
"host": "mylisteninghost",
"port": 9200,
"path": "/{{watch_id}}",
"body": "Encountered {{ctx.payload.hits.total}} errors"
}
},
"email_administrator": {
"email": {
"to": "sys.admino@host.domain",
"subject": "Encountered {{ctx.payload.hits.total}} errors",
"body": "Too many error in the system, see attached data",
"attachments": {
"attached_data": {
"data": {
"format": "json"
}
}
},
"priority": "high"
}
}
},
)
print(resp) const response = await client.watcher.putWatch({
id: "log_errors",
metadata: {
color: "red",
},
trigger: {
schedule: {
interval: "5m",
},
},
input: {
search: {
request: {
indices: "log-events",
body: {
size: 0,
query: {
match: {
status: "error",
},
},
},
},
},
},
condition: {
compare: {
"ctx.payload.hits.total": {
gt: 5,
},
},
},
transform: {
search: {
request: {
indices: "log-events",
body: {
query: {
match: {
status: "error",
},
},
},
},
},
},
actions: {
my_webhook: {
webhook: {
method: "POST",
host: "mylisteninghost",
port: 9200,
path: "/{{watch_id}}",
body: "Encountered {{ctx.payload.hits.total}} errors",
},
},
email_administrator: {
email: {
to: "sys.admino@host.domain",
subject: "Encountered {{ctx.payload.hits.total}} errors",
body: "Too many error in the system, see attached data",
attachments: {
attached_data: {
data: {
format: "json",
},
},
},
priority: "high",
},
},
},
});
console.log(response); PUT _watcher/watch/log_errors
{
"metadata" : {
"color" : "red"
},
"trigger" : {
"schedule" : {
"interval" : "5m"
}
},
"input" : {
"search" : {
"request" : {
"indices" : "log-events",
"body" : {
"size" : 0,
"query" : { "match" : { "status" : "error" } }
}
}
}
},
"condition" : {
"compare" : { "ctx.payload.hits.total" : { "gt" : 5 }}
},
"transform" : {
"search" : {
"request" : {
"indices" : "log-events",
"body" : {
"query" : { "match" : { "status" : "error" } }
}
}
}
},
"actions" : {
"my_webhook" : {
"webhook" : {
"method" : "POST",
"host" : "mylisteninghost",
"port" : 9200,
"path" : "/{{watch_id}}",
"body" : "Encountered {{ctx.payload.hits.total}} errors"
}
},
"email_administrator" : {
"email" : {
"to" : "sys.admino@host.domain",
"subject" : "Encountered {{ctx.payload.hits.total}} errors",
"body" : "Too many error in the system, see attached data",
"attachments" : {
"attached_data" : {
"data" : {
"format" : "json"
}
}
},
"priority" : "high"
}
}
}
} | Метаданные — вы можете прикрепить необязательные статические метаданные к смотрителю. | |
| Триггер — этот триггер расписания выполняет смотритель каждые 5 минут. | |
| Ввод — этот ввод ищет ошибки в индексе | |
| Условие — это условие проверяет, есть ли более 5 событий ошибок (хитов в ответе поиска). Если есть, выполнение продолжается для всех | |
| Преобразование — если условие смотрителя выполняется, это преобразование загружает все ошибки в нагрузку смотрителя, выполняя поиск ошибок с помощью типа поиска по умолчанию, | |
| Действия — у этого смотрителя два действия. Действие |
Выполнение смотрителя
При добавлении смотрителя Watcher немедленно регистрирует его триггер в соответствующем движке триггеров. Смотрители с триггером schedule регистрируются в движке триггеров scheduler.
Планировщик отслеживает время и запускает смотрителей в соответствии с их расписаниями. На каждом узле, содержащем один из фрагментов .watches, выполняется планировщик, привязанный к жизненному циклу смотрителя. Несмотря на то, что учитываются все первичные и реплицированные фрагменты, при запуске смотрителя Watcher также гарантирует, что каждый смотритель запускается только на одном из этих фрагментов. Чем больше вы добавляете реплицированных фрагментов, тем более распределённо могут выполняться смотрители. Если вы добавляете или удаляете реплики, все смотрители должны быть перезагружены. Если фрагмент перемещается, первичный и все реплики этого конкретного фрагмента будут перезагружены.
Поскольку смотрители выполняются на узле, где находятся фрагменты смотрителя, вы можете создать выделенные узлы смотрителя, используя фильтрацию распределения фрагментов. Для этого настройте узлы со специальным свойством node.attr.role: watcher.
Поскольку индекс .watches является системным индексом, вы не можете использовать обычный конечный пункт .watcher/_settings для изменения распределения маршрутизации. Вместо этого вы можете использовать следующий специальный конечный пункт для настройки распределения фрагментов .watches на узлах с атрибутом роли watcher:
resp = client.perform_request(
"PUT",
"/_watcher/settings",
headers={"Content-Type": "application/json"},
body={
"index.routing.allocation.include.role": "watcher"
},
)
print(resp) const response = await client.transport.request({
method: "PUT",
path: "/_watcher/settings",
body: {
"index.routing.allocation.include.role": "watcher",
},
});
console.log(response); PUT _watcher/settings
{
"index.routing.allocation.include.role": "watcher"
} При остановке службы Watcher планировщик останавливается вместе с ней. Движки триггеров используют отдельный пул потоков от того, который используется для выполнения смотрителей.
Когда смотритель запускается, Watcher помещает его в очередь для выполнения. Создаётся и добавляется документ watch_record в историю смотрителя, а состояние смотрителя устанавливается в awaits_execution.
При запуске выполнения Watcher создаёт контекст выполнения смотрителя для смотрителя. Контекст выполнения предоставляет скрипты и шаблоны с доступом к метаданным смотрителя, нагрузке, идентификатору смотрителя, времени выполнения и информации о триггере. Дополнительную информацию см. в разделе Контекст выполнения смотрителя.
В процессе выполнения Watcher:
- Загружает входные данные как нагрузку в контексте выполнения смотрителя. Это делает данные доступными для всех последующих этапов процесса выполнения. Этот шаг контролируется вводом смотрителя.
- Оценивает условие смотрителя, чтобы определить, следует ли продолжить обработку смотрителя. Если условие выполнено (оценивается как
true), обработка переходит к следующему шагу. Если условие не выполнено (оценивается какfalse), выполнение смотрителя останавливается. - Применяет преобразования к нагрузке смотрителя (при необходимости).
- Выполняет действия смотрителя, при условии, что условие выполнено, и смотритель не ограничен.
По завершении выполнения смотрителя результат выполнения записывается как Запись смотрителя в истории смотрителя. Запись смотрителя включает время и продолжительность выполнения, было ли выполнено условие смотрителя и статус каждого выполненного действия.
На следующей схеме показан процесс выполнения смотрителя:
Подтверждение и ограничение смотрителя
Watcher поддерживает ограничение, основанное на времени и на подтверждении. Это позволяет предотвратить многократное выполнение действий для одного события.
По умолчанию Watcher использует временное ограничение с периодом ограничения 5 секунд. Это означает, что если смотритель выполняется каждую секунду, его действия выполняются не более одного раза каждые 5 секунд, даже если условие всегда выполняется. Вы можете настроить период ограничения для каждого действия или на уровне смотрителя.
Ограничение, основанное на подтверждении, позволяет указать Watcher, чтобы он не отправлял уведомления о смотрителе, пока его условие выполняется. После того, как условие оценивается как false, подтверждение удаляется, и Watcher возобновляет выполнение действий смотрителя в обычном режиме.
Дополнительную информацию см. в разделе Подтверждение и ограничение.
Активное состояние смотрителя
По умолчанию, при добавлении смотрителя он немедленно переходит в состояние активный, регистрируется в соответствующем движке триггеров и выполняется в соответствии с настроенным триггером.
Вы также можете установить смотритель в состояние неактивный. Неактивные смотрители не регистрируются в движке триггеров и никогда не могут быть запущены.
Чтобы установить смотритель в неактивное состояние при его создании, установите параметр active в значение неактивный. Чтобы деактивировать существующий смотритель, используйте API деактивации смотрителя. Чтобы активировать неактивный смотритель, используйте API активации смотрителя.
Вы можете использовать API выполнения смотрителя, чтобы принудительно запустить смотритель, даже если он неактивный.
Деактивация смотрителей полезна в различных ситуациях. Например, если у вас есть смотритель, который отслеживает внешнюю систему, и вам нужно остановить эту систему на время технического обслуживания, вы можете деактивировать смотритель, чтобы предотвратить ложные сообщения о проблемах с доступностью во время окна технического обслуживания.
Деактивация смотрителя также позволяет сохранить его для будущего использования, не удаляя его из системы.
Скрипты и шаблоны
При определении смотрителя можно использовать скрипты и шаблоны. Скрипты и шаблоны могут ссылаться на элементы в контексте выполнения смотрителя, включая нагрузку смотрителя. Контекст выполнения определяет переменные, которые можно использовать в скрипте, и заполнитель параметров в шаблоне.
Watcher использует инфраструктуру скриптов Elasticsearch, которая поддерживает встроенные и сохранённые. Скрипты и шаблоны компилируются и кэшируются Elasticsearch для оптимизации многократного выполнения. Также поддерживается автоматическая загрузка. Дополнительную информацию см. в разделах Скриптинг и Как писать скрипты.
Контекст выполнения наблюдения
Следующий фрагмент демонстрирует основную структуру контекста выполнения наблюдения:
{
"ctx" : {
"metadata" : { ... },
"payload" : { ... },
"watch_id" : "<id>",
"execution_time" : "20150220T00:00:10Z",
"trigger" : {
"triggered_time" : "20150220T00:00:10Z",
"scheduled_time" : "20150220T00:00:00Z"
},
"vars" : { ... }
} | Любые статические метаданные, указанные в определении наблюдения. | |
| Текущая полезная нагрузка наблюдения. | |
| Идентификатор выполняемого наблюдения. | |
| Отметка времени, показывающая, когда началось выполнение наблюдения. | |
| Информация о событии-триггере. Для триггера | |
| Динамические переменные, которые могут быть установлены и обработаны различными конструкциями во время выполнения. Эти переменные ограничены одним выполнением (т.е. они не сохраняются и не могут использоваться между различными выполнениями одного и того же наблюдения). |
Использование скриптов
Вы можете использовать скрипты для определения условий и преобразований. По умолчанию язык скриптов – Painless.
Начиная с версии 5.0, Elasticsearch поставляется с новым языком сценариев Painless. Painless был разработан специально для использования в Elasticsearch. Помимо обширного набора функций, его ключевой особенностью является надёжная изоляция и безопасность для использования в любой части системы (в том числе в Watcher) без необходимости включения динамических скриптов.
Скрипты могут ссылаться на любые значения в контексте выполнения наблюдения или значения, явно переданные через параметры скрипта.
Например, если метаданные наблюдения содержат поле color (например, "metadata" : {"color": "red"}), вы можете получить доступ к его значению через переменную ctx.metadata.color. Если вы передадите параметр color в качестве части определения условия или преобразования (например, "params" : {"color": "red"}), вы можете получить доступ к его значению через переменную color.
Использование шаблонов
Шаблоны используются для определения динамического содержимого наблюдения. Во время выполнения шаблоны извлекают данные из контекста выполнения наблюдения. Например, вы можете использовать шаблон для заполнения поля subject для действия email данными, хранящимися в полезной нагрузке наблюдения. Шаблоны также могут получать доступ к значениям, явно переданным через параметры шаблона.
Шаблоны задаются с помощью языка разметки Mustache.
Например, следующий фрагмент демонстрирует, как шаблоны позволяют создавать динамические темы в отправляемых электронных письмах:
{
"actions" : {
"email_notification" : {
"email" : {
"subject" : "{{ctx.metadata.color}} alert"
}
}
}
} Встроенные шаблоны и скрипты
Для определения встроенного шаблона или скрипта достаточно указать его непосредственно в значении поля. Например, следующий фрагмент настраивает тему действия email, используя встроенный шаблон, который ссылается на значение color в метаданных контекста.
"actions" : {
"email_notification" : {
"email" : {
"subject" : "{{ctx.metadata.color}} alert"
}
}
}
} Для скрипта просто укажите встроенный скрипт в качестве значения поля script. Например:
"condition" : {
"script" : "return true"
} Также можно явно указать тип встроенного объекта, используя формальное определение объекта как значение поля. Например:
"actions" : {
"email_notification" : {
"email" : {
"subject" : {
"source" : "{{ctx.metadata.color}} alert"
}
}
}
} Формальное определение объекта для скрипта будет:
"condition" : {
"script" : {
"source": "return true"
}
} Хранящиеся шаблоны и скрипты
Если вы сохраняете ваши шаблоны и скрипты, вы можете ссылаться на них по идентификатору.
Чтобы сослаться на хранящийся скрипт или шаблон, используйте формальное определение объекта и укажите его идентификатор в поле id. Например, следующий фрагмент ссылается на шаблон email_notification_subject:
{
...
"actions" : {
"email_notification" : {
"email" : {
"subject" : {
"id" : "email_notification_subject",
"params" : {
"color" : "red"
}
}
}
}
}
}
© 2023-2025 Elasticsearch
As of September 2024, Elasticsearch is available under a choice of three licenses: the Server Side Public License (SSPL), the Elastic License, or the AGPLv3 (OSI approved).
Elasticsearch and the Elasticsearch logo are trademarks of Elasticsearch B.V., registered in the U.S. and in other countries.
https://www.elastic.co/guide/en/elasticsearch/reference/8.17/how-watcher-works.html