tsqtsq
aims to make hard-coded PromQL queries easier to read and maintain. Wide-ranging changes and common "query snippets" have varying approaches and often impact query readability. By introducing typed, templated queries, changing common expressions and debugging becomes much easier.
Consider the following use cases:
- Implement de-duplication of all existing queries
- Establish patterns for writing new queries
- Create reusable snippets that accept arguments for metric labels
The library in this directory is an effort to reduce the potential toil involved in refactoring tasks like those mentioned above.
- Maintain "backwards compatibilty" by returning PromQL queries as a simple
string
- just like the string literals and template strings we used before. - Re-usability of "query snippets" is a priority.
- Avoid verbose library usage and syntax wherever possible, prefer ease of use over type purity.
- Aim to make metrics and labels "discoverable" through IntelliSense, to aid query writing in the editor.
- Embed "sensible defaults" and tribal knowledge using query abstraction - e.g. using
container!=""
as a default matcher for requests/limits but only if thecontainer
label is not passed a value (this avoids matching against the confusing pod-level cgroup metrics). - Prefer named object/property parameters over ordered/implicit arguments - because who can remember whether the labels or the query comes first.
import { promql, Expression } from 'tsqtsq';
sum
promql.sum({ expr: 'test_metric{foo="bar"}', by: ['foo', 'bar', 'baz'] });
becomes
sum by (foo, bar, baz) (test_metric{foo="bar"})
rate
promql.rate({ expr: 'test_metric{bar="baz"}', interval: '5m' });
becomes
test_metric(foo{bar="baz"}[5m])
label manipulation
promql.label_replace({ expr: 'test_metric{foo="bar"}', newLabel: 'baz', existingLabel: 'foo' });
becomes
label_replace(test_metric{foo="bar"}, "baz", "$1", "foo", "(.*)")
aggregation over time
promql.sum_over_time({ expr: 'test_metric{foo="bar"}' });
becomes
sum_over_time((test_metric{foo="bar"})[$__range:])
simple offset
promql.offset({ units: { d: 42 } });
becomes
offset 42d
complex offset
promql.offset({ units: { y: 2, d: 1, h: 42, m: 2, s: 3 } });
becomes
offset 2y1d42h2m3s
The Expression
class can be used to compose reusable PromQL expressions to be further used with the promql
library.
new Expression({
metric: 'test_metric',
values: {
arg1: 'foo',
arg2: 'bar'
},
defaultOperator: MatchingOperator.regexMatch,
defaultSelectors: [{ label: 'baz', operator: MatchingOperator.notEqual, value: '' }],
}).toString(),
becomes
test_metric{baz!="", arg1=~"foo", arg2=~"bar"}
which can then be used with a promql
method
promql.max({
by: 'baz',
expr: new Expression({
metric: 'test_metric',
values: {
arg1: 'foo',
arg2: 'bar',
},
defaultOperator: MatchingOperator.regexMatch,
defaultSelectors: [{ label: 'baz', operator: MatchingOperator.notEqual, value: '' }],
}).toString(),
});
becomes
max by (baz) (test_metric{baz!="", arg1=~"foo", arg2=~"bar"})
see promql.ts for all available methods.