Monitors

Table of contents


Key terms

TermDefinition
MonitorA job that runs on a defined schedule and queries OpenSearch. The results of these queries are then used as input for one or more triggers.
TriggerConditions that, if met, generate alerts.
AlertAn event associated with a trigger. When an alert is created, the trigger performs actions, which can include sending a notification.
ActionThe information that you want the monitor to send out after being triggered. Actions have a destination, a message subject, and a message body.
DestinationA reusable location for an action, such as Amazon Chime, Slack, or a webhook URL.

Create destinations

  1. Choose Alerting, Destinations, Add destination.
  2. Specify a name for the destination so that you can identify it later.
  3. For Type, choose Slack, Amazon Chime, custom webhook, or email.

For Email type, refer to Email as a destination section below. For all other types, specify the webhook URL. For more information about webhooks, see the documentation for Slack and Chime.

For custom webhooks, you must specify more information: parameters and headers. For example, if your endpoint requires basic authentication, you might need to add a header with a key of Authorization and a value of Basic <Base64-encoded-credential-string>. You might also need to change Content-Type to whatever your webhook requires. Popular values are application/json, application/xml, and text/plain.

This information is stored in plain text in the OpenSearch cluster. We will improve this design in the future, but for now, the encoded credentials (which are neither encrypted nor hashed) might be visible to other OpenSearch users.

Email as a destination

To send or receive an alert notification as an email, choose Email as the destination type. Next, add at least one sender and recipient. We recommend adding email groups if you want to notify more than a few people of an alert. You can configure senders and recipients using Manage senders and Manage email groups.

Manage senders

Senders are email accounts from which the alerting plugin sends notifications.

To configure a sender email, do the following:

  1. After you choose Email as the destination type, choose Manage senders.
  2. Choose Add sender, New sender and enter a unique name.
  3. Enter the email address, SMTP host (e.g. smtp.gmail.com for a Gmail account), and the port.
  4. Choose an encryption method, or use the default value of None. However, most email providers require SSL or TLS, which requires a username and password in OpenSearch keystore. Refer to Authenticate sender account to learn more.
  5. Choose Save to save the configuration and create the sender. You can create a sender even before you add your credentials to the OpenSearch keystore. However, you must authenticate each sender account before you use the destination to send your alert.

You can reuse senders across many different destinations, but each destination only supports one sender.

Manage email groups or recipients

Use email groups to create and manage reusable lists of email addresses. For example, one alert might email the DevOps team, whereas another might email the executive team and the engineering team.

You can enter individual email addresses or an email group in the Recipients field.

  1. After you choose Email as the destination type, choose Manage email groups. Then choose Add email group, New email group.
  2. Enter a unique name.
  3. For recipient emails, enter any number of email addresses.
  4. Choose Save.

Authenticate sender account

If your email provider requires SSL or TLS, you must authenticate each sender account before you can send an email. Enter these credentials in the OpenSearch keystore using the CLI. Run the following commands (in your OpenSearch directory) to enter your username and password. The <sender_name> is the name you entered for Sender earlier.

  1. ./bin/opensearch-keystore add plugins.alerting.destination.email.<sender_name>.username
  2. ./bin/opensearch-keystore add plugins.alerting.destination.email.<sender_name>.password

Note: Keystore settings are node-specific. You must run these commands on each node.

To change or update your credentials (after you’ve added them to the keystore on every node), call the reload API to automatically update those credentials without restarting OpenSearch:

  1. POST _nodes/reload_secure_settings
  2. {
  3. "secure_settings_password": "1234"
  4. }

Create monitors

  1. Choose Alerting, Monitors, Create monitor.
  2. Specify a name for the monitor.

The anomaly detection option is for pairing with the anomaly detection plugin. See Anomaly Detection. For anomaly detector, choose an appropriate schedule for the monitor based on the detector interval. Otherwise, the alerting monitor might miss reading the results.

For example, assume you set the monitor interval and the detector interval as 5 minutes, and you start the detector at 12:00. If an anomaly is detected at 12:05, it might be available at 12:06 because of the delay between writing the anomaly and it being available for queries. The monitor reads the anomaly results between 12:00 and 12:05, so it does not get the anomaly results available at 12:06.

To avoid this issue, make sure the alerting monitor is at least twice the detector interval. When you create a monitor using OpenSearch Dashboards, the anomaly detector plugin generates a default monitor schedule that’s twice the detector interval.

