Stop Wasting Time: Filter Saved Splunk Reports on Time in Dashboards
By Eric Levy, Splunk Consultant II
In a fast-paced world, people don’t have time to wait for reports to generate important metrics. Thankfully, Splunk provides several tools that speed up getting critical results generated for post-processed searches and dashboard panels. The | savedsearch and | loadjob commands allow users to retrieve Splunk results from existing reports or search jobs.
- | savedsearch returns the results from a saved search or report. Simply add the title of your search after the command. By default, this will use the time range defined in the saved search or report. However, selecting your own time range in the Time Picker overrides this setting.
- | loadjob loads results from an already run search job using the search job id (sid) and uses the time range of the existing search job.
Using these in dashboards can raise a problem: using | savedsearch in a base search or any use of a | loadjob loses the ability to control the time range with the Time Picker due to a pre-selected time range value. You can tokenize the time value within the base search if you’re using a | savedsearch, but let’s say we are unable for the sake of this example.
Let’s look at this sample dashboard. There is a | savedsearch used as a base search collecting some simple metrics on my laptop, and the sole panel is a timechart looking at eventtype frequency. The base search is set to look back 7 days.
Base Search:
| savedsearch MACOS_test_report Panel Search (uses Base Search):
| timechart count by eventtype If we try and change the Time Picker to the last 24 hours… nothing happens.
Let’s add on some SPL to force the search to use values from the Time Picker. Please note that this method can only be used to filter down from the original time range, rather than expand the search to use a larger time range.
Going line by line:
| eval earliest="$time.earliest$" First, to remove any confusion from tokens or quotes, we store the time.earliest token value (which comes from the Time Picker as the lower time bound) in a variable called “earliest”.
| eval latest = if(isnull("$time.latest$") OR match("$time.latest$","now"), now(), "$time.latest$") Next, we set the time.latest token value (which comes from the Time Picker as the upper time bound) with an if() function.
When searching All Time, the Time Picker will set the time.earliest token value to “0” and the time.latest token value to nothing. Or, there will be situations where the time.latest variable is set to the literal string “now”. To circumvent this, we set the “latest” variable to the now() function which returns the current time (in epoch format). Otherwise, it returns the time.latest token value as it stands.
| eval earliest = if(match(earliest,"[@]|-(\w|\d{1,2}\w)"), relative_time(now(), earliest), earliest) | eval latest = if(match(latest,"[@]|-(\w|\d{1,2}\w)"), relative_time(now(), latest), latest) Don’t worry – the SPL won’t get any more complicated than this. Here, we use an if() function to account for time.earliest and time.latest tokens using time specifier values, which determines relative time from now without needing to use specific timestamps. For example, breaking down “-1d@d” would mean:
= looking back in time
1d = one day
@d = snapped to the start of the day (midnight)
More comprehensive documentation on time specifiers can be found here.
Returning to the SPL, we compare the earliest and latest values using the match() function using a regular expression that will look for the time modifier format. If there’s a match, we use the relative_time() function, which takes an epoch time value (or the now() function, as used above) and offsets the time by the selected time modifier, which in this case would be our earliest and latest variables. This is returned in epoch time format. Otherwise, it returns the earliest and latest values as they stand.
| where _time >= earliest AND _time <= latest After normalizing the earliest and latest values to epoch time, we filter results where _time is between the earliest and latest values (inclusive). If done correctly, this will return the desired time range!
When we add the SPL to the dashboard, we only see data from the selected time range. However, since the time range of the search is still technically 7 days, we still see 7 days’ worth of rows.
To remove the empty rows, use this SPL (or a variation of it, depending on the panel’s format) to only filter on columns whose total values do not equal zero:
| addtotals col=f
| where Total > 0
| fields - Total Now we can see the table properly filtered for the Time Range selected.
Here is the complete search:
| savedsearch MACOS_test_report
| eval earliest="$time.earliest$"
| eval latest = if(isnull("$time.latest$") OR match("$time.latest$","now"), now(), "$time.latest$")
| eval earliest = if(match(earliest,"[@]|-(\w|\d{1,2}\w)"), relative_time(now(), earliest), earliest)
| eval latest = if(match(latest,"[@]|-(\w|\d{1,2}\w)"), relative_time(now(), latest), latest)
| where _time >= earliest AND _time <= latest
| timechart count by eventtype
| addtotals col=f
| where Total > 0
| fields - Total Happy Splunking!
Need help scaling your saved searches, reports, or dashboards? Engage TekStream’s Splunk architects.
About the Author
Eric Levy is a Splunk Core Certified Consultant who joined the TekStream team in July 2022. Eric’s background and eagerness to learn makes him excited to unlock the data possibilities Splunk has to offer its clients. Eric’s portfolio of projects makes him well adapted to time management and a diverse array of technical situations and has since expanded his horizons into Enterprise Security engagements as well as a full-time member of the IRS Splunk team. Eric resides in Arlington, Virginia and is a proud Virginia Tech graduate. In his free time, he continues to pursue his love of music.