[PYTHON] Create a Splunk custom search command-the first step-

Use the Splunk SDK to create a Custom Search Command.

It is said that there is a document, but it is difficult to understand, so I will summarize the reference destination and procedure. As a first step, create a custom search command generatehello [^ 2] that outputs" hello, world "[^ 1].

[^ 1]: In lowercase, in honor of Kernighan & Ritchie. [^ 2]: It's a so-called Native command that uses the Splunk SDK framework instead of calling a script using run. For how to create a script using the run command as a custom search command, "How to create a custom search command (Splunk) --Qiita" will be helpful. I will.

: point_up_tone3: It's a bit old, but the content is still valid Splunk official blog "[Building custom search commands in Python part I – A simple Generating commands](https://www.splunk.com/en_us/blog/tips] -and-tricks / building-custom-search-commands-in-python-part-ia-simple-generating-command.html) It is based on "[^ 3]. However, this article takes a bottom-up approach.

[^ 3]: In the blog of April 2014, it is "Part I", but it seems that the blog of "Part II" has been deleted or not posted.

goal

Outputs "hello, world" in the SPL statement | generatehello count = 3 and the number of events specified in the count argument (3 events in this example).

Splunk カスタムサーチコマンド (custom search command) 作成 ― はじめの一歩 ― ゴール

For now, let's create a simple custom search command that takes no arguments.

Before you start

Development guide"Develop apps | Documentation | Splunk Developer Program"However, it is often confusing to read this, so I will organize the terms.

the term easy explanation
App(s) Display part(UI)、Add-on, entire application, including custom search commands
App in singular, but Apps(Ups)Is often called in the plural.
$SPLUNKHOME/etc/apps/It is arranged in directory units below.
Add-on(s) Display part(UI)Part or whole of the app without
Custom Search Command Your own program called as an SPL command. Generally configured as part of the App.

In this article, it is described as SPLUNKHOME = / opt / splunk [^ 5].

[^ 5]: As an aside, some files seem to be hardcoded as SPLANKHOME = / opt / splunk_home. Since the installation destination of the distributed package is / opt / splunk, you may trip over a little bit.

Development environment & execution environment

Preparation

Download the Splunk SDK, unpack it, and set up your development directory.

Download Splunk SDK

reference: Create custom search commands | Documentation | Splunk Developer Program See also: Downloads | Splunk Developer Program See also: GitHub --splunk / splunk-sdk-python: Splunk Software Development Kit for Python See also: Releases · splunk / splunk-sdk-python · GitHub

The document also describes how to install with pip [^ 4], but this time I will not use the Python virtual environment and will not install pip. Download and use the .zip or .tar.gz file.

[^ 4]: cd $ SPLUNKHOME / etc / apps / yourapp / bin; pip install -t. Splunk-sdk and other methods are written, but the official method described in the official document is used in another directory. Develop and test in, and deploy to Splunk.

: point_up_tone3: From "Releases · splunk / splunk-sdk-python · GitHub" to the latest (currently 1.6.12) .zip Download and unzip the file or .tar.gz file.

Splunk SDK Download and unpack


$ wget https://github.com/splunk/splunk-sdk-python/archive/1.6.12.tar.gz
...
2020-03-17 01:50:38 (3.12 MB/s) - ‘1.6.12.tar.gz’ saved [3876452]

$ ls
1.6.12.tar.gz
$ tar xvfz 1.6.12.tar.gz
splunk-sdk-python-1.6.12/
splunk-sdk-python-1.6.12/.gitattributes
...
splunk-sdk-python-1.6.12/utils/cmdopts.py
$ 

(There is setup.py in the extracted directory, but I will not use it this time.)

Setting up a directory for development work

  1. After copying the SDK template as the working directory HelloWorld-work /, cp -rp splunk-sdk-python-1.6.12/examples/searchcommands_template HelloWorld-work
  2. Create a HelloWorld-work / lib / directory mkdir HelloWorld-work/lib
  3. Copy the splunklib directory under it. cp -rp splunk-sdk-python-1.6.12/splunklib/ HelloWorld-work/lib/

HelloWorld-work Setup


