SplunkのAdd-on Builderで自前のアドオンを作成してみる(Pythonスクリプト作成編)

2020.02.05

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

オペレーション部 江口です。

前回、Splunk Add-on Builderで簡単なREST APIで情報を取得するアドオンの作成方法を紹介しました

この方法はREST APIで取得したJSONデータをSplunkにイベントとして記録する単純な利用であれば十分ですが、REST API以外の方法でデータを取得したいとか、データ取得後に何らかの加工を施したい、といった場合には利用できません。

Splunkでは柔軟にデータの入力処理を実現するため、Pythonスクリプトによるアドオンの作成に対応しています。今回はこちらについて解説します。

なおSplunkアドオンやAdd-on Builderについての基本的な解説は前回の記事をご参考ください。

SplunkのAdd-on Builderで自前のアドオンを作成してみる(REST API編)

この記事で作成するアドオン

前回の記事では、手軽にAWSの各サービスのステータスを取得できる下記URLからJSONデータを取得していました。

https://status.aws.amazon.com/data.json

今回も引き続きこちらを利用してみたいと思います。

もちろん単純にこのURLにアクセスして得たJSONデータを取得するだけでは前回のものと変わらないので、ここでは少し加工処理を加えてみることにします。

まず復習として、実行時に返ってくるJSONデータを以下に載せておきます(前回掲載の情報と同一です)。

