Dashboards & Visualizations

Usage of JS in Dashboards

TheEggi98
Path Finder

I wonder whats the best practice when working with JS in Dashboards.

Im on Splunk Enterprise 8.2.1 Windows single Instance for learning.


When i use a JS for just setting tokens its enough to <host>:<port>/<language>/_bump after changes

But when i require a second JS inside my JS (separated JS for customview) i have to rename the second JS and restart splunkd service and then _bump.  _bump alone is not working neither /debug/refresh here

What is the best practice there?
How does splunk behave on different Systems? Our productive Splunk for example ist clustered on Linux servers.

Labels (2)
0 Karma

kamlesh_vaghela
SplunkTrust
SplunkTrust

@TheEggi98 

<host>:<port>/<language>/_bump is enough to reload / reflect JS or CSS changes. It's not dependent on any OS. On production, when you push your app this files will be automatically reloaded on Cluster.. No manuals required here.

If you can share your sample code of both js then may I can help whether something is breaking internally or not.

Thanks
KV
▄︻̷̿┻̿═━一   😉

If any of my reply helps you to solve the problem Or gain knowledge, an upvote would be appreciated.

0 Karma

TheEggi98
Path Finder

@kamlesh_vaghela 

Its a simple JS, that make a search, convert the Transaction Results to JSON-Objects and simply print them as HTML-table.
I used a sample JS-View that i customized a bit.

Script thats directly referred in the Dashboard:

require([
    "/static/app/fishingbot/tableview.js",
    "splunkjs/mvc/searchmanager",
    "splunkjs/mvc/simplexml/ready!"
], function(DemoView, SearchManager) {

    // Create a custom view
    var customView = new DemoView({
        id: "mycustomview",
        managerid: "mysearch",
        el: $("#mycustomview")
    }).render();

    var mysearch = new SearchManager({
        id: "mysearch",
        preview: true,
        cache: true,
        search: "index=fishingbot | fields * | transaction maxspan=0s maxpause=0s | search message=\"*->*\" | where eventcount > 1 | table message",
		earliest_time:"0", 
		latest_time:"now" 
    });

});

 

The second Script, that uses the Result, converts to JSON and prints as table:

/* demoview.js */

class EnchantedItem {
	constructor(name, enchantments) {
		this.name = name;
		this.enchantments = enchantments;
	}
};
class Enchantment {
	constructor(name, level) {
		this.name = name;
		this.level = level;
	}
};

