Splunk SDK を使用して、カスタムサーチコマンド (Custom Search Command) を作成します。
ドキュメントがあるといえばあるのですが、なかなかわかりずらいので、参照先と手順をまとめておきます。
はじめの一歩として、"hello, world"1 を出力するカスタムサーチコマンド generatehello
を作成2します。
少し古いのですが、内容は今でも通用する Splunk 公式ブログ "Building custom search commands in Python part I – A simple Generating command"3 をベースとしています。ただし、本稿では、ボトムアップのアプローチをとります。
ゴール
|generatehello count=3
という SPL文で "hello, world" を、引数 count に指定した個数のイベント (この例では 3イベント) を出力します。
本稿では、ひとまず、引数を取らない、簡単なカスタムサーチコマンドを作成します。
はじめる前に
開発の手引きは "Develop apps | Documentation | Splunk Developer Program" ですが、これを読み進めるうえで、混乱することが多いので、用語を整理しておきます。
用語 | 簡単な説明 |
---|---|
App(s) | 表示部分 (UI)、Add-on、カスタムサーチコマンドを含む、アプリケーション全体 単数では App だが、Apps (アップス) と複数形で呼ばれることが多い。 $SPLUNKHOME/etc/apps/ 下にディレクトリ単位で配置される。 |
Add-on(s) | 表示部分 (UI) を伴わない、App の一部、または全体 |
Custom Search Command | SPL のコマンドとして呼び出される自前のプログラム。一般的に App の一部として構成する。 |
なお、本稿では SPLUNKHOME=/opt/splunk
として記述します4。
開発環境 & 実行環境
- OS: Ubuntu 18.04 (厳密には、Windows 10 Pro の Hyper-V - Ubuntu 18.04 - docker 内)
- Python: 開発・テスト環境: 3.6.9、Splunk Python: 3.7.4
-
Splunk: Version 8.0.2.1 (本稿執筆時点で最新、日本時間2020年3月12日リリース)
(開発時にはインストールされている必要はありません。実行環境として必要です。) - Splunk SDK (Software Development Kit): Version 1.6.12
準備
Splunk SDK をダウンロードして展開、開発用ディレクトリの設定を行います。
Splunk SDK のダウンロード
参照: Create custom search commands | Documentation | Splunk Developer Program
参照: Downloads | Splunk Developer Program
参照: GitHub - splunk/splunk-sdk-python: Splunk Software Development Kit for Python
参照: Releases · splunk/splunk-sdk-python · GitHub
pip でのインストール方法などもドキュメントには書かれています5が、今回は Python 仮想環境も使わず、 pip インストールも行いません。.zip ファイルか .tar.gz ファイルをダウンロードして使用します。
"Releases · splunk/splunk-sdk-python · GitHub" から、最新(現時点では 1.6.12) の .zip ファイルか .tar.gz ファイルをダウンロードして、展開します。
$ 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
$
(展開したディレクトリの中に setup.py がありますが、今回は使いません。)
開発作業用ディレクトリのセットアップ
- SDK のテンプレートを作業用ディレクトリ
HelloWorld-work/
としてコピーしたのち、
cp -rp splunk-sdk-python-1.6.12/examples/searchcommands_template HelloWorld-work
-
HelloWorld-work/lib/
ディレクトリを作成して
mkdir HelloWorld-work/lib
- その下に
splunklib
ディレクトリをコピーします。
cp -rp splunk-sdk-python-1.6.12/splunklib/ HelloWorld-work/lib/
$ 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/
$
これで、以下のようなディレクトリ構造ができあがりました。
HelloWorld-work/
|-- bin
| |-- filter.py ................ Eventing commands (後述) のテンプレート。
| |-- generate.py .............. Generating commands (後述) のテンプレート。
| | 今回は、このファイルを使用します。
| |-- report.py ................ Reporting commands (後述) のテンプレート。
| `-- stream.py ................ Streaming commands (後述) のテンプレート。
|-- default ...................... 提供者のデフォルト設定ファイルを格納するディレクトリ。
| |-- app.conf ................. Splunk 設定時に修正します。
| |-- commands-scpv1.conf ...... このファイルは削除します。
| |-- commands-scpv2.conf ...... Splunk 設定時にこのファイルを commands.conf に置き換えます。
| | 最終的には削除します。
| |-- commands.conf ............ Splunk 設定時に、
| | このファイルを command-scpv2.conf で置き換えて修正します。
| |-- data
| | `-- ui
| | `-- nav
| | `-- default.xml .. [設定]-[ユーザインタフェース]-[ナビゲーションメニュー]-[default]
| | にて表示される、App 表示構成です。
| `-- logging.conf ............. 今回、このファイルは削除します。
|-- lib .......................... PYTHONPATH として参照するライブラリディレクトリ。
| | この場所は決まっているわけではないが、公式ドキュメントで推奨しています。
| | Python 仮想環境で splunklib に含まれないパッケージを追加した場合は、
| | site-packages/ 下のライブラリを置く必要があります。
| `-- splunklib ................ SDK の splunklib と同じもの。import splunklib で呼び出します。
| |-- __init__.py
: :
: :
| `-- six.pyc
`-- metadata
`-- default.meta ............. 参照/書き込み権限が指定されています。
12 directories, 79 files
このディレクトリ構造は、$SPLUNKHOME/etc/apps/yourapplication/ ディレクトリの構造を模したものです。
不要なファイルを削除して、このまま $SPLUNKHOME/etc/apps/ へコピーすることで App として登録できます。
設定ファイルのディレクトリには default/
と local/
があり、default/
ディレクトリは提供者がデフォルトの設定を記載し、使用者は local/
ディレクトリで(なければディレクトリを作成して)変更分のみを設定するルールになっています。
今回は、開発者=提供者ですので、default/
ディレクトリの設定ファイルを直接修正します。
開発
カスタムサーチコマンドの作成を始めるにあたり、種類について説明しておきます。
カスタムサーチコマンドの4つの種類
参照: Create custom search commands | Documentation | Splunk Developer Program
参照: Python classes | Documentation | Splunk Developer Program
カスタムサーチコマンドには4つの種類があります。
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.
簡単に説明すると、以下のようになります。
タイプ | 簡単な説明 | 実行場所 | コマンド例 |
---|---|---|---|
Eventing commands | 入力を受けて、加工して出力するコマンド | Search Head のみ | sort, dedup, cluster |
Generating commands | 入力を受けず、出力を行うコマンド | Search Head のみ | (先頭に書かれた)search, inputcsv, input lookup, metadata |
Reporting commands | 入力を受けて、加工してレポート形式にするコマンド | Search Head のみ | stats, top, timechart |
Streaming commands | 分散環境で、加工して出力するコマンド | 並列で Indexer でも可 | search, eval, where |
Eventing commands と Streaming commands の区別がつきにくいかもしれませんが、Eventing commands は Search Head でのみ実行可能ですが、Streaming commands は Indexer でも実行可能という違いがあります6。(詳しくは、"Types of commands" も参照してください)
はじめの一歩としては、入力を行わない、Generating commands を作成していきます。
Generating commands のテンプレート
参照: Templates - Create custom search commands | Documentation | Splunk Developer Program
4つのタイプそれぞれにテンプレートが用意されています。Generating comannds のテンプレートを参照します。
Generating commands テンプレート - generate.py
Splunk SDK ディレクトリの examples/searchcommands_template/bin/generate.py
にありますが、セットアップした作業ディレクトリでは、bin/
の下にあります。
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__)
-
6行目 Python ライブラリを読み込むパスを指定しています。
このディレクトリ構造では、generate.py
があるディレクトリの親ディレクトリにある lib ディレクトリ (..../HellWorld-work/bin/../lib
=..../HelloWorld-work/lib
) を sys.path に加えています。
この lib の下にあるsplunklib
モジュールを呼び出します。
このことからわかることは、lib/
を Splunk が自動的に PYTHONPATH に設定するわけではないということです。
自前のライブラリを追加する場合には、sys.path の設定が必要になりますが、このテンプレートを使用する場合には、lib ディレクトリに置けば読み込むことができます。 - 7行目 Splunk カスタムサーチコマンドに必要なモジュールを呼び出しています。
-
10行目 カスタムサーチコマンドのためのデコレータを記述しています。
(デコレータの説明は「デコレータ(decorator) とは - Python の汎用デコレータ(decorator)フレームワークを作る - Qiita」をご参照ください) -
11行目 Splunk から呼び出されるコマンドのクラスの定義部分です。
%(command.title())
の部分を適切な名前に変えます。
(27行目にも出てきますので、同じ文字列で置き換えます)
基底クラスとして GeneratingCommand クラスを指定しています。 - 12行目~22行目 pydoc 部分は、できれば、
%( )
の部分をそれぞれ適切なものに置き換えて記述する必要がありますが、今回は省略します。 -
23行目 コマンドの本体になります。
generate
という名前はそのまま使用する必要があります。
generate()
関数は、iterator である必要があります(後述)。 -
27行目 コマンドのディスパッチャーです。
%(command.title())
部分は、11行目に出てきたものと同じ文字列で置き換えます。
テンプレートの修正
テンプレート generate.py
を HelloWorld.py
にコピーして、コマンド名などを修正します。
11行目と27行目の %(command.title())
を HelloWorld
にします。
エディタでもいいですが、sed で修正すると楽かもしれません。
$ 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__)
$
generate() の修正 ― イベントをひとつだけ返す
greeting というフィールドに "hello, world" をひとつだけ返すように修正します。
戻す型は辞書型です。このとき、Splunk は時刻をキーにすることが多いので、_time
フィールドに時刻を設定します。
また、上にも書きましたが、generate() は iterate タイプである必要があります。
これには二つの方法があります。
- return で返す: 戻す型はリストである必要があります。return で返す場合には、すべてのデータがそろった時点で、それぞれの辞書型をリストにして、return する必要があります。
- yield で返す: 単一の辞書型を都度 yeild で返していきます。
まずは、ひとつだけエントリを返しますので、return で試してみましょう。
時刻を追加するために 5行目に import time()
を挿入し、24行目と25行目の部分を次のように修正します。
1 #!/usr/bin/env python
2
3 import sys
4 import os
5 import time # _time を設定するために新たに import
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"}] # リストであることに注意
26
27
28 dispatch(HelloWorldCommand, sys.argv, sys.stdin, sys.stdout, __name__)
25 行目は _time
フィールドに時刻を入れ、greeting
フィールドに "hello, world" を入れて、リストとして return しています。
動作確認
不要な設定ファイルを削除
動作確認は python3 HelloWorld.py __EXCECUTE__ < /dev/null
で行えますが、今のまま実行するとエラーになります。
$ 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'
$
これは、.conf ファイルを読み込む際にエラーになっているものです。
default/
ディレクトリ下のファイルを読みに行きますが、現在は何も設定していないので、テンプレート文字がそのまま残っています。
必要な設定はいずれ行うとして、本稿では、一旦不要なファイルを削除します。
今回の対象は logging.conf です。(トラブルシューティングのキーワードは、上のエラーの in configure_logging
と KeyError: 'handlers'
です。)
default/
ディレクトリにある、logging.conf を削除します。(復活したければ、SDK のディレクトリから改めてコピーします。)
$ rm ../default/logging.conf
$ ls ../default/
app.conf commands-scpv1.conf commands-scpv2.conf commands.conf data
$
テスト実行
開発環境内でテストで実行します。
python3 HelloWorld.py __EXECUTE__ < /dev/null
というコマンド列で実行可能です。
__EXECUTE__
は EXECUTE
の前後にアンダースコア (_
) ふたつずつです。
Generating command であっても標準入力待ちになる7ので、入力として /dev/null を指定しておきます。
$ python3 --version
Python 3.6.9
$ python3 HelloWorld.py __EXECUTE__ < /dev/null
_time,__mv__time,greeting,__mv_greeting
1584528442.0660899,,"hello, world",
$
__mv__time
と __mv_greeting
という知らないフィールドが追加されていますが、これは Splunk ライブラリが自動的に付加するものです。ここでは、意図した _time
と greeting
が出力されていることを確認してください。
Splunk へのインストール
Splunk へインストール(登録)して、実行してみましょう。
設定ファイルの修正
default/
ディレクトリにある app.conf
と commands.conf
を修正します。
app.conf
の修正
参照: app.conf - Splunk Documentation
テンプレートのままの app.conf
は下のようになっています。
1 # Splunk app configuration file
2
3 [ui]
4 label = %(app_label) <= ここを 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
カスタムサーチコマンド単体でもインストール可能ですが、システムのディレクトリに設定することになるので、新規の App として登録するために、label
に名前を設定します。
ここでは、"Hello World" とします。他の部分も本来は修正が必要ですが、カスタムサーチコマンドの動作には影響しませんので、このままにします。
*** 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]
# 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
commands.conf
の修正
参照: commands.conf - Splunk Documentation
カスタムサーチコマンドの設定を行うのが commands.conf
です。
default/
ディレクトリの下には commands.conf
、 commands-scpv1.conf
、commands-scpv2.conf
という三つのファイルがあります。カスタムサーチコマンドが Splunk とやり取りをするプロトコルのバージョンには v1 と v2 があるため、二つのテンプレートが用意されています。テンプレートのままの commands.conf
は v1 の内容になっています。
厳密にはどちらのプロトコルを使うのかを吟味する必要がありますが、今後は v2 になっていくと思いますので、commands-scpv2.conf
を commands.conf
にコピーして修正します。
$ cp commands-scpv2.conf commands.conf
$
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
SPL から呼び出すコマンド名と .py
を除いたファイル名が同じ場合には filename
の設定は不要なのですが、今回は呼び出すコマンド名を generatehello
、ファイル名が HelloWorld.py
ですので、設定を行います。
また、冒頭で書いたように、Python3 を使いますので、この設定を行います。
Python3 を使用する場合には、
python.version = python3
を設定します。
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
Splunk apps ディレクトリへのコピー
app.conf
に App 名を書きましたので、Splunk の他の Apps とディレクトリ名がぶつからなければ、インストールするディレクトリは何でも構いません。ここでは、helloworld
としておきます。インストール(コピー)の前に、不要な設定ファイルは削除しておきます。
インストール先のディレクトリは $SPLUNKHOME/etc/apps/
下です。HelloWorld-work/
ディレクトリを丸ごとコピーします。この時、ファイルのオーナやパーミッションに注意してください。Splunk を 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
$
btool によるチェック
参照: Use btool to troubleshoot configurations - Splunk Documentation
設定ファイルに間違いがないか、btool を使用してチェックします。
$SPLUNKHOME/bin/splunk btool check
問題が無ければ何も表示されませんが、何か間違いなどがあると、次のような表示が出ます。(python.version
を誤って ython.version
としてしまった例)
$ 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).
$
--debug
オプションを付けると、問題のない設定ファイルについても大量にメッセージがでます。
Splunk の Refresh または再起動
http(s)://yourURL/debug/refresh で設定が読み込まれますので、再起動は基本的に不要ですが、読み込まれないようであれば、Splunk を再起動してください。
カスタムサーチコマンド実行
SPL 投入
いよいよ、Splunk 上で実行します。App から Hello World
を選択してサーチ窓にコマンドを入力します。
|generatehello
動きました。
- App を選択
- App が "Hello World" になっていることを確認
-
| generatehello
を投入 - イベントが一つ表示されていて、時刻は表示されているが「イベント」は空欄
- 「関連するフィールド」に "greeting" が存在
greeting が「イベント」として表示されないのは、生成されたデータに _raw
フィールドが含まれていないためです。
左側のメニューの greeting
の部分をクリックすると、"hello, world" が出力されているのがわかります。
明示的に出力したければ、 table
などでフィールドを指定すると表示されます。
トラブルシューティング
なんか変だなと思った場合には、ジョブのログを見ましょう。
上の例は、テストのために例外を発生させてみたものです。
今回はここまで。
はじめの一歩が踏み出せれば、次の一歩も踏み出しやすくなります。
まとめ
-
| generatehello count=3
と入力してイベントが3つ表示されるカスタムサーチコマンド作成を目標として、今回は引数のないコマンドでイベントをひとつだけ表示するところまで作成しました。 - 今のままでは「イベント」には表示されず、明示的にフィールドを参照しなければ "hello, world" が表示されません。
次回は、コマンドをブラシアップして仕上げます。 ⇒ 続きの「Splunk カスタムサーチコマンド (custom search command) 作成 その2 - Qiita」を書きました。
-
Splunk SDK のプログラム例はこちら→ splunk-sdk-python/generatehello.py at master · splunk/splunk-sdk-python · GitHub
-
【2020/05/04 追記】GitHub でサンプルコードを公開しました → Splunk-CustomSearchCommand-FirstStep at step1
-
Kernighan & Ritchie への敬意をこめて、小文字で。 ↩
-
run を用いてスクリプトを呼び出すのではなく、Splunk SDK のフレームワークを利用した、いわば Native なコマンドです。run コマンドを用いたスクリプトをカスタムサーチコマンドとして作成する方法は、「 カスタムサーチコマンドの作り方(Splunk) - Qiita」が参考になると思います。 ↩
-
2014年4月のブログで、"Part I" となっていますが、"Part II" のブログは削除されたか、投稿されていないようです。 ↩
-
余談ですが、いくつかのファイルで SPLANKHOME=/opt/splunk_home とハードコードされているようです。配布されているパッケージによるインストール先は /opt/splunk ですので、ちょっとしたところでつまずいたりすることがあります。 ↩
-
cd $SPLUNKHOME/etc/apps/yourapp/bin; pip install -t . splunk-sdk などの方法が書かれたものもありますが、公式ドキュメントに記載された正規の方法で、別ディレクトリでの開発とテスト、Splunk への導入を行います。 ↩
-
"Stateful Streaming commands" という、 Search Head でしか実行できないコマンドもあるとか……もう、何が何やら…… ↩
-
Splunk 上で実行した場合には、Splunk から meta 情報が入力され、Splunk ライブラリによって処理されます。 ↩