Whenever you update a detector’s interval, make sure to update the associated monitor interval as well, as the anomaly detection plugin does not do this automatically.

  1. Choose one or more indices. You can also use * as a wildcard to specify an index pattern.

    If you use the security plugin, you can only choose indices that you have permission to access. For details, see Alerting security.

  2. Define the monitor in one of three ways: visually, using a query, or using an anomaly detector.

    • Visual definition works well for monitors that you can define as “some value is above or below some threshold for some amount of time.”

    • Query definition gives you flexibility in terms of what you query for (using the OpenSearch query DSL) and how you evaluate the results of that query (Painless scripting).

      This example averages the cpu_usage field:

      1. {
      2. "size": 0,
      3. "query": {
      4. "match_all": {}
      5. },
      6. "aggs": {
      7. "avg_cpu": {
      8. "avg": {
      9. "field": "cpu_usage"
      10. }
      11. }
      12. }
      13. }

      You can even filter query results using {{period_start}} and {{period_end}}:

      1. {
      2. "size": 0,
      3. "query": {
      4. "bool": {
      5. "filter": [{
      6. "range": {
      7. "timestamp": {
      8. "from": "{{period_end}}||-1h",
      9. "to": "{{period_end}}",
      10. "include_lower": true,
      11. "include_upper": true,
      12. "format": "epoch_millis",
      13. "boost": 1
      14. }
      15. }
      16. }],
      17. "adjust_pure_negative": true,
      18. "boost": 1
      19. }
      20. },
      21. "aggregations": {}
      22. }

      “Start” and “end” refer to the interval at which the monitor runs. See Available variables.

  3. To define a monitor visually, choose Define using visual graph. Then choose an aggregation (for example, count() or average()), a set of documents, and a timeframe. Visual definition works well for most monitors.

    To use a query, choose Define using extraction query, add your query (using the OpenSearch query DSL), and test it using the Run button.

    The monitor makes this query to OpenSearch as often as the schedule dictates; check the Query Performance section and make sure you’re comfortable with the performance implications.

    To use an anomaly detector, choose Define using Anomaly detector and select your Detector.

  4. Choose a frequency and timezone for your monitor. Note that you can only pick a timezone if you choose Daily, Weekly, Monthly, or custom cron expression for frequency.

  5. Choose Create.

Create triggers

The next step in creating a monitor is to create a trigger. These steps differ depending on whether you chose Define using visual graph or Define using extraction query or Define using Anomaly detector when you created the monitor.

Either way, you begin by specifying a name and severity level for the trigger. Severity levels help you manage alerts. A trigger with a high severity level (e.g. 1) might page a specific individual, whereas a trigger with a low severity level might message a chat room.

Visual graph

For Trigger condition, specify a threshold for the aggregation and timeframe you chose earlier, such as “is below 1,000” or “is exactly 10.”

The line moves up and down as you increase and decrease the threshold. Once this line is crossed, the trigger evaluates to true.

Extraction query

For Trigger condition, specify a Painless script that returns true or false. Painless is the default OpenSearch scripting language and has a syntax similar to Groovy.

Trigger condition scripts revolve around the ctx.results[0] variable, which corresponds to the extraction query response. For example, your script might reference ctx.results[0].hits.total.value or ctx.results[0].hits.hits[i]._source.error_code.

A return value of true means the trigger condition has been met, and the trigger should execute its actions. Test your script using the Run button.

The Info link next to Trigger condition contains a useful summary of the variables and results available to your query.

Anomaly detector

For Trigger type, choose Anomaly detector grade and confidence.

Specify the Anomaly grade condition for the aggregation and timeframe you chose earlier, “IS ABOVE 0.7” or “IS EXACTLY 0.5.” The anomaly grade is a number between 0 and 1 that indicates the level of severity of how anomalous a data point is.

Specify the Anomaly confidence condition for the aggregation and timeframe you chose earlier, “IS ABOVE 0.7” or “IS EXACTLY 0.5.” The anomaly confidence is an estimate of the probability that the reported anomaly grade matches the expected anomaly grade.

The line moves up and down as you increase and decrease the threshold. Once this line is crossed, the trigger evaluates to true.

Sample scripts

  1. // Evaluates to true if the query returned any documents
  2. ctx.results[0].hits.total.value > 0
  1. // Returns true if the avg_cpu aggregation exceeds 90
  2. if (ctx.results[0].aggregations.avg_cpu.value > 90) {
  3. return true;
  4. }
  1. // Performs some crude custom scoring and returns true if that score exceeds a certain value
  2. int score = 0;
  3. for (int i = 0; i < ctx.results[0].hits.hits.length; i++) {
  4. // Weighs 500 errors 10 times as heavily as 503 errors
  5. if (ctx.results[0].hits.hits[i]._source.http_status_code == "500") {
  6. score += 10;
  7. } else if (ctx.results[0].hits.hits[i]._source.http_status_code == "503") {
  8. score += 1;
  9. }
  10. }
  11. if (score > 99) {
  12. return true;
  13. } else {
  14. return false;
  15. }

Below are some variables you can include in your message using Mustache templates to see more information about your monitors.

Available variables

Monitor variables

VariableData TypeDescription
ctx.monitorJSONIncludes ctx.monitor.name, ctx.monitor.type, ctx.monitor.enabled, ctx.monitor.enabled_time, ctx.monitor.schedule, ctx.monitor.inputs, triggers and ctx.monitor.last_update_time.
ctx.monitor.userJSONIncludes information about the user who created the monitor. Includes ctx.monitor.user.backend_roles and ctx.monitor.user.roles, which are arrays that contain the backend roles and roles assigned to the user. See alerting security for more information.
ctx.monitor.enabledBooleanWhether the monitor is enabled.
ctx.monitor.enabled_timeMillisecondsUnix epoch time of when the monitor was last enabled.
ctx.monitor.scheduleJSONContains a schedule of how often or when the monitor should run.
ctx.monitor.schedule.period.intervalIntegerThe interval at which the monitor runs.
ctx.monitor.schedule.period.unitStringThe interval’s unit of time.
ctx.monitor.inputsArrayAn array that contains the indices and definition used to create the monitor.
ctx.monitor.inputs.search.indicesArrayAn array that contains the indices the monitor observes.
ctx.monitor.inputs.search.queryN/AThe definition used to define the monitor.