$ cp -rp splunk-sdk-python-1.6.12/examples/searchcommands_template HelloWorld-work
$ mkdir HelloWorld-work/lib
$ cp -rp splunk-sdk-python-1.6.12/splunklib/ HelloWorld-work/lib/
$

You now have a directory structure like the one below.

HelloWork-work Directory tree structure


HelloWorld-work/
|-- bin
|   |-- filter.py  ................ Eventing commands (See below)Template.
|   |-- generate.py  .............. Generating commands (See below)Template.
|   |This time, we will use this file.
|   |-- report.py  ................ Reporting commands (See below)Template.
|   `-- stream.py  ................ Streaming commands (See below)Template.
|-- default  ......................The directory that stores the provider's default configuration files.
|   |-- app.conf  .................Fix it when you set up Splunk.
|   |-- commands-scpv1.conf  ......Delete this file.
|   |-- commands-scpv2.conf  ......Commands this file when configuring Splunk.Replace with conf.
|   |Eventually it will be deleted.
|   |-- commands.conf  ............When setting up Splunk
|   |Command this file-scpv2.Replace with conf and fix.
|   |-- data
|   |   `-- ui
|   |       `-- nav
|   |           `-- default.xml  .. [Setting]-[User interface]-[Navigation menu]-[default]
|   |It is the App display configuration displayed in.
|   `-- logging.conf  .............This time, delete this file.
|-- lib  ..........................The library directory referenced as PYTHONPATH.
|   |This location is not fixed, but it is recommended in the official documentation.
|   |If you added a package that is not included in splunklib in your Python virtual environment
|   |                               site-packages/You need to put the library below.
|   `-- splunklib  ................Same as splunklib in SDK. Call it with import splunklib.
|       |-- __init__.py
:       :
:       :
|       `-- six.pyc
`-- metadata
    `-- default.meta  .............reference/Write permission is specified.

12 directories, 79 files

This directory structure mimics the structure of the $ SPLUNKHOME / etc / apps / yourapplication / directory. You can register as an App by deleting unnecessary files and copying them to $ SPLUNKHOME / etc / apps / as they are.

: point_up_tone3: There are default / and local / in the config file directory, the default / directory is the provider's default setting, and the user is the local / directory (otherwise the directory) It is a rule to set only the changes (by creating). This time, the developer = the provider, so modify the configuration file in the default / directory directly.

development of

Before we start creating custom search commands, let's talk about the types.

4 types of custom search commands

reference: Create custom search commands | Documentation | Splunk Developer Program reference: Python classes | Documentation | Splunk Developer Program

: point_up_tone3: There are four types of custom search commands.

The core of the search commands module contains four classes:

  • EventingCommand: Defines a search command that applies a transformation to search results as they travel through the events pipeline. Examples of eventing commands include sort, dedup, and cluster.
  • GeneratingCommand: Defines a search command that generates event records based on command arguments. Examples of generating commands include search (at the beginning of the pipeline), inputcsv, input lookup, and metadata.
  • ReportingCommand: Defines a search command that processes search results and generates a reporting data structure. Examples of reporting commands include stats, top, and timechart.
  • StreamingCommand: Defines a search command that applies a transformation to search results as they travel through the processing pipeline. Examples of streaming commands include search, eval, and where.

The simple explanation is as follows.

type easy explanation Execution location Command example
Eventing commands Command that receives input, processes it, and outputs it Search Head only sort, dedup, cluster
Generating commands InputNot received, Command to output Search Head only (Written at the beginning)search, inputcsv, input lookup, metadata
Reporting commands Command to receive input and process it into report format Search Head only stats, top, timechart
Streaming commands Commands to process and output in a distributed environment Indexer can be used in parallel search, eval, where

It may be difficult to distinguish between Eventing commands and Streaming commands, with the difference that Eventing commands can only be executed in Search Head, while Streaming commands can also be executed in Indexer [^ 7]. (See also "Types of commands" for more information)

[^ 7]: There is also a command called "Stateful Streaming commands" that can only be executed by Search Head ... What's wrong ...

As a first step, we will create ** Generating commands ** without any input.

Generating commands template

reference: Templates - Create custom search commands | Documentation | Splunk Developer Program

Templates are available for each of the four types. Browse the Generating comannds template.

Generating commands template --generate.py

It's located in ʻexamples / searchcommands_template / bin / generate.pyin the Splunk SDK directory, but underbin /` in the working directory you set up.