{
    "archive":[
        {
             "service_name":"Auto Scaling (N. Virginia)", 
             "summary":"[RESOLVED] Increased API Error Rates", 
             "date":"1525914401", 
             "status":1, 
             "details":"", 
             "description":"<div><span class="yellowfg"> 6:06 PM PDT</span> We are investigating increased API error rates in the US-EAST-1 Region.</div><div><span class="yellowfg"> 6:26 PM PDT</span> We are continuing to investigate increased API error rates in the US-EAST-1 Region</div><div><span class="yellowfg"> 7:24 PM PDT</span> We have identified the root cause of the elevated API error rates and can confirm that most customers have recovered. We are continuing to work towards full resolution.</div><div><span class="yellowfg"> 7:40 PM PDT</span> Between 5:42 PM and 7:04 PM PDT, we experienced increased API error rates in the US-EAST-1 Region. The issue has been resolved and the service is operating normally.</div>", 
             "service":"autoscaling-us-east-1" 
        },
    (略)
    "current":[
    ]
}

前回記事で解説した通り、取得されるJSONデータには、、過去の障害情報を記載したarchiveと現行の障害情報を記載したcurrentの2種類の情報が入ってきます。場合によってはcurrentの情報だけ取れれば良い、というユーザもいるでしょうし、参考のためarchiveの情報も記録しておきたい、というユーザもいるでしょう。

そこで、どちらの一方だけの情報を取得するか、もしくは両方とも取得するのか、をユーザが設定できる機能をこのPythonスクリプトに実装してみます。

ついでに、以下の処理も実装します。

  1. 各サービスの情報のエントリごとに別々のSplunkイベントに分割して記録する
  2. 上記のエントリがcurrentarchiveどちらの情報かわかるよう、エントリーに情報を追記する
  3. エントリ内のdateフィールドの値がUnix Timeなので、分かりやすい日時の文字列に変換した情報もエントリーに追記する

上記23で付加する追加情報は、added_informationという項目に収めることにしたいと思います。

それでは実装してみましょう。

アドオンの新規作成

まずはPythonスクリプトを利用するアドオンを新規に作成します。手順は前回と同様です。

Pythonスクリプトを利用するデータ入力の定義の作成

アドオン内でデータ入力の定義を作成します。後ほど説明しますが、このアドオン用のPythonスクリプトは一種のフレームワークの一部で、記述する必要がある関数が決まっていたり、ユーザが設定したパラメータを取得するためのメソッドなどが予め用意されています。データ入力の定義を行うと、その情報を反映したテンプレートをSplunkが自動で生成してくれる仕組みです。

  • 「Configure Data Collection」をクリックし、データ入力方法の画面に遷移します。
  • 「Choose Input Method」で「Python code」を選択します。

  • 「Inputs & Parameters」の設定画面に遷移します。「Data Input Properties」タブでSource type名、データ入力の定義名などを設定します。

  • 「Data Input Parameters」でユーザに設定可能なパラメータを定義します。

この画面では入力フォームの部品を配置して、入力画面を作成することができます。今回は前述のようにデータの種類として、currentarchive、両方(both)をユーザが選択できるようにしたいので、ドロップダウンでこの3つを選択できるようにします。

ドロップダウンメニューにはいくつかプロパティが存在しますので、以下かいつまんで紹介します。

  • Display label: 入力フォームに表示されるラベル文字列
  • Internal name: Pythonスクリプトで参照する際に利用される内部用の名前
  • オプション: ドロップダウンで選択可能な値のリスト。Display labelはフォーム上の表示名、Intenal valueは選択された際Pythonスクリプトに渡される値

今回の例では下記スクリーンショットのように設定しました。

この「Inputs & Parameters」の設定には、もうひとつ「Add-on Setup Parameters」というタブもあります。 前回の記事の説明の繰り返しですが、こちらは「Data Input Parameters」と似ているものの、アドオン全体のグローバルな設定の入力フォームを作成できます。「Data Input Parameters」はユーザが複数の定義を作成できるのに対して、こちらはグローバルな設定のため定義は1つのみ、という点が異なります。たとえば共通で利用するユーザ名・パスワードなどをこちらに配置します。今回は「Data Input Parameters」のみ利用することにします。

Pythonスクリプトの作成

メニュー上部の「次へ」ボタンをクリックすると、Pythonスクリプトの記述・テストが行える「Define Inputs」画面へ遷移します。

左側のペインには、前の画面で定義したパラメータの入力フォームが表示されています。ここで入力した値を利用してスクリプトの動作をテストすることができます。

「Code Editor」と書かれた左側のペインには、Pythonスクリプトの雛形が表示されています。前述しましたが、この雛形では定義した入力パラメータなどの情報が反映されています。

スクリプトを確認すると、関数として以下の2つが用意されているはずです。この2つは、アドオンでPythonスクリプトを動かすにあたって必須の関数となっています。

  • validate_input(helper, definition)
  • collect_events(helper, ew)

生成されたスクリプトの冒頭に下記のようなコメントが記載されているように、ユーザが処理を記述するのもこの2つの関数のみという想定です。

'''
    IMPORTANT
    Edit only the validate_input and collect_events functions.
    Do not edit any other part in this file.
    This file is generated only once when creating the modular input.
'''

なおスクリプト内の処理では、Splunkの用意したPythonヘルパ関数を利用してパラメータの受け取りやイベントの書き込みなどを行えます。ヘルパ関数については生成された雛形のコメント内でいくつか紹介されていますが、詳しくは以下の公式ドキュメントを参照してください。

https://docs.splunk.com/Documentation/AddonBuilder/latest/UserGuide/PythonHelperFunctions

以下、記述が必要な2つの関数について説明します。

validate_input

入力フォームで指定されたパラメータが正しいかを検証する処理を記述する関数です。 ここでは入力フォームの値は、definition.parameters.get()によって受け取ります。

今回の場合、パラメータ名はinformation_typeと設定しましたが、この場合は以下のように受け取ります。雛形にはこの処理はあらかじめ記述されていると思います。

information_type = definition.parameters.get('information_type', None)

今回、想定される値はcurrentarchivebothの3種類のみなので、それ以外の値を受け取った場合は例外(ValueErrorを投げるよう記述しました。

#正常な値のリスト
valid_values=['current','archive','both']
if information_type in valid_values:
    pass
else:
    raise ValueError("Value for information type %s was not valid" % information_status)

collect_events

実際にデータを収集する処理を記述する関数です。 この処理では最終的にイベントをSplunkに記録します。この際にはまずイベントデータをhelper.new_event()で作成し、ew.write_event()で書き込みを行います。以下は今回の例でこの処理だけを抜き出したものです。

#Splunk用イベントデータの作成
event = helper.new_event(source=helper.get_input_type(), index=helper.get_output_index(), 
                            sourcetype=helper.get_sourcetype(), data=json.dumps(entry))
#イベントデータの書き込み
ew.write_event(event)

helper.new_event()では、パラメータとして以下を指定しています。

  • source: イベントの入力ソースの情報
  • index: 保存するインデックス
  • sourcetype: イベントのソースタイプ
  • data: 実際にイベントとして書き込むデータ

sourceindexsourcetypeはSplunkでこのアドオン用のデータ入力を定義した際に指定する情報で、ヘルパ関数(helper.get_xxx())によりそれぞれ取得しています。

実際のスクリプト

以下、実際に私が作成したPythonスクリプトを参考までに紹介しておきます。

# encoding = utf-8

import os
import sys
import time
import datetime

'''
    IMPORTANT
    Edit only the validate_input and collect_events functions.
    Do not edit any other part in this file.
    This file is generated only once when creating the modular input.
'''

def validate_input(helper, definition):
    """Implement your own validation logic to validate the input stanza configurations"""
    # This example accesses the modular input variable
    information_type = definition.parameters.get('information_type', None)
    #正常な値のリスト
    valid_values=['current','archive','both']
    if information_type in valid_values:
        pass
    else:
        raise ValueError("Value for information type %s was not valid" % information_status)

def collect_events(helper, ew):
    #Implement your data collection logic here
    import urllib.request
    import json

    #イベントの書き込み
    def write_events(information_type, entries):
        for entry in entries:
            #付加情報をキー'added_information'に格納する
            # information_type: archive/currentのどちらなのかの情報
            # date-str: 日時情報を文字列に変換した情報
            entry['added_information'] = {
                'information_type': information_type,
                'date_str': datetime.datetime.fromtimestamp(int(entry['date'])).strftime('%Y-%m-%d %H:%M:%S')
            }
            #Splunk用イベントデータの作成
            event = helper.new_event(source=helper.get_input_type(), index=helper.get_output_index(), 
                                        sourcetype=helper.get_sourcetype(), data=json.dumps(entry))
            #イベントデータの書き込み
            ew.write_event(event)

    #パラメータの情報の受け取り
    opt_information_type = helper.get_arg('information_type')

    #指定URLへのアクセス
    url = "https://status.aws.amazon.com/data.json"
    req = urllib.request.Request(url)
    try:
        with urllib.request.urlopen(req) as res:
            content = json.loads(res.read().decode('utf8'))
    except urllib.error.HTTPError as e:
        helper.log(e.reason)

    #アーカイブ情報の取得
    if opt_information_type in {'both', 'archive'}: 
        write_events('archive', content['archive'])
    if opt_information_type in {'both', 'current'}: 
        write_events('current', content['current'])

動作テスト・保存

スクリプトを記述したら、動作テストを行うことができます。実際に左側のペインから入力フォームの値を指定し「テスト」ボタンをクリックすると、実行結果の出力が右側「Output」ペインに表示されます。

期待される結果が出力されるようであれば、「保存」ボタンを押すとPythonスクリプトを保存することができます。上記スクリプトの場合、以下が期待する結果となります。

  • 「current」を選んだ場合は現在の障害情報、「archive」を選んだ場合には過去の障害情報、「both」の場合は双方のデータを取得する
  • キー「added_information」に、処理で追加した情報('information_type','date_str')が記録されている

保存すると、アドオンとして利用することができるようになります。Splunkを再起動すると、アドオンがSplunk Appの画面に表示されるようになるはずです。

実際に動かすには、表示されたアドオンのメニューに移動し、定義したパラメータに値を指定したData Inputの定義を作成する必要があります。定義を作成すると、そのパラメータに従った取得処理が実行されるようになります。

サーチしてみると、下記のようにイベントがきちんと記録されていました!

終わりに

以上、簡単ですがSplunk Add-on BuilderによるPythonスクリプトを利用したアドオンの作成方法について紹介しました。Pythonスクリプトを利用することで多彩な処理を実現することができるようになるため、Splunkへのデータ入力をさらに柔軟に行えると思います。Splunkのデータ入力に興味のある方はぜひ試してみてください