There are a couple of features of SimpleXML / Classic dashboards that can be used to enhance the user experience. This article is about using tokens and handlers to control how a dashboard behaves. Modifying the "Waiting for data ..." message Starting with a simple count of events by sourcetype in the _internal index, depending on your system resources, anything above a small time period will usually produce a temporary "Waiting for data ..." message in place of the chart. <form version="1.1" theme="light">
<label>Internal counts</label>
<description>Dashboard to demonstrate use of tokens and handlers</description>
<fieldset submitButton="false">
<input type="time" token="period">
<label>Please select time period</label>
<default>
<earliest>-24h@h</earliest>
<latest>now</latest>
</default>
</input>
</fieldset>
<row>
<panel>
<title>Sourcetype counts</title>
<chart>
<search>
<query>index=_internal
| eval label="Sourcetype"
| chart count by label sourcetype useother=f limit=0</query>
<earliest>$period.earliest$</earliest>
<latest>$period.latest$</latest>
<sampleRatio>1</sampleRatio>
</search>
<option name="charting.axisTitleX.visibility">collapsed</option>
<option name="charting.axisTitleY.text">Count</option>
<option name="charting.axisTitleY.visibility">visible</option>
<option name="charting.axisY.scale">log</option>
<option name="charting.chart">column</option>
<option name="charting.drilldown">none</option>
<option name="refresh.display">progressbar</option>
</chart>
</panel>
</row>
</form> When a chart is displayed, particularly when the underlying search is not particularly fast, we would like to replace this with a tailored message, for example This is just a simple HTML panel which can be tailored to your needs. Now we need to control when the chart and the HTML panel are shown. The key to this is a token set in the done handler of the chart's search. To ensure that the token is undefined while the search is being executed, we can unset it in the change handler of the time selector. Now we can make it so that the chart depends on the token and the HTML rejects the same token. Since the token can either be present or not, this is enough to determine whether to display the chart or the HTML; it doesn't matter what the contents of the token are, merely that it is either set or unset. <form version="1.1" theme="light">
<label>Internal counts</label>
<description>Dashboard to demonstrate use of tokens and handlers</description>
<fieldset submitButton="false">
<input type="time" token="period">
<label>Please select time period</label>
<default>
<earliest>-24h@h</earliest>
<latest>now</latest>
</default>
<change>
<unset token="data"/>
</change>
</input>
</fieldset>
<row>
<panel>
<title>Sourcetype counts</title>
<chart depends="$data$">
<search>
<query>index=_internal
| eval label="Sourcetype"
| chart count by label sourcetype useother=f limit=0</query>
<earliest>$period.earliest$</earliest>
<latest>$period.latest$</latest>
<sampleRatio>1</sampleRatio>
<done>
<set token="data"/>
</done>
</search>
<option name="charting.axisTitleX.visibility">collapsed</option>
<option name="charting.axisTitleY.text">Count</option>
<option name="charting.axisTitleY.visibility">visible</option>
<option name="charting.axisY.scale">log</option>
<option name="charting.chart">column</option>
<option name="charting.drilldown">none</option>
<option name="refresh.display">progressbar</option>
</chart>
<html rejects="$data$">
<h1><center>Please wait while your search is being executed</center></h1>
</html>
</panel>
</row>
</form> Modifying values use by Inline CSS Tokens can be used elsewhere in dashboards; for example, using Cascading Style Sheets (CSS) to change how elements are displayed. In this example, the fill colour of the text element is modified by CSS and a token is used to change the value used by the CSS; this value is defined (randomly) by the search and passed to the CSS again using the done handler. <row>
<panel>
<html depends="$alwaysHide$">
<style>
#single text {
fill: $single_text_colour$ !important;
}
</style>
</html>
<single id="single">
<search>
<done>
<set token="single_text_colour">$result._colour$</set>
</done>
<query>| makeresults count=20
| fields - _time
``` This search creates events for a random set of hosts with random Severity values (skewed towards "LOW")
A count of "CRITICAL" events is taken for each host to determine whether to show the host in red or green
Note that in this instance, only the host with the most events is shown in the Single viz ```
| eval Severity=mvindex(split("LOW,CRITICAL",","),random()%5%4%3%2)
| eval host="host".random()%3
| stats count count(eval(Severity=="CRITICAL")) as _critical by host
| sort 0 - count
| eval _colour=if(_critical>0,"red","green")
| eval count=host
| table host count _colour</query>
<earliest>0</earliest>
<latest></latest>
</search>
<option name="drilldown">none</option>
<option name="refresh.display">progressbar</option>
</single>
</panel>
</row> The panel can be refreshed to produce different results. Controlling search execution order Tokens can also be used to control the order in which searches are executed. In this example, Table C is dependent on a token which is set in the done handler of Table B, which in turn is dependent on a token which is set in the done handler of Table A <row>
<panel>
<table>
<title>Table A</title>
<search>
<query>index=_internal
| eval Now=now()
| eval Time=time()
| stats min(Now) as Now max(Time) as Time
| fieldformat Now=strftime(Now,"%F %T")
| fieldformat Time=strftime(Time,"%F %T")</query>
<earliest>-30d@d</earliest>
<latest>now</latest>
<progress>
<unset token="time_a"/>
<unset token="time_b"/>
</progress>
<done>
<set token="time_a">$result.Now$</set>
</done>
</search>
<option name="drilldown">none</option>
<option name="refresh.display">progressbar</option>
</table>
</panel>
<panel>
<table>
<title>Table B</title>
<search>
<query>index=_internal
| eval A_Time="$time_a$"
| eval Now=now()
| eval Time=time()
| stats min(Now) as Now max(Time) as Time
| fieldformat Now=strftime(Now,"%F %T")
| fieldformat Time=strftime(Time,"%F %T")</query>
<earliest>-30d@d</earliest>
<latest>now</latest>
<progress>
<unset token="time_b"/>
</progress>
<done>
<set token="time_b">$result.Now$</set>
</done>
</search>
<option name="drilldown">none</option>
<option name="refresh.display">progressbar</option>
</table>
</panel>
<panel>
<table>
<title>Table C</title>
<search>
<query>index=_internal
| eval B_Time="$time_b$"
| eval Now=now()
| eval Time=time()
| stats min(Now) as Now max(Time) as Time
| fieldformat Now=strftime(Now,"%F %T")
| fieldformat Time=strftime(Time,"%F %T")</query>
<earliest>-30d@d</earliest>
<latest>now</latest>
</search>
<option name="drilldown">none</option>
<option name="refresh.display">progressbar</option>
</table>
</panel>
</row> For example, Table B refreshes when Table A search completes, and Table C refreshes when Table B search completes. Refreshing Table B does not affect Table A, but Table C will also refresh when Table B's search completes. You can see that the Time field in Table B is the same as the Now field in Table C. The now() function effectively returns the time when the search query is parsed (at the beginning) and the time() function effectively returns the time when the eval statement is executed. Further information For further information about other dashboarding techniques, please see my Community Blog series on extending the Buttercup games tutorial Search "dashboard" "In Community Blog" "by ITWhisperer"
... View more