generate.py


     1  #!/usr/bin/env python
     2
     3  import sys
     4  import os
     5
     6  sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "lib"))
     7  from splunklib.searchcommands import \
     8      dispatch, GeneratingCommand, Configuration, Option, validators
     9
    10  @Configuration()
    11  class %(command.title())Command(GeneratingCommand):
    12      """ %(synopsis)
    13
    14      ##Syntax
    15
    16      %(syntax)
    17
    18      ##Description
    19
    20      %(description)
    21
    22      """
    23      def generate(self):
    24         # Put your event  code here
    25         pass
    26
    27  dispatch(%(command.title())Command, sys.argv, sys.stdin, sys.stdout, __name__)

Template modification

Copy the template generate.py to HelloWorld.py and modify the command name etc.

Set % (command.title ()) on lines 11 and 27 to HelloWorld. You can use an editor, but it may be easier to fix it with sed.

sed Fix using


$ sed -e 's/%(command.title())/HelloWorld/' generate.py > HelloWorld.py
$ diff generate.py HelloWorld.py
11c11
< class %(command.title())Command(GeneratingCommand):
---
> class HelloWorldCommand(GeneratingCommand):
27c27
< dispatch(%(command.title())Command, sys.argv, sys.stdin, sys.stdout, __name__)
---
> dispatch(HelloWorldCommand, sys.argv, sys.stdin, sys.stdout, __name__)
$ 

Modify generate () — return only one event

Modify the field called greeting to return only one "hello, world".

The type to return is a dictionary type. At this time, Splunk often uses the time as a key, so set the time in the _time field.

Also, as I wrote above, generate () must be of type iterate. : point_up_tone3: There are two ways to do this.

  1. Return with return: The return type must be a list. When returning with return, when all the data is available, it is necessary to list each dictionary type and return.
  2. Return by yield: Returns a single dictionary type with yeild each time.

First, it returns only one entry, so let's try it with return. Insert ʻimport time ()` on line 5 to add the time, and modify the parts on lines 24 and 25 as follows:

     1  #!/usr/bin/env python
     2
     3  import sys
     4  import os
     5  import time      # _New import to set time
     6
     7  sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "lib"))
     8  from splunklib.searchcommands import \
     9      dispatch, GeneratingCommand, Configuration, Option, validators
    10
    11  @Configuration()
    12  class HelloWorldCommand(GeneratingCommand):
    13      """ %(synopsis)
    14
    15      ##Syntax
    16
    17      %(syntax)
    18
    19      ##Description
    20
    21      %(description)
    22
    23      """
    24      def generate(self):
    25          return [{"_time": time.time(), "greeting": "hello, world"}] #Note that it is a list
    26
    27
    28  dispatch(HelloWorldCommand, sys.argv, sys.stdin, sys.stdout, __name__)

The 25th line puts the time in the _time field, puts" hello, world "in the greeting field, and returns as a list.

Operation check

Delete unnecessary configuration files

You can check the operation with python3 HelloWorld.py __EXCECUTE__ </ dev / null, but if you execute it as it is, an error will occur.

Error occurred


$ python3 --version
Python 3.6.9
$ python3 HelloWorld.py __EXECUTE__ < /dev/null
Traceback (most recent call last):
  File "HelloWorld.py", line 8, in <module>
    from splunklib.searchcommands import \
  File "../lib/splunklib/searchcommands/__init__.py", line 145, in <module>
    from .environment import *
  File "../lib/splunklib/searchcommands/environment.py", line 120, in <module>
    splunklib_logger, logging_configuration = configure_logging('splunklib')
  File "../lib/splunklib/searchcommands/environment.py", line 103, in configure_logging
    fileConfig(filename, {'SPLUNK_HOME': splunk_home})
  File "/usr/lib/python3.6/logging/config.py", line 84, in fileConfig
    handlers = _install_handlers(cp, formatters)
  File "/usr/lib/python3.6/logging/config.py", line 131, in _install_handlers
    hlist = cp["handlers"]["keys"]
  File "/usr/lib/python3.6/configparser.py", line 959, in __getitem__
    raise KeyError(key)
