mirror of https://github.com/grafana/loki
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
308 lines
12 KiB
308 lines
12 KiB
|
5 years ago
|
---
|
||
|
|
title: LogQL
|
||
|
|
weight: 700
|
||
|
|
---
|
||
|
6 years ago
|
# LogQL: Log Query Language
|
||
|
|
|
||
|
6 years ago
|
Loki comes with its own PromQL-inspired language for queries called *LogQL*.
|
||
|
6 years ago
|
LogQL can be considered a distributed `grep` that aggregates log sources.
|
||
|
6 years ago
|
LogQL uses labels and operators for filtering.
|
||
|
6 years ago
|
|
||
|
6 years ago
|
There are two types of LogQL queries:
|
||
|
6 years ago
|
|
||
|
6 years ago
|
- *Log queries* return the contents of log lines.
|
||
|
|
- *Metric queries* extend log queries and calculate values based on the counts of logs from a log query.
|
||
|
|
|
||
|
|
A basic log query consists of two parts:
|
||
|
|
|
||
|
|
- **log stream selector**
|
||
|
|
- **filter expression**
|
||
|
6 years ago
|
|
||
|
|
Due to Loki's design, all LogQL queries must contain a log stream selector.
|
||
|
6 years ago
|
|
||
|
6 years ago
|
The log stream selector determines how many log streams (unique sources of log content, such as files) will be searched.
|
||
|
|
A more granular log stream selector then reduces the number of searched streams to a manageable volume.
|
||
|
|
This means that the labels passed to the log stream selector will affect the relative performance of the query's execution.
|
||
|
|
The filter expression is then used to do a distributed `grep` over the aggregated logs from the matching log streams.
|
||
|
6 years ago
|
|
||
|
6 years ago
|
To avoid escaping special characters you can use the `` ` ``(back-tick) instead of `"` when quoting strings.
|
||
|
|
For example `` `\w+` `` is the same as `"\\w+"`.
|
||
|
|
This is specially useful when writing a regular expression which contains multiple backslashes that require escaping.
|
||
|
6 years ago
|
|
||
|
6 years ago
|
## Log Stream Selector
|
||
|
6 years ago
|
|
||
|
6 years ago
|
The log stream selector determines which log streams should be included in your query results.
|
||
|
|
The stream selector is comprised of one or more key-value pairs, where each key is a **log label** and each value is that **label's value**.
|
||
|
6 years ago
|
|
||
|
6 years ago
|
The log stream selector is written by wrapping the key-value pairs in a pair of curly braces:
|
||
|
6 years ago
|
|
||
|
6 years ago
|
```logql
|
||
|
6 years ago
|
{app="mysql",name="mysql-backup"}
|
||
|
|
```
|
||
|
|
|
||
|
6 years ago
|
In this example, all log streams that have a label of `app` whose value is `mysql` _and_ a label of `name` whose value is `mysql-backup` will be included in the query results.
|
||
|
|
Note that this will match any log stream whose labels _at least_ contain `mysql-backup` for their name label;
|
||
|
|
if there are multiple streams that contain that label, logs from all of the matching streams will be shown in the results.
|
||
|
6 years ago
|
|
||
|
5 years ago
|
The `=` operator after the label name is a **label matching operator**.
|
||
|
6 years ago
|
The following label matching operators are supported:
|
||
|
6 years ago
|
|
||
|
|
- `=`: exactly equal.
|
||
|
|
- `!=`: not equal.
|
||
|
|
- `=~`: regex matches.
|
||
|
|
- `!~`: regex does not match.
|
||
|
|
|
||
|
|
Examples:
|
||
|
|
|
||
|
|
- `{name=~"mysql.+"}`
|
||
|
|
- `{name!~"mysql.+"}`
|
||
|
6 years ago
|
- `` {name!~`mysql-\d+`} ``
|
||
|
6 years ago
|
|
||
|
6 years ago
|
The same rules that apply for [Prometheus Label Selectors](https://prometheus.io/docs/prometheus/latest/querying/basics/#instant-vector-selectors) apply for Loki log stream selectors.
|
||
|
6 years ago
|
|
||
|
|
### Filter Expression
|
||
|
|
|
||
|
6 years ago
|
After writing the log stream selector, the resulting set of logs can be further filtered with a search expression.
|
||
|
|
The search expression can be just text or regex:
|
||
|
6 years ago
|
|
||
|
|
- `{job="mysql"} |= "error"`
|
||
|
|
- `{name="kafka"} |~ "tsdb-ops.*io:2003"`
|
||
|
6 years ago
|
- `` {name="cassandra"} |~ `error=\w+` ``
|
||
|
6 years ago
|
- `{instance=~"kafka-[23]",name="kafka"} != "kafka.server:type=ReplicaManager"`
|
||
|
6 years ago
|
|
||
|
5 years ago
|
In the previous examples, `|=`, `|~`, and `!=` act as **filter operators**.
|
||
|
6 years ago
|
The following filter operators are supported:
|
||
|
6 years ago
|
|
||
|
|
- `|=`: Log line contains string.
|
||
|
|
- `!=`: Log line does not contain string.
|
||
|
|
- `|~`: Log line matches regular expression.
|
||
|
|
- `!~`: Log line does not match regular expression.
|
||
|
|
|
||
|
6 years ago
|
Filter operators can be chained and will sequentially filter down the expression - resulting log lines must satisfy _every_ filter:
|
||
|
6 years ago
|
|
||
|
6 years ago
|
```logql
|
||
|
|
{job="mysql"} |= "error" != "timeout"
|
||
|
|
```
|
||
|
6 years ago
|
|
||
|
6 years ago
|
When using `|~` and `!~`, Go (as in [Golang](https://golang.org/)) [RE2 syntax](https://github.com/google/re2/wiki/Syntax) regex may be used.
|
||
|
|
The matching is case-sensitive by default and can be switched to case-insensitive prefixing the regex with `(?i)`.
|
||
|
6 years ago
|
|
||
|
6 years ago
|
## Metric Queries
|
||
|
|
|
||
|
6 years ago
|
LogQL also supports wrapping a log query with functions that allows for counting entries per stream.
|
||
|
6 years ago
|
|
||
|
6 years ago
|
Metric queries can be used to calculate things such as the rate of error messages, or the top N log sources with the most amount of logs over the last 3 hours.
|
||
|
6 years ago
|
|
||
|
|
### Range Vector aggregation
|
||
|
|
|
||
|
6 years ago
|
LogQL shares the same [range vector](https://prometheus.io/docs/prometheus/latest/querying/basics/#range-vector-selectors) concept from Prometheus, except the selected range of samples include a value of 1 for each log entry.
|
||
|
|
An aggregation can be applied over the selected range to transform it into an instance vector.
|
||
|
6 years ago
|
|
||
|
|
The currently supported functions for operating over are:
|
||
|
|
|
||
|
6 years ago
|
- `rate`: calculates the number of entries per second
|
||
|
6 years ago
|
- `count_over_time`: counts the entries for each log stream within the given range.
|
||
|
6 years ago
|
- `bytes_rate`: calculates the number of bytes per second for each stream.
|
||
|
|
- `bytes_over_time`: counts the amount of bytes used by each log stream for a given range.
|
||
|
6 years ago
|
|
||
|
6 years ago
|
#### Examples
|
||
|
|
|
||
|
|
```logql
|
||
|
|
count_over_time({job="mysql"}[5m])
|
||
|
|
```
|
||
|
6 years ago
|
|
||
|
6 years ago
|
This example counts all the log lines within the last five minutes for the MySQL job.
|
||
|
6 years ago
|
|
||
|
6 years ago
|
```logql
|
||
|
|
rate({job="mysql"} |= "error" != "timeout" [10s] )
|
||
|
|
```
|
||
|
6 years ago
|
|
||
|
6 years ago
|
This example demonstrates that a fully LogQL query can be wrapped in the aggregation syntax, including filter expressions.
|
||
|
|
This example gets the per-second rate of all non-timeout errors within the last ten seconds for the MySQL job.
|
||
|
6 years ago
|
|
||
|
6 years ago
|
It should be noted that the range notation `[5m]` can be placed at end of the log stream filter or right after the log stream matcher.
|
||
|
|
For example, the two syntaxes below are equivalent:
|
||
|
6 years ago
|
|
||
|
|
```logql
|
||
|
|
rate({job="mysql"} |= "error" != "timeout" [5m])
|
||
|
|
|
||
|
|
rate({job="mysql"}[5m] |= "error" != "timeout")
|
||
|
|
```
|
||
|
|
|
||
|
6 years ago
|
### Aggregation operators
|
||
|
|
|
||
|
6 years ago
|
Like [PromQL](https://prometheus.io/docs/prometheus/latest/querying/operators/#aggregation-operators), LogQL supports a subset of built-in aggregation operators that can be used to aggregate the element of a single vector, resulting in a new vector of fewer elements but with aggregated values:
|
||
|
6 years ago
|
|
||
|
|
- `sum`: Calculate sum over labels
|
||
|
|
- `min`: Select minimum over labels
|
||
|
|
- `max`: Select maximum over labels
|
||
|
|
- `avg`: Calculate the average over labels
|
||
|
|
- `stddev`: Calculate the population standard deviation over labels
|
||
|
|
- `stdvar`: Calculate the population standard variance over labels
|
||
|
|
- `count`: Count number of elements in the vector
|
||
|
|
- `bottomk`: Select smallest k elements by sample value
|
||
|
|
- `topk`: Select largest k elements by sample value
|
||
|
|
|
||
|
6 years ago
|
The aggregation operators can either be used to aggregate over all label values or a set of distinct label values by including a `without` or a `by` clause:
|
||
|
6 years ago
|
|
||
|
6 years ago
|
```logql
|
||
|
|
<aggr-op>([parameter,] <vector expression>) [without|by (<label list>)]
|
||
|
|
```
|
||
|
6 years ago
|
|
||
|
6 years ago
|
`parameter` is only required when using `topk` and `bottomk`.
|
||
|
|
`topk` and `bottomk` are different from other aggregators in that a subset of the input samples, including the original labels, are returned in the result vector.
|
||
|
6 years ago
|
|
||
|
6 years ago
|
`by` and `without` are only used to group the input vector.
|
||
|
|
The `without` clause removes the listed labels from the resulting vector, keeping all others.
|
||
|
|
The `by` clause does the opposite, dropping labels that are not listed in the clause, even if their label values are identical between all elements of the vector.
|
||
|
6 years ago
|
|
||
|
|
#### Examples
|
||
|
|
|
||
|
|
Get the top 10 applications by the highest log throughput:
|
||
|
|
|
||
|
6 years ago
|
```logql
|
||
|
|
topk(10,sum(rate({region="us-east1"}[5m])) by (name))
|
||
|
|
```
|
||
|
6 years ago
|
|
||
|
6 years ago
|
Get the count of logs for the last five minutes, grouping
|
||
|
6 years ago
|
by level:
|
||
|
|
|
||
|
6 years ago
|
```logql
|
||
|
|
sum(count_over_time({job="mysql"}[5m])) by (level)
|
||
|
|
```
|
||
|
6 years ago
|
|
||
|
|
Get the rate of HTTP GET requests from NGINX logs:
|
||
|
|
|
||
|
6 years ago
|
```logql
|
||
|
|
avg(rate(({job="nginx"} |= "GET")[10s])) by (region)
|
||
|
|
```
|
||
|
6 years ago
|
|
||
|
|
### Binary Operators
|
||
|
|
|
||
|
|
#### Arithmetic Binary Operators
|
||
|
|
|
||
|
|
The following binary arithmetic operators exist in Loki:
|
||
|
|
|
||
|
|
- `+` (addition)
|
||
|
|
- `-` (subtraction)
|
||
|
|
- `*` (multiplication)
|
||
|
|
- `/` (division)
|
||
|
|
- `%` (modulo)
|
||
|
|
- `^` (power/exponentiation)
|
||
|
|
|
||
|
6 years ago
|
Binary arithmetic operators are defined between two literals (scalars), a literal and a vector, and two vectors.
|
||
|
6 years ago
|
|
||
|
6 years ago
|
Between two literals, the behavior is obvious:
|
||
|
|
They evaluate to another literal that is the result of the operator applied to both scalar operands (`1 + 1 = 2`).
|
||
|
|
|
||
|
|
Between a vector and a literal, the operator is applied to the value of every data sample in the vector, e.g. if a time series vector is multiplied by 2, the result is another vector in which every sample value of the original vector is multiplied by 2.
|
||
|
6 years ago
|
|
||
|
6 years ago
|
Between two vectors, a binary arithmetic operator is applied to each entry in the left-hand side vector and its matching element in the right-hand vector.
|
||
|
|
The result is propagated into the result vector with the grouping labels becoming the output label set. Entries for which no matching entry in the right-hand vector can be found are not part of the result.
|
||
|
6 years ago
|
|
||
|
6 years ago
|
Pay special attention to [operator order](#operator-order) when chaining arithmetic operators.
|
||
|
6 years ago
|
|
||
|
|
##### Examples
|
||
|
|
|
||
|
6 years ago
|
Implement a health check with a simple query:
|
||
|
|
|
||
|
6 years ago
|
```logql
|
||
|
|
1 + 1
|
||
|
|
```
|
||
|
6 years ago
|
|
||
|
|
Double the rate of a a log stream's entries:
|
||
|
|
|
||
|
6 years ago
|
```logql
|
||
|
|
sum(rate({app="foo"})) * 2
|
||
|
|
```
|
||
|
6 years ago
|
|
||
|
6 years ago
|
Get proportion of warning logs to error logs for the `foo` app
|
||
|
|
|
||
|
6 years ago
|
```logql
|
||
|
|
sum(rate({app="foo", level="warn"}[1m])) / sum(rate({app="foo", level="error"}[1m]))
|
||
|
|
```
|
||
|
6 years ago
|
|
||
|
|
#### Logical/set binary operators
|
||
|
|
|
||
|
|
These logical/set binary operators are only defined between two vectors:
|
||
|
|
|
||
|
|
- `and` (intersection)
|
||
|
|
- `or` (union)
|
||
|
|
- `unless` (complement)
|
||
|
|
|
||
|
6 years ago
|
`vector1 and vector2` results in a vector consisting of the elements of vector1 for which there are elements in vector2 with exactly matching label sets.
|
||
|
|
Other elements are dropped.
|
||
|
6 years ago
|
|
||
|
|
`vector1 or vector2` results in a vector that contains all original elements (label sets + values) of vector1 and additionally all elements of vector2 which do not have matching label sets in vector1.
|
||
|
|
|
||
|
6 years ago
|
`vector1 unless vector2` results in a vector consisting of the elements of vector1 for which there are no elements in vector2 with exactly matching label sets.
|
||
|
|
All matching elements in both vectors are dropped.
|
||
|
6 years ago
|
|
||
|
|
##### Examples
|
||
|
|
|
||
|
6 years ago
|
This contrived query will return the intersection of these queries, effectively `rate({app="bar"})`:
|
||
|
6 years ago
|
|
||
|
6 years ago
|
```logql
|
||
|
|
rate({app=~"foo|bar"}[1m]) and rate({app="bar"}[1m])
|
||
|
|
```
|
||
|
6 years ago
|
|
||
|
|
#### Comparison operators
|
||
|
|
|
||
|
6 years ago
|
- `==` (equality)
|
||
|
|
- `!=` (inequality)
|
||
|
|
- `>` (greater than)
|
||
|
|
- `>=` (greater than or equal to)
|
||
|
|
- `<` (less than)
|
||
|
|
- `<=` (less than or equal to)
|
||
|
|
|
||
|
|
Comparison operators are defined between scalar/scalar, vector/scalar, and vector/vector value pairs.
|
||
|
|
By default they filter.
|
||
|
|
Their behavior can be modified by providing `bool` after the operator, which will return 0 or 1 for the value rather than filtering.
|
||
|
|
|
||
|
|
Between two scalars, these operators result in another scalar that is either 0 (false) or 1 (true), depending on the comparison result.
|
||
|
|
The `bool` modifier must **not** be provided.
|
||
|
|
|
||
|
|
`1 >= 1` is equivalent to `1`
|
||
|
|
|
||
|
|
Between a vector and a scalar, these operators are applied to the value of every data sample in the vector, and vector elements between which the comparison result is false get dropped from the result vector.
|
||
|
|
If the `bool` modifier is provided, vector elements that would be dropped instead have the value 0 and vector elements that would be kept have the value 1.
|
||
|
|
|
||
|
|
Filters the streams which logged at least 10 lines in the last minute:
|
||
|
6 years ago
|
|
||
|
6 years ago
|
```logql
|
||
|
|
count_over_time({foo="bar"}[1m]) > 10
|
||
|
|
```
|
||
|
|
|
||
|
|
Attach the value(s) `0`/`1` to streams that logged less/more than 10 lines:
|
||
|
|
|
||
|
|
```logql
|
||
|
|
count_over_time({foo="bar"}[1m]) > bool 10
|
||
|
|
```
|
||
|
6 years ago
|
|
||
|
6 years ago
|
Between two vectors, these operators behave as a filter by default, applied to matching entries.
|
||
|
|
Vector elements for which the expression is not true or which do not find a match on the other side of the expression get dropped from the result, while the others are propagated into a result vector.
|
||
|
|
If the `bool` modifier is provided, vector elements that would have been dropped instead have the value 0 and vector elements that would be kept have the value 1, with the grouping labels again becoming the output label set.
|
||
|
6 years ago
|
|
||
|
6 years ago
|
Return the streams matching `app=foo` without app labels that have higher counts within the last minute than their counterparts matching `app=bar` without app labels:
|
||
|
6 years ago
|
|
||
|
6 years ago
|
```logql
|
||
|
|
sum without(app) (count_over_time({app="foo"}[1m])) > sum without(app) (count_over_time({app="bar"}[1m]))
|
||
|
|
```
|
||
|
|
|
||
|
|
Same as above, but vectors have their values set to `1` if they pass the comparison or `0` if they fail/would otherwise have been filtered out:
|
||
|
|
|
||
|
|
```logql
|
||
|
|
sum without(app) (count_over_time({app="foo"}[1m])) > bool sum without(app) (count_over_time({app="bar"}[1m]))
|
||
|
|
```
|
||
|
6 years ago
|
|
||
|
6 years ago
|
#### Operator order
|
||
|
6 years ago
|
|
||
|
6 years ago
|
When chaining or combining operators, you have to consider operator precedence:
|
||
|
|
Generally, you can assume regular [mathematical convention](https://en.wikipedia.org/wiki/Order_of_operations) with operators on the same precedence level being left-associative.
|
||
|
6 years ago
|
|
||
|
6 years ago
|
More details can be found in the [Golang language documentation](https://golang.org/ref/spec#Operator_precedence).
|
||
|
6 years ago
|
|
||
|
6 years ago
|
`1 + 2 / 3` is equal to `1 + ( 2 / 3 )`.
|
||
|
6 years ago
|
|
||
|
6 years ago
|
`2 * 3 % 2` is evaluated as `(2 * 3) % 2`.
|