Not Enough Space? Rotate Through Your Dashboard Panels Automatically

By Marvin Martinez, Team Lead, Security Operations

Splunk dashboards allow for great flexibility and can provide many ways to visualize your data. Sometimes, however, you may need to ensure you can fit everything on one non-scrollable screen. Perhaps you’re in a SOC with a main screen and need some different panes to display at specific intervals? What if you need to cycle through a set of data between different time ranges like the last 24 hrs, 7 days, and 30 days? In these situations, it would be very helpful to be able to have a dashboard that automatically rotates the desired panels on specific time intervals, not unlike a fast food menu screen or those digital billboards you frequently see on the interstate!

In the example we’ll use for this article, I’ll demonstrate how to configure a dashboard to display an Attack Map in two separate ways. The first view will contain a full screen attack map with all of the different sources in one single map to provide a comprehensive view. The second view is a broken out set of panels that shows each individual source/group in its own panel with a dedicated attack map for added detail. The Missile Map app that contains this attack map visualization used below can be found on Splunkbase.

View 1

View 2

These two views will cycle automatically based on a specified time interval defined within a global search in your dashboard. There are a few tokens to ensure you set up correctly but, once set up as needed, your dashboard will cycle through the two configured views (sets of panels) on its own for use in any monitor on a wall or other constantly monitored screen.

The snippet of dashboard XML code responsible for the setup is below, with a full detailed explanation below:

   <search> 

    <query>| makeresults count=1 

| eval test = IF("global" = "global","individual","global") 

    </query> 

    <done> 

      <eval token="panelView">IF($panelView$ = 

&quot;global&quot;,&quot;individual&quot;,&quot;global&quot;)</eval> 

      <set token="form.panelView">$panelView$</set> 

      <eval token="refreshCount">$refreshCount$ + 1</eval> 

    </done> 

    <refresh>15s</refresh> 

    <refreshType>interval</refreshType> 

  </search> 

  <fieldset submitButton="false"> 

    <input type="text" token="panelView" depends="$tok_hide$"> 

      <label>field1</label> 

      <initialValue>global</initialValue> 

    <change> 

      <condition value="global"> 

          <set token="globalView">true</set> 

          <unset token="individualView"></unset> 

      </condition> 

      <condition> 

        <unset token="globalView"></unset> 

        <set token="individualView">true</set> 

      </condition> 

    </change> 

    </input> 

  </fieldset> 

Components

The components of this setup are as follows:

– Search to detect what view is currently being displayed and what the next one will be, as well as to define what the refresh interval will be

– A hidden input to allow for catching the resulting value and setting the appropriate tokens for view hiding/showing.

– Setup your rows (or panels) with the appropriate depends settings to leverage the appropriate tokens to ensure they are shown only when desired.

First, the initial search. Set this search up at the top of your dashboard.

<search> 

    <query>| makeresults count=1 

| eval test = IF("global" = "global","individual","global") 

    </query> 

    <done> 

      <eval token="panelView">IF($panelView$ = &quot;global&quot;,&quot;individual&quot;,&quot;global&quot;)</eval> 

      <set token="form.panelView">$panelView$</set> 

      <eval token="refreshCount">$refreshCount$ + 1</eval> 

    </done> 

    <refresh>15s</refresh> 

    <refreshType>interval</refreshType> 

  </search> 

The query is just a generic makeresults command to return some output value but it’s being leveraged to set the token value of the hidden input. This is to ensure that you don’t end up with an infinite loop by trying to set the token of an input within itself. Use the done event handler to set the token of the hidden input (“panelView” in my example) (details below) within it. Use an eval to set the token appropriately based on the value of the “panelView” input currently (i.e. if “global” currently, set it to “individual” and vice versa). The refresh property is what defines how often the panels/views will rotate between displaying. You can statically set it here or even define it using a token from an input, if desired, to make that refresh interval easily customizable.

As far as the input is concerned, create a text box input and set the “depends” property on it to a token you don’t intend on setting so that it is always hidden (i.e. “$tok_hide$”). Add a change condition so you can set, and unset, appropriate tokens based on the value of the input. This is where the magic happens! When the value of the token is “global”, in this case, it sets the globalView token and unsets the individualView token. This will hide the individual panels and display the global one. The default condition after that is executed when the value is anything other than “global”, which is sufficient in our scenario but you may need additional explicit conditions if you have more than two views in your dashboard. Note how the set/unset is just reversed from the first one to ensure only one is set at any given time.

<fieldset submitButton="false"> 

    <input type="text" token="panelView" depends="$tok_hide$"> 

      <label>field1</label> 

      <initialValue>global</initialValue> 

    <change> 

      <condition value="global"> 

          <set token="globalView">true</set> 

          <unset token="individualView"></unset> 

      </condition> 

      <condition> 

        <unset token="globalView"></unset> 

        <set token="individualView">true</set> 

      </condition> 

    </change> 

    </input> 

  </fieldset> 

 

Finally, it’s time to configure your rows/panels with the appropriate depends property to hide/show panels when necessary, as shown below. Set the value of each to be the token that will show the panel/row.

  <row depends="$globalView$"> 

Save your dashboard and enjoy the automatic cycling between your panels with no engagement from a human!