Caffeine Query Language

CQL is a very simple arithmetic language that is used to express SLIs. We expect it to grow over time, but for it to never be Turing complete.

The following operators are supported:

Grammar:

CQL_QUERY  ::= EXP
EXP        ::= ADD
ADD        ::= MUL (('+' | '-') MUL)*
MUL        ::= PRIMARY (('*' | '/') PRIMARY)*
PRIMARY    ::= WORD | '(' EXP ')'
WORD       ::= [A-Za-z_]+

Query Primitives

While I’ve already placed a fairly rigid constraint on CQL by saying it’s never going to be Turing complete, I’ll further constrain by saying it must map to a query primitive. A query primitive is:

A query form or structure that comes shipped with caffeine; a sort of standard library for queries. 

For example, the first primitive we will support is good and valid over total. We map to this by ensuring our query reduces to a numerator over a denominator.


Phase to Phase

(1): Parsing

In this step, we parse the CQL query into its parse tree.

Input:

(A + B) / C

Output:

let query  =   CQL_QUERY
                        └─ EXP
                           └─ ADD
                              └─ MUL
                                 ├─ PRIMARY
                                 │  └─ "(" EXP ")"
                                 │     └─ ADD
                                 │        ├─ MUL
                                 │        │  └─ PRIMARY
                                 │        │     └─ WORD("A")
                                 │        ├─ "+"
                                 │        └─ MUL
                                 │           └─ PRIMARY
                                 │              └─ WORD("B")
                                 ├─ "/"
                                 └─ PRIMARY
                                    └─ WORD("C")

UnresolvedQueryTemplateType(
  ...
  query: query
  ...
)

(2): Linking

Linking in the caffeine compiler is mostly about resolving references between structures from different files. Since the query is all in one file, it isn’t modified at all in this step (it’s just moved from one object to another).

Input:

UnresolvedQueryTemplateType(
  ...
  query: query
  ...
)

Output:

QueryTemplateType(
  ...
  query:  query
  ...
)

(3): Semantic Analysis

Here we perform a series of checks including, but not limited to:

We do not modify the parse tree. We simply traverse to ensure its validity.

Input:

QueryTemplateType(
  ...
  query: query
  ...
)

Output:

QueryTemplateType(
  ...
  query: query
  ...
)

(4): Resolution

In this step, we attempt to reduce our CQL query to a query primitive. Then we resolve the query template variables. The final result is fairly close to what the backend generator will use

Input:

QueryTemplateType(
  ...
  query: query
  ...
)

Output:

QueryTemplateType(
  ...
  query: QUERY_PRIMITIVE(
    numerator = "(SOME_QUERY_A + SOME_QUERY_B)"
    denominator = "SOME_QUERY_C""
  ...
)

(5): Generation

Given a query primitive, we generator reliability artifact(s).

Input:

QueryTemplateType(
  ...
  query: QUERY_PRIMITIVE(
    numerator = "(SOME_QUERY_A + SOME_QUERY_B)"
    denominator = "SOME_QUERY_C""
  ...

Output:

...
query {
  numerator: "(SOME_QUERY_A + SOME_QUERY_B)"
  denominator: "SOME_QUERY_C"
}

A Full Example

Specification

basic_types.yaml

basic_types:
  - attribute_name: some_value
    attribute_type: String

query_template_types.yaml

query_template_types:
  - name: "valid_over_total"
    query: "numerator / denominator"
    specification_of_query_templates: ["numerator", "denominator"]

sli_types.yaml

types:
  - name: success_rate
    query_template_type: valid_over_total
    typed_instatiation_of_query_templates:
      numerator: "sum:hits_and_errors{status:success env:$$some_value$$}"
      denominator: "sum:hits_and_errors{env:$$some_value$$}" 
    specification_of_query_templatized_variables:
      - some_value

services.yaml

services:
  - name: reliable_service
    sli_types:
      - success_rate

Instantiation

company/platform/reliable_service.yaml

slos:
  - sli_type: "success_rate"
    typed_instatiation_of_query_templatized_variables:
      "some_value": "foobar"
    threshold: 99.5
    window_in_days: 30

Search Document