KeyError: 'handlers'
$

This is an error when reading the .conf file.

I go to read the files under the default / directory, but since I haven't set anything at the moment, the template characters are still there.

In this article, we will delete unnecessary files once, assuming that we will make the necessary settings. The target this time is logging.conf. (Troubleshooting keywords are ʻin configure_loggingandKeyError:'handlers'` in the above error.)

Delete logging.conf in the default / directory. (If you want to restore it, copy it from the SDK directory again.)

logging.conf&nbsp;Delete


$ rm ../default/logging.conf
$ ls ../default/
app.conf  commands-scpv1.conf  commands-scpv2.conf  commands.conf  data
$

Test run

Run the test in the development environment.

python3 HelloWorld.py __EXECUTE__ < /dev/null

It can be executed with the command sequence. : point_up_tone3: __EXECUTE__ is two underscores (_) before and after ʻEXECUTE`. Even if it is a Generating command, it will wait for standard input [^ 6], so specify / dev / null as input.

[^ 6]: When run on Splunk, Splunk populates meta information for processing by the Splunk library.

Test run


$ python3 --version
Python 3.6.9
$ python3 HelloWorld.py __EXECUTE__ < /dev/null

_time,__mv__time,greeting,__mv_greeting
1584528442.0660899,,"hello, world",
$

You've added unknown fields, __mv__time and __mv_greeting, which the Splunk library adds automatically. Here, make sure that the intended _time and greeting are output.

Install on Splunk

Install (register) it in Splunk and run it.

Modify configuration file

Modify ʻapp.confandcommands.conf in the default / `directory.

ʻApp.conf` modification

See also: app.conf --Splunk Documentation

The template ʻapp.conf` looks like this:

app.conf


     1  # Splunk app configuration file
     2
     3  [ui]
     4  label = %(app_label)<= Correct this to the name of the App.
     5  is_visible = 1
     6
     7  [launcher]
     8  description = %(app_description)
     9  author = %(app_author)
    10  version = %(app_version)
    11
    12  [package]
    13  id = %(app_id)
    14
    15  [install]
    16  is_configured = 0

You can install the custom search command alone, but it will be set in the system directory, so set the name to label to register it as a new app.

Here, it is "Hello World". Other parts need to be modified, but they do not affect the operation of the custom search command, so leave them as they are.

*** app.conf.orig       2020-03-18 20:00:07.303785404 +0900
--- app.conf    2020-03-18 20:00:18.943809800 +0900
***************
*** 1,7 ****
  # Splunk app configuration file

  [ui]
! label = %(app_label)
  is_visible = 1

  [launcher]
--- 1,7 ----
  # Splunk app configuration file

  [ui]
! label = Hello World
  is_visible = 1

  [launcher]

After modification&nbsp;app.conf


# Splunk app configuration file

[ui]
label = Hello World
is_visible = 1

[launcher]
description = %(app_description)
author = %(app_author)
version = %(app_version)

[package]
id = %(app_id)

[install]
is_configured = 0

Modify commands.conf

See also: commands.conf --Splunk Documentation

It is commands.conf that sets the custom search command.

Under the default / directory, there are three files, commands.conf, commands-scpv1.conf, and commands-scpv2.conf. Two templates are available because there are v1 and v2 versions of the protocol that the custom search command interacts with Splunk. The template, commands.conf, has the contents of v1.

Strictly speaking, it is necessary to examine which protocol to use, but I think that it will be v2 in the future, so copy commands-scpv2.conf to commands.conf and modify it.

commands-scpv2.conf&nbsp;copy of


$ cp commands-scpv2.conf commands.conf
$ 

commands.conf&nbsp;(v2)&nbsp;template


     1  # [commands.conf]($SPLUNK_HOME/etc/system/README/commands.conf.spec)
     2  # Configuration for Search Commands Protocol version 2
     3
     4  [%(command.lower()]
     5  filename = %(command.lower()).py
     6  chunked = true

If the command name called from SPL and the file name excluding .py are the same, it is not necessary to set filename, but this time the command name to be called is generatehello and the file name is HelloWorld.py. So, set it.

Also, as I wrote at the beginning, Python3 is used, so make this setting. : point_up_tone3: When using Python3

python.version = python3

To set.

After rewriting&nbsp;commands.conf


     1  # [commands.conf]($SPLUNK_HOME/etc/system/README/commands.conf.spec)
     2  # Configuration for Search Commands Protocol version 2
     3
     4  [generatehello]
     5  filename = HelloWorld.py
     6  chunked = true
     7  python.version = python3

Copy to Splunk apps directory

I wrote the App name in ʻapp.conf, so it doesn't matter what directory you install, as long as the directory name doesn't conflict with other Splunk Apps. Here, let's call it helloworld`. Delete unnecessary configuration files before installation (copy).

: point_up_tone3: The installation directory is under $ SPLUNKHOME / etc / apps /. Copy the entire HelloWorld-work / directory. At this time, pay attention to the owner and permissions of the file. Be especially careful if you're running Splunk as non-root.

$ rm HelloWorld-work/default/commands-scpv[12].conf; sudo sh -c "cp -rp HelloWorld-work /opt/splunk/etc/apps/helloworld; chown -R splunk:splunk /opt/splunk/etc/apps/helloworld"
$ ls -ld /opt/splunk/etc/apps/helloworld/{*,}
drwxr-xr-x 6 splunk splunk 4096 Mar 18 07:52 /opt/splunk/etc/apps/helloworld/
drwxr-xr-x 2 splunk splunk 4096 Mar 18 09:33 /opt/splunk/etc/apps/helloworld/bin
drwxr-xr-x 3 splunk splunk 4096 Mar 18 11:43 /opt/splunk/etc/apps/helloworld/default
drwxr-xr-x 3 splunk splunk 4096 Mar 18 07:52 /opt/splunk/etc/apps/helloworld/lib
drwxr-xr-x 2 splunk splunk 4096 Feb 13 23:30 /opt/splunk/etc/apps/helloworld/metadata
$

Check with btool

See also: Use btool to troubleshoot configurations --Splunk Documentation

Use btool to check that the configuration file is correct.

$SPLUNKHOME/bin/splunk btool check

If there is no problem, nothing will be displayed, but if there is something wrong, the following display will appear. (Example of accidentally changing python.version to ython.version)

Display when there is a problem with the configuration file


$ sudo su splunk -c "/opt/splunk/bin/splunk btool check"
                Invalid key in stanza [generatehello] in /opt/splunk/etc/apps/helloworld/default/commands.conf, line 7: ython.version  (value:  python3).
$

With the --debug option, you will get a lot of messages even for config files that are okay.

Refresh or restart Splunk

The settings are loaded at http (s): // _ yourURL_ / debug / refresh, so restarting is basically unnecessary, but if it does not load, restart Splunk.

Custom search command execution

SPL input

Finally, run it on Splunk. Select Hello World from the App and enter the command in the search window.

|generatehello

コマンド実行 (1)

It worked.

  1. Select App
  2. Make sure the App is "Hello World"
  3. Input | generatehello
  4. One event is displayed, the time is displayed, but "Event" is blank
  5. "greeting" exists in "related fields"

The greeting does not appear as an "event" because the generated data does not contain a _raw field. If you click on the greeting part of the menu on the left, you will see that" hello, world "is output.

SplunkHelloWorld-002.png

If you want to output it explicitly, specify the field with table etc. and it will be displayed.

SplunkHelloWorld-003.png

trouble shooting

If you think something is strange, look at the job log.

image.png

image.png

image.png

The above example is an example of raising an exception for testing.


Up to here for this time. If you can take the first step, it will be easier to take the next step.

Summary

Next time, I will brush up the commands to finish them. ⇒ I wrote the following "Splunk custom search command creation part 2-Qiita".

Recommended Posts

Create a Splunk custom search command-the first step-
Create a custom search command in Splunk (Streaming Command)
Create Splunk custom search command Part 2
Creating custom search commands for Splunk EventingCommand
Create a command to encode / decode Splunk base64
[Go] How to create a custom error for Sentry