Aggregation operators :: Kloudfuse Docs
Aggregation operators
Aggregation operators enable you to create log-based metrics. Log-based metrics help you cut through the noise of high-volume logs to identify trends and patterns in your application activity.
FuseQL groups aggregations by time buckets and supports additional grouping dimensions.
avg
Computes the arithmetic mean of a numeric field across matched log lines within the selected query time window. The avg operator ignores null or missing values. Use it to understand the typical value of a metric — for example, the mean response body size per HTTP method over the last hour.
Syntax
| avg(<field>) [as <alias>] [by <field1>, <field2>, ...]
Parameters
| Parameter | Required | Description |
|---|---|---|
<field> |
Required | The numeric field to average. Null or missing values are ignored. |
as <alias> |
Optional | Renames the output column. Defaults to _avg. |
by <field1>, … |
Optional | Groups results by one or more fields. Without by, returns a single aggregate row for all matched logs. |
Example
Parse nginx access logs and compute the average response body size (in bytes) per HTTP method. A much higher average for GET than POST reflects that GET requests return full resource payloads while POST responses are typically small acknowledgements.
source="nginx"
| parse "* - - [*] \"* *\" * * *" as ip,date,method,url,status,bytes,rest
| avg(bytes) as avg_bytes by method
| method | avg_bytes |
|---|---|
| GET | 87,284.33 |
| POST | 37.77 |
| OPTIONS | 69.0 |
Expected output
avg aggregates over every log line that matches the query within the selected time window (for example, the last 1 hour). A single returned row represents the mean across all matching events in that window. After extracting fields with parse, FuseQL coerces the string values to numbers automatically — no explicit conversion is needed. |
count_unique
Counts the number of distinct values of a field across matched log lines. count_unique works on string, UUID, and IP address typed facets — it cannot be applied to purely numeric fields. Use it to answer questions like "how many distinct URLs were requested per HTTP method?" or "how many unique user sessions made requests in this window?"
Syntax
| count_unique(<field>) [as <alias>] [by <field1>, <field2>, ...]
Parameters
| Parameter | Required | Description |
|---|---|---|
<field> |
Required | The string, UUID, or IP address facet to count distinct values of. |
as <alias> |
Optional | Renames the output column. Defaults to _count_unique. |
by <field1>, … |
Optional | Groups results by one or more fields. Without by, returns a single aggregate row for all matched logs. |
Example: distinct URLs per HTTP method
Parse nginx access logs and count how many unique URLs were requested for each HTTP method. A high count for GET compared to POST indicates broad read access across many resources.
source="nginx"
| parse "* - - [*] \"* *\" * * *" as ip,date,method,url,status,bytes,rest
| count_unique(url) by method
| method | _count_unique |
|---|---|
| DELETE | 2 |
| GET | 3,353 |
| POST | 197,143 |
Expected output
count_unique works on string, UUID, and IP address typed facets. Fields extracted by parse are treated as strings, so they work directly with count_unique without any conversion. |
count
Counts the total number of log lines matched by the query. Unlike most aggregation operators, count takes no field argument — it counts rows, not field values. Use it to measure request volume, error frequency, or event occurrence across any grouping.
Syntax
| count [as <alias>] [by <field1>, <field2>, ...]
Parameters
| Parameter | Required | Description |
|---|---|---|
as <alias> |
Optional | Renames the output column. Defaults to _count. |
by <field1>, … |
Optional | Groups results by one or more fields. Without by, returns a single aggregate row for all matched logs. |
Example: request count by HTTP method
Parse nginx access logs and count requests per HTTP method to understand traffic distribution.
source="nginx"
| parse "* - - [*] \"* *\" * * *" as ip,date,method,url,status,bytes,rest
| count by method
| method | _count |
|---|---|
| DELETE | 4 |
| GET | 92,253 |
| POST | 67,267,496 |
Expected output
Example: time-bucketed request counts
Count requests per minute to spot traffic spikes or drops over time.
source="nginx"
| timeslice 1m
| count as req_count by _timeslice
| _timeslice | req_count |
|---|---|
| 2024-06-10 09:00 | 38,412 |
| 2024-06-10 09:01 | 41,987 |
| 2024-06-10 09:02 | 39,631 |
Expected output
count counts every matched log line, including lines where a particular field is null. To count only lines where a specific field has a value, use count_unique on that field, or add a where filter before counting. |
first
Returns the value of a field from the chronologically earliest log line within the query window. When grouped with by, first returns the earliest value observed per group. Use it to capture the initial state — for example, the first URL requested via each HTTP method at the start of a traffic window.
Syntax
| first(<field>) [as <alias>] [by <field1>, <field2>, ...]
Parameters
| Parameter | Required | Description |
|---|---|---|
<field> |
Required | The field whose earliest value to return. Works with string and numeric fields. |
as <alias> |
Optional | Renames the output column. Defaults to _first. |
by <field1>, … |
Optional | Groups results by one or more fields. Without by, returns a single aggregate row for all matched logs. |
Example
Parse nginx access logs and retrieve the first URL requested for each HTTP method. This shows the first request path seen for each method within the selected time window.
source="nginx"
| parse "* - - [*] \"* *\" * * *" as ip,date,method,url,status,bytes,rest
| first(url) by method
| method | _first |
|---|---|
| DELETE | /grafana/apis/…/dashboards/dcb2ef50 |
| GET | /oauth2/sign_in?rd=%2F HTTP/1.1 |
| POST | /ingester/otlp/metrics HTTP/2.0 |
Expected output
first is determined by log ingestion order within the query window, which reflects the timestamp on each log line. It is most useful for baselining or detecting cold-start behaviour. Compare first against last to see whether values changed significantly over the window. |
last
Returns the value of a field from the chronologically latest log line within the query window. When grouped with by, last returns the most recent value observed per group. Use it to capture the current or final state — for example, the most recent URL requested via each HTTP method at the end of a traffic window.
Syntax
| last(<field>) [as <alias>] [by <field1>, <field2>, ...]
Parameters
| Parameter | Required | Description |
|---|---|---|
<field> |
Required | The field whose latest value to return. Works with string and numeric fields. |
as <alias> |
Optional | Renames the output column. Defaults to _last. |
by <field1>, … |
Optional | Groups results by one or more fields. Without by, returns a single aggregate row for all matched logs. |
Example
Parse nginx access logs and retrieve the most recent URL requested for each HTTP method. This shows the last request path seen for each method within the selected time window.
source="nginx"
| parse "* - - [*] \"* *\" * * *" as ip,date,method,url,status,bytes,rest
| last(url) by method
| method | _last |
|---|---|
| DELETE | /grafana/apis/…/dashboards/fc05b8c4 |
| GET | /ingester/health/ HTTP/2.0 |
| POST | /ingester/otlp/v1/logs HTTP/2.0 |
Expected output
last is the counterpart of first — together they let you compare the earliest and most recent observations within a window to detect trends or state changes. last is most useful for capturing the final outcome of a process or the steady-state value after a warm-up period. |
max
Returns the highest value of a numeric field across matched log lines. The max operator ignores null or missing values. Use it to surface worst-case conditions such as the highest HTTP status code, peak response latency, or maximum error count observed in a window.
Syntax
| max(<field>) [as <alias>] [by <field1>, <field2>, ...]
Parameters
| Parameter | Required | Description |
|---|---|---|
<field> |
Required | The numeric field to find the maximum of. Null or missing values are ignored. |
as <alias> |
Optional | Renames the output column. Defaults to _max. |
by <field1>, … |
Optional | Groups results by one or more fields. Without by, returns a single aggregate row for all matched logs. |
Example
Parse nginx access logs and find the largest response body size (in bytes) per HTTP method. A very large max_bytes for GET reveals the biggest single payload served — useful for identifying unexpectedly large responses.
source="nginx"
| parse "* - - [*] \"* *\" * * *" as ip,date,method,url,status,bytes,rest
| max(bytes) as max_bytes by method
| method | max_bytes |
|---|---|
| GET | 35,590,999 |
| POST | 10,422,627 |
| OPTIONS | 138 |
Expected output
max surfaces worst-case conditions. A single outlier can cause max to spike even when avg looks healthy — pair max with p99 to distinguish rare extreme outliers from the general tail. After extracting fields with parse, FuseQL coerces string values to numbers automatically. |
min
Returns the lowest value of a numeric field across matched log lines. The min operator ignores null or missing values. Use it to find the best-case response time, the lowest HTTP status code, or the minimum resource usage observed in a window.
Syntax
| min(<field>) [as <alias>] [by <field1>, <field2>, ...]
Parameters
| Parameter | Required | Description |
|---|---|---|
<field> |
Required | The numeric field to find the minimum of. Null or missing values are ignored. |
as <alias> |
Optional | Renames the output column. Defaults to _min. |
by <field1>, … |
Optional | Groups results by one or more fields. Without by, returns a single aggregate row for all matched logs. |
Example
Parse nginx access logs and find the smallest response body size (in bytes) per HTTP method. A min_bytes of 0 for GET and POST indicates that some responses sent no body — for example, 204 No Content or 304 Not Modified responses.
source="nginx"
| parse "* - - [*] \"* *\" * * *" as ip,date,method,url,status,bytes,rest
| min(bytes) as min_bytes by method
| method | min_bytes |
|---|---|
| GET | 0 |
| POST | 0 |
| OPTIONS | 0 |
Expected output
min is useful for establishing a lower bound. A result of 0 bytes does not mean the response failed — status codes like 204 No Content and 304 Not Modified legitimately send no body. Combine min and max in a single query to see the full response size range in one result set. After extracting fields with parse, FuseQL coerces string values to numbers automatically. |
percentiles
Computes a percentile of a numeric field across matched log lines. Seven percentile operators are available: p16, p50, p75, p84, p90, p95, and p99. Multiple percentile operators can be combined in a single query pipe stage to produce several percentile columns at once. Null or missing field values are ignored.
Syntax
| p50(<field>) [as <alias>] [by <field1>, <field2>, ...]
| p75(<field>) [as <alias>] [by <field1>, <field2>, ...]
| p90(<field>) [as <alias>] [by <field1>, <field2>, ...]
| p95(<field>) [as <alias>] [by <field1>, <field2>, ...]
| p99(<field>) [as <alias>] [by <field1>, <field2>, ...]
| p84(<field>) [as <alias>] [by <field1>, <field2>, ...]
| p16(<field>) [as <alias>] [by <field1>, <field2>, ...]
Parameters
| Parameter | Required | Description |
|---|---|---|
<field> |
Required | The numeric field to compute the percentile of. Null or missing values are ignored. |
as <alias> |
Optional | Renames the output column. Defaults to _p<N> (e.g. _p95). |
by <field1>, … |
Optional | Groups results by one or more fields. Without by, returns a single aggregate row for all matched logs. |
Example: median and tail percentiles for HTTP status codes
Parse nginx access logs and compute p50, p90, and p99 of response body size per HTTP method. The large gap between GET p50 (138 bytes) and p99 (3,678,129 bytes) reveals that while most GET responses are small, the top 1% are multi-megabyte payloads — exactly the kind of tail behaviour that avg would understate.
source="nginx"
| parse "* - - [*] \"* *\" * * *" as ip,date,method,url,status,bytes,rest
| p50(bytes) as p50_bytes, p90(bytes) as p90_bytes, p99(bytes) as p99_bytes by method
| method | p50_bytes | p90_bytes | p99_bytes |
|---|---|---|---|
| GET | 138 | 3,026 | 3,678,129 |
| POST | 2 | 2 | 2 |
| OPTIONS | 69 | 124 | 137 |
Expected output
Use p95 or p99 for SLO threshold checks and p50 (the median) for a robust measure of typical behaviour that is not skewed by outliers. A large gap between p50 and p99 indicates a long-tail distribution — common for endpoints that serve both small API responses and large file downloads. After extracting fields with parse, FuseQL coerces string values to numbers automatically. |
stddev
Computes the standard deviation of a numeric field across matched log lines. stddev measures how spread out values are around the mean — a low value indicates that most log lines have similar values, while a high value indicates erratic or inconsistent behaviour. Null or missing field values are ignored.
Syntax
| stddev(<field>) [as <alias>] [by <field1>, <field2>, ...]
Parameters
| Parameter | Required | Description |
|---|---|---|
<field> |
Required | The numeric field to compute the standard deviation of. Null or missing values are ignored. |
as <alias> |
Optional | Renames the output column. Defaults to _stddev. |
by <field1>, … |
Optional | Groups results by one or more fields. Without by, returns a single aggregate row for all matched logs. |
Example
Parse nginx access logs and measure the consistency of response body sizes per HTTP method. A very high standard deviation for GET (1,073,687 bytes) reflects that GET responses range from zero-byte 304 responses to multi-megabyte payloads. The low standard deviation for POST (1,894 bytes) shows that POST responses are consistently small.
source="nginx"
| parse "* - - [*] \"* *\" * * *" as ip,date,method,url,status,bytes,rest
| stddev(bytes) as stddev_bytes by method
| method | stddev_bytes |
|---|---|
| GET | 1,073,687.61 |
| POST | 1,894.84 |
| OPTIONS | 69.0 |
Expected output
stddev is expressed in the same unit as the input field (bytes, in this case), making it easy to interpret alongside avg. A high stddev relative to avg signals a wide mix of response sizes — this is normal for GET endpoints that serve both small API responses and large file downloads. Prefer stddev over stdvar when you need a human-readable measure of spread. After extracting fields with parse, FuseQL coerces string values to numbers automatically. |
stdvar
Computes the variance of a numeric field across matched log lines. Variance is the square of the standard deviation and quantifies the spread of values around the mean. It is primarily used in statistical calculations that combine variance across groups; for human-readable interpretation, prefer stddev. Null or missing field values are ignored.
Syntax
| stdvar(<field>) [as <alias>] [by <field1>, <field2>, ...]
Parameters
| Parameter | Required | Description |
|---|---|---|
<field> |
Required | The numeric field to compute the variance of. Null or missing values are ignored. |
as <alias> |
Optional | Renames the output column. Defaults to _stdvar. |
by <field1>, … |
Optional | Groups results by one or more fields. Without by, returns a single aggregate row for all matched logs. |
Example
Parse nginx access logs and compute the variance in response body size per HTTP method. The very high variance for GET (1,149,810,367,291 bytes²) versus POST (3,591,132 bytes²) reflects the wide range of payload sizes returned by GET requests compared to the consistently small POST responses.
source="nginx"
| parse "* - - [*] \"* *\" * * *" as ip,date,method,url,status,bytes,rest
| stdvar(bytes) as var_bytes by method
| method | var_bytes |
|---|---|
| GET | 1,149,810,367,291.90 |
| POST | 3,591,132.22 |
| OPTIONS | 4,761.0 |
Expected output
Because variance squares the unit of the input field (bytes², in this case), the result is difficult to interpret directly. Use stdvar when you need to mathematically combine variance across groups (for example, pooled variance calculations). For dashboards and alerts where you want a spread figure in the original unit (bytes), use stddev instead. After extracting fields with parse, FuseQL coerces string values to numbers automatically. |
sum
Computes the total sum of a numeric field across matched log lines. The sum operator ignores null or missing values. Use it to measure cumulative load — for example, the total number of requests handled per HTTP method or the aggregate bytes transferred in a window.
Syntax
| sum(<field>) [as <alias>] [by <field1>, <field2>, ...]
Parameters
| Parameter | Required | Description |
|---|---|---|
<field> |
Required | The numeric field to sum. Null or missing values are ignored. |
as <alias> |
Optional | Renames the output column. Defaults to _sum. |
by <field1>, … |
Optional | Groups results by one or more fields. Without by, returns a single aggregate row for all matched logs. |
Example
Parse nginx access logs and compute the total bytes transferred per HTTP method. Summing response body sizes gives the total data volume served by each method during the query time window — useful for bandwidth analysis and capacity planning.
source="nginx"
| parse "* - - [*] \"* *\" * * *" as ip,date,method,url,status,bytes,rest
| sum(bytes) as total_bytes by method
| method | total_bytes |
|---|---|
| GET | 7,913,715,573 |
| POST | 2,524,318,781 |
| OPTIONS | 138 |
Expected output
sum is most meaningful for fields that represent quantities that accumulate, such as bytes transferred, processing time, or event counts. The values above are totals across all log lines in the selected time window. After extracting fields with parse, FuseQL coerces string values to numbers automatically. |