Dashboards & Visualizations

EventsViewer Drilldowns from 2 charts update the same panel?

Path Finder

Is it possible to have drilddowns from 2 different charts in a dashboard update the same panel?

I have a dashboard with 2 charts. Each chart drills down to an EventsViewer module. What i'd like is that, regardless of whether the user clicks on the first or second chart, the events from the drilldown get displayed in the same, 3rd panel. Furthermore, if the user has drilled down on one chart, then drills down on the other, the events from the 2nd will overwrite those from the 1st. In other words, the 3rd panel will only show the results from the latest drilldown.

If I set both layoutPanels in the drilldown search to the same panel, the results from both do indeed go to that panel. But they don't overwrite each other. So if the user drills downs on both charts the panel displays the results from both results at the same time. I'm looking for the panel to show only the results from the latest drilldown.

Explorer

Hi,

I'm trying to do the same thing, but hitting a weird problem. I've set up two SimpleResultsTables, both containing an identical 'sendPushes' CustomBehavior module (taken exactly from Sideview's example) and a 'receivePushes' CustomBehavior further down the page (but not downstream) of the two tables. With this setup, nothing happens when I click on an entry in either of the tables. However, if I remove the sendPushes CustomBehavior from one of the tables then when I click on a row in the other table (which still has the sendPushes CustomBehavior), the receivePushes CustomBehavior is called correctly. It doesn't matter which of the two SimpleResultsTable has the CustomBehavior module, just so long as only one does.

Any ideas anyone?

Thanks,
Andy

0 Karma

Explorer

Great tip, thanks.

0 Karma

SplunkTrust
SplunkTrust

It gets a lot of people -- that restarting splunk doesn't clear files cached in people's browsers. There is however a strange little thing called the bump endpoint. If you go to the Sideview Utils FreshMaker (/en-US/app/sideview_utils/refresh_entities) and scroll down, you'll see a link and some explanatory text there. In short it is good to hit the bump endpoint after changing static files on deployed Splunk instances - it effectively invalidates the cache of all users who might have older versions cached.

0 Karma

Explorer

Oh of course - yes, clearing the browser cache fixed it. Thanks again for your help, it all works great now.

0 Karma

SplunkTrust
SplunkTrust

Interesting. Did you clear your browser cache though? Also are there any other JS errors in the error console?

0 Karma

Explorer

That makes sense, but it didn't work for me unfortunately (I restarted Splunk after making the change).

0 Karma

SplunkTrust
SplunkTrust

In my answer you'll see a little comment saying "this part is weird", after which is a little 5 line for-loop. Delete that and I think it'll work for you. Since that ode assumes that there are FlashChart modules upstream from the sendPushes customBehaviors, and since in your example there are not, I think it's throwing a JS error here as soon as there are 2 or more. Remove that for loop and I think you're good.

0 Karma

Explorer

Hello to you both!I'm trying to do the excact same thing as anssntaco with the only difference my drilldown is a simple table.I followed the steps but nothing happens.What am i doing wrong!Thanks in advance!

<module name="HiddenSearch" layoutPanel="panel_row3_col1" group="Service" autoRun="True">
<param name="search">
networkindex` type=ips | table dest_app | chart count(dest_app) over dest_app

Service

<module name="ViewstateAdapter">
<module name="HiddenFieldPicker">
    <param name="strictMode">True</param>
    <module name="JobProgressIndicator">
    <module name="EnablePreview">
        <param name="enable">True</param>
        <param name="display">False</param>
        <module name="HiddenChartFormatter">
            <param name="charting.chart">pie</param>
            <module name="FlashChart">
                <param name="width">100%</param>
                    <param name="enableResize">true</param>

                    <module name="HiddenSearch">
      <param name="search">`networkindex` type=ips | fields _time dest_app src_ip dest_ip src_port dest_port | fields - _raw </param>
      <!-- this module will grab the value we clicked on and put it in as a searchterm,   series="someSourcetype".   -->
      <module name="ConvertToIntention" layoutPanel="panel_row4_col1">
        <param name="intention">
          <param name="name">addterm</param>
          <param name="arg">
            <param name="dest_app">$click.value$</param>
          </param>
          <!-- tells the addterm intention to put our term in the first search clause no matter what. -->
          <param name="flags"><list>indexed</list></param>
        </param>

        <!-- finally, we render the search in another FlashChart, and we throw in a JobProgressIndicator for good measure. -->
        <module name="JobProgressIndicator"></module>
           <module name="Pager">
                   <param name="count">10</param>
             <module name="SimpleResultsTable">
                    <param name="drilldown">row</param>

        <module name="CustomBehavior">
              <param name="customBehavior">sendPushesToDrilldownTable</param>
            </module>

        </module>
      </module>
    </module>
</module>
    </module>
  </module>
</module>

            </module>
        </module>
    </module>
    </module>

<module name="Tabs" layoutPanel="panel_row3_col2" autoRun="True">
    <param name="name">selectedTab</param>
    <param name="staticTabs">
      <list>
    <param name="label">Attacks</param>
    <param name="value">attack_name</param>
      </list>
      <list>
    <param name="label">Service</param>
    <param name="value">dest_app</param>
      </list>
      <list>
    <param name="label">Source IP</param>
    <param name="value">src_ip</param>
      </list>
      <list>
    <param name="label">Destination IP</param>
    <param name="value">dest_ip</param>
      </list>
      <list>
    <param name="label">User</param>
    <param name="value">user</param>
      </list>

    </param>


    <module name="Search">    
    <param name="search">`networkindex` type=ips | stats  sparkline count by $selectedTab$ | sort -count</param>  
    <module name="Pager">
    <param name="count">10</param>
      <module name="SimpleResultsTable">
        <param name="drilldown">row</param>
      </module>
    </module>
     </module>

    <module name="CustomBehavior" layoutPanel="panel_row5_col1">
      <param name="customBehavior">receivePushes</param>
    </module>

</module>`
0 Karma

SplunkTrust
SplunkTrust

Well, take another look. You would set up two drilldown tables both with the 'sendPushesToDrilldownTable' customBehavior, and then you would have the actual downstream table sort of dangling in space with only the "receivePushes" customBehavior upstream from it. Here it looks like you've put sendPushes on the one upstream drilldown table, and the receivePushes on the other upstream drilldown table. Also I assume you are, but make sure that the JS defining the customBehaviors is in application.js.

0 Karma

SplunkTrust
SplunkTrust

There is a way to do this, but not without writing custom code into your app.

The cleanest way to do this, is to use Sideview Utils and set up some CustomBehavior modules at the key points. You still have to write custom code but it makes it a lot easier and cleaner to wire up.

Once you've downloaded Sideview Utils http://sideviewapps.com/apps/sideview-utils

The first part is giving your two charts each a CustomBehavior module that looks like this:

<module name="FlashChart">
  [[any params you have on your FlashChart]]

  <module name="CustomBehavior">
    <param name="customBehavior">sendPushes</param>
  </module>

</module>

The second part is putting your EventsViewer lower down in the view such that it is NOT nested in either one of those two FlashCharts. Instead put this third CustomBehavior module wrapping your EventsViewer (or the Sideview Events module), and that it is wrapping any other modules you want to be driven.

<module name="CustomBehavior" layoutPanel="panel_row2_col1">
  <param name="customBehavior">receivePushes</param>

  <module name="Search">
    <!-- make sure to use the $customSearchTerms$ key somewhere or it's all for nothing -->
    <param name="search">$customSearchTerms$ [[and the rest of your search goes here]]</param>

    <!-- if you want to use $customSearchValue$ or $selectedField$ also, for instance in an HTML module, go for it -->
    [... your EventsViewer / Events module and other modules go here ]
  </module>
</module>

The third part (and you might not grasp the reason for this one as easily as with the other ones), is to put this CustomBehavior right up at the top, right after your SubmitButton module or Button module if you're using one, and after the last form field up top if you're not.

<module name="CustomBehavior">
  <param name="customBehavior">clearPushes</param>
</module>

Last but not least, the fourth part is actually defining these three customBehaviors. I've done this same thing and here's the JS that I have used.

if (typeof(Sideview)!="undefined") {

    var driven  = null;
    var drivers = {};

    Sideview.utils.declareCustomBehavior("sendPushes", function(mod) {
        drivers[mod.moduleId] = mod;
        mod.pushContextToChildren = function() {
            // this part is weird - we're just clearing selection state on the other FlashChart(s)
            for (moduleId in drivers) {
                if (moduleId != this.moduleId) {
                    drivers[moduleId].parent.update();
                }
            }

            var context = this.getContext();

            driven.searchTerms = context.get("click.searchTerms");
            driven.searchValue   = context.get("click.value");
            driven.selectedField = context.get("selectedField");

            driven.pushContextToChildren();
        }
    });
    Sideview.utils.declareCustomBehavior("receivePushes", function(mod) {
        driven = mod;
        mod.getModifiedContext = function() {
            var context = this.getContext();
            context.set("customSearchTerms", this.searchTerms);
            context.set("customSearchValue", this.searchValue);
            context.set("selectedField", this.selectedField);
            return context;
        }
    });
    Sideview.utils.declareCustomBehavior("clearPushes", function(mod) {
        mod.onContextChange = function() {
            driven.searchTerms = null;
        }
    });
 }

Basically the first two customBehaviors custom-wire the view so that both of your Charts will push data to that one EventsViewer module down below, even though it's not nested within either one of them.

UPDATE: In my earlier post I forgot to show that you have to use the $customSearchTerms$ key in your search just above the EventsViewer, or else your hard-won selected searchterms wont be applied.

SplunkTrust
SplunkTrust

What you would then do, is put a ValueSetter module in one branch but not the other (or for more complicated cases put one or more ValueSetters in each branch) and then have that ValueSetter put out your subsearch syntax or whatever as another key, ie $mySubsearch$. If that subsearch has to incorporate further $foo$ tokens you will do it up there. Then the wiring as above will push that complete key down to the EventsViewer along with the others so you just have to reference it down in that Search module's search as $mySubsearch$.

0 Karma

Path Finder

This is an outstanding answer. Thank you!!

In my dashboard, there are (subtle) differences in the searches that feed into EventsViewer. Rather, the search from one of the charts includes a subsearch that's not in the other.

It looks like, for this to work, the search in the receivePushes customBehavior module needs to be the same, regardless of whether it came from one chart or the other. Or is that not the case? I'm new to this level of customization, so apologies if the answer is obvious.

Thanks again!

0 Karma