Custom Error View in Splunk Part 1: Listening for Search Events

This blog-screencast tutorial will teach you how to leverage aspects of the Splunk JavaScript Framework to display error messages directly within your dashboard panels.



If you've ever had a dashboard in Splunk that includes searches with errors, you'll notice a little icon popup that alerts you of an error message. From a user standpoint, this little popup may not make it completely obvious that an error is being outputted. This can be less than ideal for the user, especially when running searches against an API, as the user should have immediate clarity as to why the search failed. A better way to handle these error alerts, to benefit the user interface perspective, would be to clearly display the error message directly within the Splunk dashboard panel.

This blog-screencast tutorial will teach you how to leverage aspects of the Splunk JavaScript Framework to display error messages directly within your dashboard panels. You can either watch the screencast below, or continue reading. The second part on adding style to our error is here.

PART 1: LISTENING FOR SEARCH EVENTS

I will be showing you an example of what the end result will be when an error message is fully displayed - allowing the user to gain immediate, fully visible feedback, not just an alert for the message. I will begin by showing you how to write a search that will generate an error - allowing us to then modify the dashboard panel to use the search’s on(“progress:done”) event to check and see if an error was returned and, if so, display it.

Building a Simple Dashboard Let’s start by creating an invalid Splunk search that guarantees an error will be thrown

| input nothing.csv

When running the search, we will get back an error:

command="input", Invalid argument ("nothing.csv"). Expected "add" or "remove" argument."

Now that we have an error coming back, click on ‘Save As' < Dashboard Panel in the top right:

Name the Dashboard whatever you like. I named mine ‘Error Reporting:'

New Dashboard Modal
Error reporting

Then click on 'View Dashboard' and click on 'Edit' < Edit Source

You should see the following:

<dashboard>
    <label>Error Reporting</label>
    <row>
        <panel>
            <table>
                <search>
                    <query>| input nothing.csv</query>
                    <earliest>0</earliest>
                    <latest></latest>
                </search>
                <option name="wrap">true</option>
                <option name="rowNumbers">false</option>
                <option name="dataOverlayMode">none</option>
                <option name="drilldown">cell</option>
                <option name="count">10</option>
            </table>
        </panel>
    </row>
</dashboard>

Make the following changes highlighted below:

<dashboard script="app.js" stylesheet=”app.css”> //Add a reference to our soon to be created JS file and CSS files
    <label>Error Reporting</label>
    <row>
        <panel>
            <table id="errorTestTable"> //Add id attribute for the table
                <search id="errorTestSearch"> //Add id attribute for the search
                    <query>| input nothing.csv</query>
                    <earliest>0</earliest>
                    <latest></latest>
                </search>
… Removed For Brevity …

Click 'Save.'

Creating the app.js file If you have access to your Splunk install directories, depending on where you created your dashboard (for example in the Search and Reporting app), you would go to:

$SPLUNK_HOME/opt/splunk/etc/apps/search/

Then inside of that directory, go to appserver/static. Your full directory path would be:

$SPLUNK_HOME/opt/splunk/etc/apps/search/appserver/static

If you added this to some other app, or a newly created app, the directory ‘appserver’ may not exist and you’ll have to create it.

Splunk loads it’s dependencies using the require.js library. If you’ve never used it before it is a more efficient way to load file dependencies.

app.js:

require([
    'underscore',
    'backbone',
    'splunkjs/mvc',
    'splunkjs/mvc/simplexml/ready!'
], function(_, Backbone, mvc) {

});

Splunk’s JS Framework is based on the backbone.js library. It has one dependency, the underscore.js library, which is why we load that first. We are also going to load in Splunk’s MVC components. We then pass in our dependencies as function parameters.

Creating Instances of Our Search and Table Inside of your require function, we will need to first create variables that will reference our search and the visualization of that search, in this case a table:

var search = mvc.Components.get('errorTestSearch');
var table = mvc.Components.get('errorTestTable');