Trigger variables

VariableData TypeDescription
ctx.trigger.idStringThe trigger’s ID.
ctx.trigger.nameStringThe trigger’s name.
ctx.trigger.severityStringThe trigger’s severity.
ctx.trigger.conditionJSONContains the Painless script used when creating the monitor.
ctx.trigger.condition.script.sourceStringThe language used to define the script. Must be painless.
ctx.trigger.condition.script.langStringThe script used to define the trigger.
ctx.trigger.actionsArrayAn array with one element that contains information about the action the monitor needs to trigger.

Action variables

VariableData TypeDescription
ctx.trigger.actions.idStringThe action’s ID.
ctx.trigger.actions.nameStringThe action’s name.
ctx.trigger.actions.destination_idStringThe alert destination’s ID.
ctx.trigger.actions.message_template.sourceStringThe message to send in the alert.
ctx.trigger.actions.message_template.langStringThe scripting language used to define the message. Must be Mustache.
ctx.trigger.actions.throttle_enabledBooleanWhether throttling is enabled for this trigger. See adding actions for more information about throttling.
ctx.trigger.actions.subject_template.sourceStringThe message’s subject in the alert.
ctx.trigger.actions.subject_template.langStringThe scripting language used to define the subject. Must be mustache.

Other variables

VariableData TypeDescription
ctx.resultsArrayAn array with one element (i.e. ctx.results[0]). Contains the query results. This variable is empty if the trigger was unable to retrieve results. See ctx.error.
ctx.last_update_timeMillisecondsUnix epoch time of when the monitor was last updated.
ctx.periodStartStringUnix timestamp for the beginning of the period during which the alert triggered. For example, if a monitor runs every ten minutes, a period might begin at 10:40 and end at 10:50.
ctx.periodEndStringThe end of the period during which the alert triggered.
ctx.errorStringThe error message if the trigger was unable to retrieve results or unable to evaluate the trigger, typically due to a compile error or null pointer exception. Null otherwise.
ctx.alertJSONThe current, active alert (if it exists). Includes ctx.alert.id, ctx.alert.version, and ctx.alert.isAcknowledged. Null if no alert is active.

Add actions

The final step in creating a monitor is to add one or more actions. Actions send notifications when trigger conditions are met and support Slack, Amazon Chime, and webhooks.

If you don’t want to receive notifications for alerts, you don’t have to add actions to your triggers. Instead, you can periodically check OpenSearch Dashboards.

  1. Specify a name for the action.
  2. Choose a destination.
  3. Add a subject and body for the message.

    You can add variables to your messages using Mustache templates. You have access to ctx.action.name, the name of the current action, as well as all trigger variables.

    If your destination is a custom webhook that expects a particular data format, you might need to include JSON (or even XML) directly in the message body:

    1. { "text": "Monitor {{ctx.monitor.name}} just entered alert status. Please investigate the issue. - Trigger: {{ctx.trigger.name}} - Severity: {{ctx.trigger.severity}} - Period start: {{ctx.periodStart}} - Period end: {{ctx.periodEnd}}" }

    In this case, the message content must conform to the Content-Type header in the custom webhook.

  4. (Optional) Use action throttling to limit the number of notifications you receive within a given span of time.

    For example, if a monitor checks a trigger condition every minute, you could receive one notification per minute. If you set action throttling to 60 minutes, you receive no more than one notification per hour, even if the trigger condition is met dozens of times in that hour.

  5. Choose Create.

After an action sends a message, the content of that message has left the purview of the security plugin. Securing access to the message (e.g. access to the Slack channel) is your responsibility.

Sample message

  1. Monitor {{ctx.monitor.name}} just entered an alert state. Please investigate the issue.
  2. - Trigger: {{ctx.trigger.name}}
  3. - Severity: {{ctx.trigger.severity}}
  4. - Period start: {{ctx.periodStart}}
  5. - Period end: {{ctx.periodEnd}}

If you want to use the ctx.results variable in a message, use {{ctx.results.0}} rather than {{ctx.results[0]}}. This difference is due to how Mustache handles bracket notation.


Work with alerts

Alerts persist until you resolve the root cause and have the following states:

StateDescription
ActiveThe alert is ongoing and unacknowledged. Alerts remain in this state until you acknowledge them, delete the trigger associated with the alert, or delete the monitor entirely.
AcknowledgedSomeone has acknowledged the alert, but not fixed the root cause.
CompletedThe alert is no longer ongoing. Alerts enter this state after the corresponding trigger evaluates to false.
ErrorAn error occurred while executing the trigger—usually the result of a a bad trigger or destination.
DeletedSomeone deleted the monitor or trigger associated with this alert while the alert was ongoing.