eventstats
The eventstats command enriches your event data with calculated summary statistics. It analyzes the specified fields within your events, computes various statistical measures, and then appends these results as new fields to each original event.
The eventstats command operates in the following way:
- It performs calculations across the entire search results or within defined groups.
- The original events remain intact, with new fields added to contain the statistical results.
- The command is particularly useful for comparative analysis, identifying outliers, and providing additional context to individual events.
Comparing stats and eventstats
For a comprehensive comparison of stats, eventstats, and streamstats commands, including their differences in transformation behavior, output format, aggregation scope, and use cases, see Comparing stats, eventstats, and streamstats.
Syntax
The eventstats command has the following syntax:
eventstats [bucket_nullable=bool] <function>... [by-clause]
The following are examples of the eventstats command syntax:
source = table | eventstats avg(a)
source = table | where a < 50 | eventstats count(c)
source = table | eventstats min(c), max(c) by b
source = table | eventstats count(c) as count_by by b | where count_by > 1000
source = table | eventstats dc(field) as distinct_count
source = table | eventstats distinct_count(category) by region
Parameters
The eventstats command supports the following parameters.
| Parameter | Required/Optional | Description |
|---|---|---|
<function> | Required | An aggregation function or window function. |
bucket_nullable | Optional | Controls whether the eventstats command considers null buckets as a valid group in group-by aggregations. When set to false, it does not treat null group-by values as a distinct group during aggregation. Default is determined by plugins.ppl.syntax.legacy.preferred. |
<by-clause> | Optional | Groups results by specified fields or expressions. Syntax: by [span-expression,] [field,]... Default is aggregating over the entire search results. |
<span-expression> | Optional | Splits a field into buckets by intervals (at most one). Syntax: span(field_expr, interval_expr). For example, span(age, 10) creates 10-year age buckets, while span(timestamp, 1h) creates hourly buckets. |
Time units
The following time units are available for span expressions:
- Milliseconds (
ms) - Seconds (
s) - Minutes (
m, case sensitive) - Hours (
h) - Days (
d) - Weeks (
w) - Months (
M, case sensitive) - Quarters (
q) - Years (
y)
Aggregation functions
The eventstats command supports the following aggregation functions:
COUNT– Count of valuesSUM– Sum of numeric valuesAVG– Average of numeric valuesMAX– Maximum valueMIN– Minimum valueVAR_SAMP– Sample varianceVAR_POP– Population varianceSTDDEV_SAMP– Sample standard deviationSTDDEV_POP– Population standard deviationDISTINCT_COUNT/DC– Distinct count of valuesEARLIEST– Earliest value by timestampLATEST– Latest value by timestamp
For detailed documentation of each function, see Functions.
Example 1: Enriching logs with per-service counts
The following query adds the total log count for each service to every log entry, letting you see how active each service is alongside individual log details:
source=otellogs
| eventstats count() as service_total by `resource.attributes.service.name`
| where severityText = 'ERROR'
| sort `resource.attributes.service.name`
| fields severityText, `resource.attributes.service.name`, service_total, body
| head 3
The query returns the following results:
| severityText | resource.attributes.service.name | service_total | body |
|---|---|---|---|
| ERROR | checkout | 3 | NullPointerException in CheckoutService.placeOrder at line 142 |
| ERROR | checkout | 3 | Kafka producer delivery failed: message too large for topic order-events (max 1048576 bytes) |
| ERROR | frontend-proxy | 3 | [2024-02-01T09:20:00.456Z] “POST /api/checkout HTTP/1.1” 503 - 0 30000 checkout-8d4f7b-mk2p9 |
Example 2: Calculating severity statistics by group
The following query adds the average severity and error count per service to each log entry:
source=otellogs
| where severityText = 'ERROR'
| eventstats avg(severityNumber) as avg_sev, count() as error_count by `resource.attributes.service.name`
| sort `resource.attributes.service.name`
| fields `resource.attributes.service.name`, severityNumber, avg_sev, error_count
The query returns the following results:
| resource.attributes.service.name | severityNumber | avg_sev | error_count |
|---|---|---|---|
| checkout | 17 | 17.0 | 2 |
| checkout | 17 | 17.0 | 2 |
| frontend-proxy | 17 | 17.0 | 1 |
| payment | 17 | 17.0 | 2 |
| payment | 17 | 17.0 | 2 |
| product-catalog | 17 | 17.0 | 1 |
| recommendation | 17 | 17.0 | 1 |
Example 3: Null bucket handling
The following query uses bucket_nullable=false to exclude null values from the group-by aggregation:
source=otellogs
| eventstats bucket_nullable=false count() as scope_count by instrumentationScope.name
| where severityText = 'ERROR'
| sort `resource.attributes.service.name`
| fields `resource.attributes.service.name`, `instrumentationScope.name`, scope_count
The query returns the following results:
| resource.attributes.service.name | instrumentationScope.name | scope_count |
|---|---|---|
| checkout | null | null |
| checkout | null | null |
| frontend-proxy | null | null |
| payment | null | null |
| payment | @opentelemetry/instrumentation-http | 2 |
| product-catalog | null | null |
| recommendation | null | null |