define(function(require, exports, module){
    // Base class for custom views
    var SimpleSplunkView = require('splunkjs/mvc/simplesplunkview');

    // Require Underscore.js to work with a list of search results
    var _ = require("underscore");

    // Define the custom view class
    var DemoView = SimpleSplunkView.extend({
        className: "demoview",

        // Change the value of the "data" property
        options: {
            data: "results"
        },

        // Override this method to format your data in a specific way
        // Our view expects HTML, so reformat the results array accordingly
        formatData: function(data) {
            // Display the data object to the console
            console.log("The data object: ", data);

            // Format each row of results as an HTML list
			var items = [];
            _.each(data, function(row, index){
                let itemName = row[0][0].split(" ");
				itemName = itemName[0].replace(/"/g, "");
				itemName = itemName.replace(/_/g, " ");
				let enchants = [];
				row[0].shift();
				row[0].forEach(function(val) {
					var enchInfo = val.split(" ");
					let enchant = new Enchantment(enchInfo[1].replace(/_/g, " "),enchInfo[2]);
					enchants.push(enchant);
				});
				let enchItem = new EnchantedItem(itemName, enchants);
				items.push(enchItem);
            });
			var mydatastring = "";
			items.sort(dynamicSort("name"));
			items.forEach(function(item) {
				mydatastring = mydatastring + "<tr><td>" + item.name + "</td><td>";
				
				item.enchantments.forEach(function(enchant) {
					mydatastring = mydatastring + enchant.name + " " + enchant.level + "</br>";
				})
				
				mydatastring = mydatastring + "</td></tr>";
			});

            mydatastring = "<table class=\"table table-hover\"><thead><tr><td>Item</td><td>Enchantment<td></tr></thead><tbody>" + mydatastring + "</tbody></table>";
            return mydatastring;
        },

        // Override this method to configure your view
        createView: function() {
            return this;
        },

        // Override this method to put the Splunk data into the view
        updateView: function(viz, data) {
            // Display the reformatted data object to the console
            console.log("HTML-formatted data: ", data);
            this.$el.html(data);
        }
    });

    return DemoView;

});

 

0 Karma

kamlesh_vaghela
SplunkTrust
SplunkTrust

@TheEggi98 

Can you please try this demo view.js?

 

class EnchantedItem {
    constructor(name, enchantments) {
        this.name = name;
        this.enchantments = enchantments;
    }
};
class Enchantment {
    constructor(name, level) {
        this.name = name;
        this.level = level;
    }
};
define(function(require, exports, module) {
    // Base class for custom views
    var SimpleSplunkView = require('splunkjs/mvc/simplesplunkview');

    // Require Underscore.js to work with a list of search results
    var _ = require("underscore");

    // Define the custom view class
    var DemoView = SimpleSplunkView.extend({
        className: "demoview",

        options: {
            data: "results"
        },

        formatData: function(data) {
            // Display the data object to the console
            console.log("The data object: ", data);

            // Format each row of results as an HTML list
            var items = [];
            _.each(data, function(row, index) {
                let itemName = row[0][0].split(" ");
                itemName = itemName[0].replace(/"/g, "");
                itemName = itemName.replace(/_/g, " ");
                let enchants = [];
                console.log(row[0])
                row[0].shift();
                row[0].forEach(function(val) {
                    var enchInfo = val.split(" ");
                    let enchant = new Enchantment(enchInfo[1].replace(/_/g, " "), enchInfo[2]);
                    enchants.push(enchant);
                });
                let enchItem = new EnchantedItem(itemName, enchants);
                items.push(enchItem);
            });
            var mydatastring = "";
            items.sort(dynamicSort("name"));
            items.forEach(function(item) {
                mydatastring = mydatastring + "<tr><td>" + item.name + "</td><td>";

                item.enchantments.forEach(function(enchant) {
                    mydatastring = mydatastring + enchant.name + " " + enchant.level + "</br>";
                })

                mydatastring = mydatastring + "</td></tr>";
            });

            mydatastring = "<table class=\"table table-hover\"><thead><tr><td>Item</td><td>Enchantment<td></tr></thead><tbody>" + mydatastring + "</tbody></table>";
            return mydatastring;
        },

        // Override this method to configure your view
        createView: function() {
            return this;
        },

        // Override this method to put the Splunk data into the view
        updateView: function(viz, data) {
            // Display the reformatted data object to the console
            console.log("HTML-formatted data: ", data);
            this.$el.html(data);
        },

        // Override the render function to make the view do something
        // In this example: print to the page and to the console
        render: function() {
            console.log("Hello, world!");

            return this;
        }
    });
    return DemoView;
});

 

KV 

0 Karma

TheEggi98
Path Finder

@kamlesh_vaghela 
Does your addition of the override of the render() function changed the behaviour, except logging "Hello, world!" to the console? 

I dont notice a difference

0 Karma

kamlesh_vaghela
SplunkTrust
SplunkTrust

@TheEggi98 

Are you getting any error in console??

When I use your JS it is giving me an error. 

[Error] Refused to execute as script because "X-Content-Type-Options: nosniff" was given and its Content-Type is not a script MIME type.

So I gone through the custom view example and rebuild the code. 

So for me It's working for me with NO errors in console.

 

Screenshot 2021-10-11 at 2.32.37 PM.png

require([
    "/static/app/cmsBOFA/demoview.js",
    "splunkjs/mvc/searchmanager",
    "splunkjs/mvc/simplexml/ready!"
], function(DemoView, SearchManager) {

    // Create a custom view
    var customView = new DemoView({
        id: "mycustomview",
        managerid: "mysearch",
        el: $("#mycustomview")
    }).render();

    var mysearch = new SearchManager({
        id: "mysearch",
        preview: true,
        cache: true,
        search: '| makeresults count=5 | eval message="Test Data Test Data Test Data Test Data Test Data " | table message',
        earliest_time: "0",
        latest_time: "now"
    });
});

 

 

0 Karma

TheEggi98
Path Finder

@kamlesh_vaghela 
No, i dont get any errors from the JS.

I think the Error you get, depends on the used Browser or the settings in splunks internal webserver.
Wich Browser are you using? I use OperaGX

0 Karma

kamlesh_vaghela
SplunkTrust
SplunkTrust

@TheEggi98 

I'm using safari & Chrome.. 

🙂 

0 Karma
Get Updates on the Splunk Community!

The Splunk Success Framework: Your Guide to Successful Splunk Implementations

Splunk Lantern is a customer success center that provides advice from Splunk experts on valuable data ...

Splunk Training for All: Meet Aspiring Cybersecurity Analyst, Marc Alicea

Splunk Education believes in the value of training and certification in today’s rapidly-changing data-driven ...

Investigate Security and Threat Detection with VirusTotal and Splunk Integration

As security threats and their complexities surge, security analysts deal with increased challenges and ...