We’re using the Splunk mvc components to pull reference to these items based off the id attributes we defined in our Simple XML earlier.

Listening for Events Searches in Splunk have events tied to them such as progress, end, and failed. If you want more detailed information on these events, check out the Splunk documentation on progress events.

In our case, we are going to listen for the ‘search:done’ event, so we can check whether or not there was an error in the response. The ‘on’ event has a properties parameter from which we can extract information about the search. So, let's start by logging that out:

search.on('search:done', function(properties) {
    console.log(‘Properties: ’, properties)
});

If you inspect the console in your browser you’ll see it comes back as an object with a lot of different properties:

Console View
Console view

We’re specifically interested in what is in ‘content.' Expand that out and you should get a long list of items. Look for ‘messages,' expand that, and you should see the following:

Console Error Response
Console error response

That error message currently gets injected into the bottom right of the dashboard panel:

First, we are going to define our responseMsg variable inside of our on event, like so:

var responseMsg = properties.content.messages[0];

Then we want to ensure the response we get back is not undefined, so we don’t get an error:

if(responseMsg != undefined) {

}

Inside of our if statement we are going to create a variable for the type, which in this case is ERROR and the text, which is the actual error message:

if(responseMsg != undefined) {
    var r_type = responseMsg.type;
    var r_text = responseMsg.text;
}

Then we want to check and see if the response type is of ERROR:

if(r_type == 'ERROR') {

}

Inside of our if statement we are checking to make sure it's of type ERROR. If it is of type ERROR, then we want to append in the error to the table element. So, we are essentially saying "in the table element find the dom element with a class of panel-body and append a div with a class of error-response to it."

table.$el.find('.panel-body').append('<div class="error-response">'+r_text+'</div>');

In the end, your code should look like this:

search.on('search:done', function(properties) {
    var responseMsg = properties.content.messages[0];
    if(responseMsg != undefined) {
        var r_type = responseMsg.type;
        var r_text = responseMsg.text;

        if(r_type == 'ERROR') {
            table.$el.find('.panel-body').append('<div class="error-response">'+r_text+'</div>');
        }
    }
});

One last thing we will want to take care of is removing the error. As is, if we run the search and it errors out and then rerun the search successfully, the error will still be present because we haven't removed it from the UI - this could be very confusing for the user.

We do this by adding:

table.$el.find(".error-response").remove();

This will be added right under where we defined our responseMsg variable and right before our first if statement. Now, if it's successful and no error is thrown, the error will be removed if it exists. Also, feel free to remove your console.log() that currently exists in the on event.

In the end your entire app.js will look like the following:

require([
    'underscore',
    'backbone',
    'splunkjs/mvc',
    '../app/dev_app/components/ErrorView',
    'splunkjs/mvc/simplexml/ready!'
], function(_, Backbone, mvc, ErrorView) {

    var search = mvc.Components.get('errorTestSearch');
    var table = mvc.Components.get('errorTestTable');

    search.on('search:done', function(properties) {
        var responseMsg = properties.content.messages[0];
        table.$el.find(".error-response").remove();
        if(responseMsg != undefined) {
            var r_type = responseMsg.type;
            var r_text = responseMsg.text;

            if(r_type == 'ERROR') {
                table.$el.find('.panel-body').append('<div class="error-response">'+r_text+'</div>');
            }
         }
    });
});

Before we restart, let's go ahead and create our CSS file as well.

PART 2: STYLING OUR ERROR

Right now if we were to restart Splunk to view our custom error it would look something like this:

Unstylized Error
Right now if we were to restart Splunk to view our custom error it would look something like this:

This doesn’t look very good. So, let’s go ahead and add some style to our app.css file

.error-response {
    background-color: #c64e4e;
    color: #fff;
    padding: 10px;
    display: inline-block;
}

Go ahead and save your app.css file and then restart Splunk.

Once you restart Splunk your custom error should look like this:

Stylized Error
Stylized error

Congrats! You now have a customized error component in Splunk.




Close off Canvas Menu