LoginSignup
1
2

More than 3 years have passed since last update.

Splunk カスタムサーチコマンド (custom search command) 作成 その2

Last updated at Posted at 2020-03-27

前回は、はじめの一歩で Splunk のカスタムサーチコマンド (Custom Search Command) として、引数を取らずにイベントをひとつだけ生成するコマンドを作成しました。

今回は、引数を取り、引数で指定した個数のイベントを生成するようにコマンドをブラシアップします。

前回までのおさらい

前回: 「Splunk カスタムサーチコマンド (custom search command) 作成 ― はじめの一歩 ― - Qiita

Generating commands タイプのカスタムサーチコマンド generatehello を作成しました。

前回までに作成した HelloWorld.py
#!/usr/bin/env python

import sys
import os
import time

sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "lib"))
from splunklib.searchcommands import \
    dispatch, GeneratingCommand, Configuration, Option, validators

@Configuration()
class HelloWorldCommand(GeneratingCommand):
    """ %(synopsis)

    ##Syntax

    %(syntax)

    ##Description

    %(description)

    """
    def generate(self):
        return [{"_time": time.time(), "greeting": "hello, world"}]


dispatch(HelloWorldCommand, sys.argv, sys.stdin, sys.stdout, __name__)

このプログラムには、次のような課題があります。

  • イベントは一つのみです。
  • 「イベント」には表示されず、明示的にフィールドを参照しなければ "hello, world" が表示されません。

今回は、これを解消していきます。
Splunk 公式ブログ "Building custom search commands in Python part I – A simple Generating command" をベースとしています。(少し変更しています)

一つめの課題: イベント個数の指定

イベントの個数を指定できるようにします。

引数の指定方法 (受け取り方法)

引数は、デコレータ Option で指定します。

ここでは、簡単に Option をクラスとして呼び出して指定する方法で利用することにします。

作成した class HelloWorldCommand の中で、下のようにして呼び出します。

Option( )
from splunklib.searchcommands import Option

@Configuration()
class HelloWorldCommand(GeneratingCommand):
    count = Option()

単に count という変数に値を格納するだけでなく、SPL 文のコマンドの引数として count を使用することも Option() によって同時に設定されています。SPL 文では、 | generatehello count=3 というように指定します。

Option クラスは、"Module structure - Python classes | Documentation | Splunk Developer Program" に記載があり、その API の説明が "splunklib.searchcommands — Splunk SDK for Python API Reference" の参照となっていますが、なかなか解読が難しいドキュメントです。

class splunklib.searchcommands.Option(fget=None, fset=None, fdel=None, doc=None, name=None, default=None, require=None, validate=None)

Represents a search command option.

Required options must be specified on the search command line.

Example:

Short form (recommended). When you are satisfied with built-in or custom validation behaviors.

1
2
3
4
5
6
7
8
from splunklib.searchcommands.decorators import Option
from splunklib.searchcommands.validators import Fieldname

total = Option(
    doc=''' **Syntax:** **total=***<fieldname>*
    **Description:** Name of the field that will hold the computed
    sum''',
    require=True, validate=Fieldname())

Option() の引数は class splunklib.searchcommands.Option(fget=None, fset=None, fdel=None, doc=None, name=None, default=None, require=None, validate=None) となっています。

fgetfsetfdel は、Option() 内部において Python built-in 関数 (デコレータ) の property に渡される引数で、それぞれ、参照、代入、解放 (del) のための関数を指定しますが、ここでは頭の片隅に留めておけばよいでしょう。
(Python property の使い方に慣れた方なら、ご存知のことと思います)

docnamedefaultrequirevalidate は覚えておくべき引数です。

引数 説明
doc 引数の説明を書きます。
name 引数の名前を指定します。省略時は代入先の変数名と同じ名前が設定されます。
default 引数省略時のデフォルト値を設定します。
require 引数が必須かどうかを設定します。boolean型 (True/False)
validate 引数の型を設定します。

name は、省略すると、代入先の変数名と同じ名前がサーチコマンドの引数名になりますが、逆に言えば、name を指定することで、変数名とは別な引数名を設定することができます。

validate は、splunklib.searchcommands.validators で定義されているものですが、SDK を覗くしかないようです。(説明は省略)

  • Boolean() ..... *
  • Code() ..... *
  • Duration() ..... *
  • Fieldname()
  • File() ..... *
  • Integer() ..... *
  • List() ..... *
  • Map() ..... *
  • Match()
  • OptionName()
  • RegularExpression() ..... *
  • Set() ..... *

が定義されています。
(import * で読み出した場合は、Boolean, Code, Duration, File, Integer, List, Map, RegularExpression, Set のみ)

参照先のブログのサンプルから少し変えて、require=False で、整数値、default=1 としてみましょう。

引数 count の設定
count = Option(require=False, validate=validators.Integer(), default=1)

繰り返し出力

count が引数として与えられます (省略時は 1) ので、これに合わせて繰り返し出力を行います。

前回は

        return [{"_time": time.time(), "greeting": "hello, world"}]

