If you've ever wanted to answer questions like "how many errors happened today?" or "which user generated the most requests?", the stats command is what you're looking for. It's one of the most useful commands in SPL, and once you get the hang of it, you'll use it in nearly every search.
What the stats Command Actually Does
stats takes your raw events and collapses them into a summary table. Think of it like a pivot table in Excel, but for log data. Instead of scrolling through thousands of individual events, you get a clean table with exactly the numbers you need.
The basic structure is:
index=your_index | stats function(field) AS alias BY grouping_field
You don't have to use BY -- but when you do, it breaks your results into groups, which is usually what makes the output meaningful.
Your First stats Search: Counting Events
Let's start simple. This counts how many events you have:
index=main | stats count
That returns a single number. Not very exciting on its own, but add a BY clause and it gets useful fast:
index=main | stats count BY host
Now you've got a table showing how many events came from each host. That's the kind of query you'll run all the time.
Counting Specific Values with count(field)
There's a difference between count and count(field). The plain count counts every event. count(field) only counts events where that field has a value (i.e. it's not null).
index=web_logs | stats count(status_code) AS responses BY status_code
This groups your web logs by HTTP status code and counts how many of each you have. You can immediately see how many 200s, 404s, and 500s you're dealing with.
Summing and Averaging Fields
If you've got numeric fields in your data, sum() and avg() are your friends.
index=transactions | stats sum(amount) AS total_revenue BY product
index=performance | stats avg(response_time) AS avg_response_ms BY endpoint
The first query totals up revenue per product. The second gives you the average response time per API endpoint. Both are exactly the kind of thing you'd want on a dashboard.
Want to go deeper?
No Nonsense Introduction to Splunk
Skip the endless docs rabbit hole. This hands-on course takes you from zero to confident with Splunk searches, dashboards, and alerts. Taught by a Splunk Certified Architect with over 10 years of real-world experience.
View the course →Combining Multiple Functions in One Search
You don't have to pick just one function. You can stack them in a single stats call:
index=web_logs | stats count AS total_requests, avg(bytes) AS avg_size, max(bytes) AS largest_request BY uri_path
This gives you a table with three columns for each URL path: total hits, average response size, and the biggest response. One search, all the context you need.
Using dc() to Count Distinct Values
dc() stands for "distinct count" -- it tells you how many unique values a field has. This is handy for things like counting unique users or unique IPs.
index=auth_logs | stats dc(user) AS unique_users BY src_ip
If a single IP is showing hundreds of unique users, that's worth investigating.
Sorting Your stats Results
stats doesn't sort for you. You'll usually want to pipe your results into sort to make them readable:
index=main sourcetype=syslog | stats count BY source | sort -count
The -count means sort descending (highest first). Use +count or just count for ascending.
Common Mistakes to Avoid
Forgetting to filter first. Running stats over a huge index without any time range or filter is slow. Always narrow things down first:
index=main earliest=-24h sourcetype=access_combined | stats count BY clientip
Renaming with AS. Without AS, field names like count(response_time) end up in your table headers. Rename them to something readable -- it matters when you're building dashboards.
Mixing up count and count(field). If a field isn't always present, count and count(field) will give you different numbers. Know which one you want.
A Practical Example: Top Error Sources
Here's a real-world search you might run for a daily health check:
index=app_logs level=ERROR earliest=-24h
| stats count AS error_count, dc(user) AS affected_users BY component
| sort -error_count
| head 10
This finds your top 10 most error-prone components in the last 24 hours, and also tells you how many users each one affected. That's actionable information, not just noise.
What to Learn Next
The stats command is the gateway to most of Splunk's analytical power. Once you're comfortable with it, look at timechart (which is basically stats over time) and eventstats (which adds stats fields back onto your original events without collapsing them).
From here, the natural next step is building searches into dashboards so your team can see this data without having to run queries manually.
Ready to get hands-on? The Introduction to Splunk course walks you through SPL from scratch, including a full module on Basic Search where you'll put commands like stats to work on real data.
Ready to level up?
No Nonsense Introduction to Splunk
Learn Splunk the practical way. No death-by-slides, no waffle. Just focused video demos with real data and a structured path from installation to dashboards and alerts. From just $4.99 with lifetime access.
Start the course for $4.99 →Relevant lessons in the course