Using CEL

FireHydrant allows you to query data and relationships in your Signals using Common Expression Language (CEL).

A basic query in FireHydrant includes an entity with properties available vid dot notation entity.property and logical operators with a comparison value. The only available entity today is a signal which represents the incoming events from webhooks. A basic query might look like the following:

// entity.property == "value"
signal.summary == "CPU Utilization Spiking" 

Each Signal has properties that can be evaluated and a specific value you wish to express. CEL queries can be performed on the Signals list page and when creating Signals Rules for a team.

Basic CEL Usage

Logical Operators

OperatorMeaningExample
==Equals2 == 2 will return true
!=Does not equal3 != 2 will return true
>Greater than3 > 2 will return true
<Less Than2 < 3 will return true
&&And2 == 2 && 2 != 3 will return true
`|`Or`2 == 3 |2 == 2` will return true

CEL Functions

FunctionExample
contains()signal.summary.contains("CPU")
matches() signal.summary.matches("CPU") or matches(signal.summary, "CPU")
size()Check array length: size(signal.images) > 1
Check string length: size(signal.summary) > 3
startsWith()signal.summary.startsWith("CPU")
endsWith()signal.summary.endsWith("Spiking")

CEL Macros

MacroExampleDefinition
has()has(signal.summary)Tests whether a field is available
all() signal.all(x, has(x))Tests whether a predicate function holds for all properties of a signal
exists() signal.exists(x, has(x))Tests whether a predicate function holds for any properties of a signal
map()signal.links.map(link, link.url != "")Maps a list and provides each value to be mapped and returned in a new list
filter()signal.images.map(image, image.src != "")Filters a list and provides matching values to be returned in a new list

📘

Note:

📚 You can check out the full documentation of CEL to explore even more about leveraging CEL inside of FireHydrant for querying signals.

Example Signal and CEL Query

{
  "summary": "CPU Utilization Spiking",
  "body": "The production server is experiencing greater than 99% utilizations of compute.",
  "level": 0,
  "status": 0,
  "images": [
    {
      "src": "https://site.com/images/123.png",
      "alt": "A simple, sample image"
    }
  ],
  "links": [
    {
      "href": "https://site.com/monitors/123",
      "text": "Monitoring Source"
    }
  ],
  "annotations": {
    "policy": "escalatable"
  },
  "tags": ["service:core-application", "env:prod"],
  "received_at": "2023-11-09T18:22:16.000+00:00"
}

Below is an example CEL expression that would return true on this payload:

signal.summary.contains("CPU") && signal.level == 2 && signal.annotations.keyEquals('policy', "escalatable")

In this expression:

  • signal refers to the instance of the Signal.
  • signal.summary checks if the summary field in the Signal message contains "CPU".
  • signal.level checks if the level field in the Signal message equals the enum for “ERROR”. The standard system levels are available here: INFO: 0 , WARN: 1, ERROR: 2, & FATAL: 3
  • signal.annotations.keyEquals('policy', 'escalatable') accesses the annotations map and checks if there is a key "policy" with the value "escalatable".

☝️ Note about Signals Levels

Signals can take on a standard “Level” based on data from a webhook. You can run CEL queries based on the ENUM value for each, as shown below.

INFO = 0;
WARN = 1;
ERROR = 2;
FATAL = 3;