Splunk® Enterprise

Module System User Manual

Download manual as PDF

Download topic as PDF

Create a custom module

Important notice: As part of Advanced XML deprecation, the Module System is officially deprecated beginning with Splunk Enterprise 6.3. For more information, see Advanced XML Deprecation.
To add your module code
To define your custom module
To implement the server-side search request handler
To implement the client-side results renderer
To integrate the module into the app view

SplunkIcon.png Example 4


Typically, applications are constructed from prebuilt modules distributed with Splunk. You can list modules available in your Splunk distribution by logging in to Splunkweb and entering http://<host>:<port>/en-US/modules. For example, http://localhost:8000/en-US/modules. This also provides basic documentation about how to use a module.

For your application domain, you may need to create a custom module to present your data in a more meaningful way. Modules are at the core of Splunk apps, where the UI view is constructed from a hierarchy of modules. Data returned from your search is passed between modules and handled, or rendered, according to module functionality. The following figure introduces you to the module components:

ModuleStruct.png

Modules are nested and search results are typically passed from parent to child modules for processing. The figure depicts a HiddenModule, because it has no UI, which initiates the search request in our recipes. Using the AJAX pattern, modules pend on search results generated by the module controller on the host. The module client templating mechanism renders the results.

Details

This recipe demonstrates the basic steps needed to create a module:

  1. Create the example source files in the correct directory.
  2. Define the module so it is recognized by the Module System.
  3. On the server, handle the search request and return the requested data.
  4. On the client, render the response data.
  5. Integrate the module into the app view.

These steps are common to all modules, and demonstrated in this recipe using the CustomResultsTable module.

The CustomResultsTable module extracts CPU utilization data from the indexed metrics.log file using the following search string:

index=_internal source=*metrics.log group=pipeline |
                             stats sum(cpu_seconds) as totalCPU by name


and displays results in tabular format:

Ex4 01.png

 

Creating custom modules is the foundation of most of the recipes in this cookbook.

To add your module code

Create the $SPLUNK_HOME/etc/apps/Dev_tutorial/appserver/modules/CustomResultsTable directory and add the following files:

  • CustomResultsTable.conf
  • CustomResultsTable.js
  • CustomResultsTable.py

You can copy and paste the file contents from the sample code. Experiment with modifying the code to better understand how Module System works.

Note: Remember that modules minimally require a .conf and a .js file.

To define your custom module

  1. In the CustomResultsTable.conf file, give the module a class name and specify the base class from which it inherits.

    [module] className = Splunk.Module.CustomResultsTable superClass = Splunk.Module.DispatchingModule description = This is my first custom module.

  2. In the same file, define module parameters to customize your view. For simplicity, this module does not have parameters so none are specified.

    [param:myParam]required = False default = none

The configuration file hooks your module into the Module System. The Splunk.Module.DispatchingModule abstract base class, itself a subclass of the root Splunk.Module abstract class, handles the attachment of jobProgress and jobDone events, such that the onJobProgress() and onJobDone() methods are only called when the job context actually changes.

Note: The description and parameter fields are used to auto-document your module, which you can view when you enter http://<host>:<port>/en-US/modules in Splunkweb.

To implement the server-side search request handler

Server-side code is implemented in the CustomResultsTable.py file.

Note: The root filename is the same as the unique className defined in CustomResultsTable.conf.

  1. Import the libraries needed by most modules.

    import controllers.module as module import splunk import splunk.search import splunk.util import splunk.entity import lib.util as util import lib.i18n as i18n import logging

    Tip  : It is the recommended practice to have each import statement on a separate line.
    (See: PEP 8 -- Style Guide for Python Code )

  2. Create a logger for your module to log error and debug messages.

    logger = logging.getLogger('splunk.module.CustomResultsTable')

    Messages are logged by calling logger. logLevel ( logMessage ), which appends logMessage to the $SPLUNK_HOME/var/log/splunk/web_service.log file.

    Loggers are arranged in a namespace hierarchy so create your logger passing the module namespace, splunk.module.CustomResultsTable as a parameter.

  3. Define the module class, specifying the base class as a parameter.

    class CustomResultsTable(module.ModuleHandler)

    The ModuleHandler base class defines Module System server-side extension points for handling module requests. Your module hooks into Module System by implementing the methods for your particular application.

  4. The only method that needs to be implemented for this simple module is the generateResults() method. Define the method and parameters used.

    def generateResults(self, host_app, client_app, sid, count=1000,

                       offset=0, entity_name='results'):
    

    Validate the parameters and set local variables.

    count = max(int(count), 0) offset = max(int(offset), 0) if not sid:

       raise Exception('CustomResultsTable.generateResults - sid not passed!')
    

    try:

       job = splunk.search.getJob(sid)
    

    except splunk.ResourceNotFound, e:

       logger.error('CustomResultsTable could not find job %s.' % sid)
    

    return _('<p class="resultStatusMessage">Could not retrieve search data.</p>')

    If the job ID parameter, sid, is not associated with your search request job, valid data are not available. In more advanced examples, you will learn how to work with job states.

    Tip: Use standard Python logging to log errors.

    The rest of this method builds the HTML displayed by this module, inserting the CPU Utilization search results in a table.

    output = [] output.append('<div class="CustomResultsTableWrapper">') output.append('<table class="CustomResultsTable splTable">') fieldNames = [x for x in getattr(job, entity_name).fieldOrder if (not x.startswith('_'))] dataset = getattr(job, entity_name)[offset: offset+count] for i, result in enumerate(dataset):

       output.append('<tr>')
       for field in fieldNames:
           output.append('<td')
           fieldValues = result.get(cgi.escape(field), None)
           if fieldValues:
               output.append('>%s</td>' % fieldValues)
           else:
               output.append('></td>')
               output.append('</tr>')
               output.append('</table></div>')
               output = .join(output)
    

    return output

    The fieldNames variable contains the names of the fields specified in the search request (the pipeline indexer stage name and cpu_seconds utilization), which are used to index the field value.

    The method returns an HTML-formatted data table populated with CPU utilization data.

    Tip: To avoid security vulnerabilities, make sure to use HTML escaping of your data, either on the client or server, as applicable. Escaping is conveniently specified on the server using the Mako template but, because this example does not have a template, manually escape the HTML by calling cgi.escape(<field>).