としましたが、今回はすべての処理を待たずに値を返したいので、return でリストを返すのではなく、yield で個々のイベントを返すようにします。

        for i in range(0, self.count):
            yield {"_time": time.time(), "greeting": "hello, world"}

全体

ここまでを統合すると、プログラムは次のようになります。名前を変えて HelloWorld2.py とします。

引数を指定できるようにした HelloWorld2.py
#!/usr/bin/env python

import sys
import os
import time

sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "lib"))
from splunklib.searchcommands import \
    dispatch, GeneratingCommand, Configuration, Option, validators

@Configuration()
class HelloWorldCommand(GeneratingCommand):
    """ %(synopsis)

    ##Syntax

    %(syntax)

    ##Description

    %(description)

    """
    count = Option(require=False, validate=validators.Integer(), default=1)

    def generate(self):

        for i in range(0, self.count):
            yield {"_time": time.time(), "greeting": "hello, world"}


dispatch(HelloWorldCommand, sys.argv, sys.stdin, sys.stdout, __name__)

動作テスト

開発環境内で動作テストを行います。

HelloWorld2.py の動作確認
$ python3 HelloWorld2.py __EXECUTE__ count=3 < /dev/null

_time,__mv__time,greeting,__mv_greeting
1584952340.0804844,,"hello, world",
1584952340.0816362,,"hello, world",
1584952340.0816433,,"hello, world",

Splunk 環境への導入と動作確認

Splunk 環境での App 登録は前回行ったので、修正した HelloWorld2.pyhelloword/bin にコピーします。
前回同様、オーナやグループ、パーミッションに気をつけてください。

Splunk 環境へのコピー
cp HelloWorld2.py /opt/splunk/etc/apps/helloworld/bin/

名前を変えたので default/commands.conf も修正します。カスタムサーチコマンド名は generatehello2 とします。

commands.conf
# [commands.conf]($SPLUNK_HOME/etc/system/README/commands.conf.spec)
# Configuration for Search Commands Protocol version 2

[generatehello]
filename = HelloWorld.py
chunked = true
python.version = python3

[generatehello2]
filename = HelloWorld2.py
chunked = true
python.version = python3

btool でのチェックを行った後、debug/refresh か Splunk の再起動を行います。

Splunk 上での動作確認

サーチで | generatehello count=3 と入力してみます。

image.png

3イベントの出力ができました。

二つめの課題: "hello, world" のイベント出力

ここまでのところ、左側の「関連するフィールド」の部分には greeting があり、そこをクリックすると "hello, world" の文字が出てきますが、イベントの表示には出てきません。

これは、_raw フィールドを明示的に指定することで表示できるようになります。
ここでは、単純に、greeting と同じものを _raw に入れて出力させます。

_raw フィールドの設定
        greeting_msg = "hello, world"
        for i in range(0, self.count):
            yield {"_time": time.time(), "greeting": greeting_msg, "_raw": greeting_msg}

全体は以下の通り。

_raw フィールドの設定を行った HelloWorld2.py
#!/usr/bin/env python

import sys
import os
import time

sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "lib"))
from splunklib.searchcommands import \
    dispatch, GeneratingCommand, Configuration, Option, validators

@Configuration()
class HelloWorldCommand(GeneratingCommand):
    """ %(synopsis)

    ##Syntax

    %(syntax)

    ##Description

    %(description)

    """
    count = Option(require=False, validate=validators.Integer(), default=1)

    def generate(self):

        greeting_msg = "hello, world"
        for i in range(0, self.count):
            yield {"_time": time.time(), "greeting": greeting_msg, "_raw": greeting_msg}


dispatch(HelloWorldCommand, sys.argv, sys.stdin, sys.stdout, __name__)

一つめの時と同様、開発環境で動作確認 → Splunk 環境へコピー → btool によるチェック → Splunk のサーチで確認します。

開発環境での動作確認
$ python3 HelloWorld2.py __EXECUTE__ count=3 < /dev/null

_time,__mv__time,greeting,__mv_greeting,_raw,__mv__raw
1584954369.7098827,,"hello, world",,"hello, world",
1584954369.7099497,,"hello, world",,"hello, world",
1584954369.7099597,,"hello, world",,"hello, world",

_raw フィールドが増えていることを確認します。

Splunk 環境へのコピー
cp HelloWorld2.py /opt/splunk/etc/apps/helloworld/bin/

($SPLUNK_HOME = /opt/splunk です)

Splunk のサーチで動作を確認します。 ("| generatehello2 count=3")

image.png

「イベント」フィールドに表示されるようになりました。

まとめ

前回の「Splunk カスタムサーチコマンド (custom search command) 作成 ― はじめの一歩 ― - Qiita」で作成した Generating commands 型のカスタムサーチコマンドをブラシアップしました。

  • count 引数で、出力するイベント数を指定できるようにしました。
  • _raw フィールドを出力し、サーチ結果に「イベント」が表示されるようにしました。

ここまでできると、Eventing commands に進むのも楽になるのではないでしょうか。

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2