To implement the client-side results renderer

Client-side code is implemented in the CustomResultsTable.js file.

Note: The root filename is the same as the unique className defined in CustomResultsTable.conf.

  1. Instantiate an instance of the CustomResultsTable class as a subclass of Splunk.Module.DispatchingModule, using the jQuery klass construct.

    Splunk.Module.CustomResultsTable = $.klass(Splunk.Module.DispatchingModule, {...}

    The DispatchingModule base class, subclassing Splunk.Module, defines Module System extension points for implementing client-side response data handling and rendering particular to your application.

    Tip: Splunk provides a number of modules with predefined functionality. Choose the module from which to inherit most appropriate for your module functionality. Splunk modules are located at $SPLUNK_HOME/share/splunk/search_mrsparkle/modules. All modules have Splunk.Module as the base class.

  2. Implement the constructor, which is called automatically when the class is instantiated, passing the containing DOM element as a parameter.

    initialize: function($super, container) {

       $super(container);
       this.resultsContainer = this.container;
    

    },

    All modules must have an initialize() method.

    Call $super(), first, to guarantee that the base class constructor is called before the module initialize() method executes. Save the container where results are rendered with this object.

  3. Override the onJobDone() event handler.

    onJobDone: function(event) {

       this.getResults();
    

    },

    This method is called when the search command is completed for the job associated with this instance. The only action needed for this simple example is to request the search results. For more complex applications, you might consider using other job progress event handlers.

  4. Override the getResultParams() method, which is called when results are available following the getResults() call.

    getResultParams: function($super) {

       var params = $super();
       var context = this.getContext();
       var search = context.get("search");
       var sid = search.job.getSearchId();
       if (!sid) this.logger.error(this.moduleType, "Assertion Failed.");
           params.sid = sid;
       return params;
    

    },

  5. Override the renderResults() method to render the results in the container for this module.

    renderResults: function($super, htmlFragment) {

       if (!htmlFragment) {
           this.resultsContainer.html('No content available.');
           return;
       }
       this.resultsContainer.html(htmlFragment);
    

    }

    For this example, the HTML fragment constructed on the server can be rendered directly by calling resultsContainer.html(), passing the results as a parameter.

The following simplified sequence diagram shows the basic client-server interaction:

ModuleSequence.png

A search job is dispatched by the module with DispatchingModule binding job progress events to the module. The getResults() and response sequence is implemented as an AJAX pattern. Other apps may interact differently, responding to different job progress events or doing something other than render the data.

To integrate the module into the app view

In the $SPLUNK_HOME/etc/apps/Dev_tutorial/default/data/ui/views/Example4.xml file, add the following line in the view hierarchy where you want your module data rendered:

<module name="CustomResultsTable"></module>

In other examples, you will learn Parameterize your module.

Related recipes

Render JSON data shows you how to transfer your data as JSON and format the display on the on the client.

Include 3rd-party libraries shows you how to import third-party graphics library for more advanced rendering.

Parameterize your module shows you how to statically parameterize your module.

Setup your app shows you how to configure your app at runtime.

PREVIOUS
Simple customizations
  NEXT
Render JSON data

This documentation applies to the following versions of Splunk® Enterprise: 6.3.0, 6.3.1, 6.3.2, 6.3.3, 6.3.4, 6.3.5, 6.3.6, 6.3.7, 6.3.8, 6.3.9, 6.3.10, 6.3.11, 6.3.12, 6.3.13, 6.4.0, 6.4.1, 6.4.2, 6.4.3, 6.4.4, 6.4.5, 6.4.6, 6.4.7, 6.4.8, 6.4.9, 6.4.10, 6.5.0, 6.5.1, 6.5.1612 (Splunk Cloud only), 6.5.2, 6.5.3, 6.5.4, 6.5.5, 6.5.6, 6.5.7, 6.5.8, 6.5.9, 6.6.0, 6.6.1, 6.6.2, 6.6.3, 6.6.4, 6.6.5, 6.6.6, 6.6.7, 6.6.8, 6.6.9, 6.6.10, 6.6.11, 7.0.0, 7.0.1, 7.0.2, 7.0.3, 7.0.4, 7.0.5, 7.0.6, 7.0.7, 7.0.8, 7.1.0, 7.1.1, 7.1.2, 7.1.3, 7.1.4, 7.1.5, 7.2.0, 7.2.1


Was this documentation topic helpful?

Enter your email address, and someone from the documentation team will respond to you:

Please provide your comments here. Ask a question or make a suggestion.

You must be logged into splunk.com in order to post comments. Log in now.

Please try to keep this discussion focused on the content covered in this documentation topic. If you have a more general question about Splunk functionality or are experiencing a difficulty with Splunk, consider posting a question to Splunkbase Answers.

0 out of 1000 Characters