じゅのぶろ

社内SEが自宅でSOC/CSIRTするために色々頑張っていきたいブログ 画像が見れない場合はjavascriptを有効にするかデスクトップからご覧下さい。

Splunkでマルチバリューフィールドを扱う (eval関数編)

以前の記事でマルチバリューコマンドをご紹介しました。

jnox.hatenablog.com

今回はそれに関連したマルチバリューを扱う際に役立つeval関数コマンド11種類をご紹介します。

  1. mvappend
  2. mvcount
  3. mvdedup
  4. mvfilter
  5. mvfind
  6. mvindex
  7. mvjoin
  8. mvrange
  9. mvsort
  10. mvzip
  11. split

mvappend

mv(multi value)として値を特定のフィールドに追加(append)するコマンドです。
Syntaxはこちら

... | eval mv_append=mvappend(X,...)

initial_values、last_valuesの値、文字列「middle value」をfullNameというフィールドにマルチバリューでまとめることができました。
mvappendの実行結果

使用したSPL

| makeresults |  fields - _time
| eval initial_values="initial value"
| eval last_values="last value"
| eval fullName=mvappend(initial_values, "middle value", last_values)

mvcount

mv(multi value)の個数を数える(count)コマンドです。
Syntaxはこちら

... | eval n=mvcount(multifield)

マルチバリューの数をカウントした結果です。
文字列「initial value」と空文字「」は1としてカウントされました。
NULLはappendもcountもされませんでした。
mvcountの実行結果

使用したSPL

| makeresults | fields - _time 
| eval initial_values="initial value" 
| eval middle_values="" 
| eval last_values=NULL 
| eval fullName=mvappend(initial_values, middle_values, last_values) 
| eval mv_initial_values_count=mvcount(initial_values) 
| eval mv_middle_values_count=mvcount(middle_values) 
| eval mv_last_values_count=mvcount(last_values) 
| eval mv_fullName_count=mvcount(fullName)

mvdedup

mv(multi value)の値のうち、重複を排除(deduplicate)するコマンドです。
Syntaxはこちら

... | eval s=mvdedup(mvfield)

initial_values、middle_values、last_valuesの値を全て文字列「initial value」とし appendした結果をfullNameに、そこからさらにmvdedupした結果をdedup_fullNameにしました。
重複が排除されていることがわかります。
mvdedupの実行結果

使用したSPL

| makeresults | fields - _time 
| eval initial_values="initial value" 
| eval middle_values="initial value"
| eval last_values="initial value"
| eval fullName=mvappend(initial_values, middle_values, last_values)
| eval dedup_fullName=mvdedup(mvappend(initial_values, middle_values, last_values))

mvfilter

mv(multi value)からブール式でtrueになる場合の値のみをマルチバリューとしてフィルタするコマンドです。
Syntaxはこちら

`... | eval n=mvfilter(X)``

Xはevalのboolean functionです (参考)。
例:`... | eval n=mvfilter(match(<フィールド名>, "<正規表現>"))

プロキシログのユーザエージェントをvalues()コマンドでマルチバリューにしました。
その後mvfilterでMozillaから始まるユーザエージェントのみをフィルタしています。
mvfilterの実行結果

使用したSPL

index=squid 
| stats values(user_agent) as user_agent
| eval mv_filter=mvfilter(match(user_agent, "^Mozilla.*"))
| table mv_filter

mvfind

mv(multi value)のフィールドから正規表現に一致したインデックスを見つける(find)コマンドです。
Syntaxはこちら

... | eval n=mvfind(mymvfield, "正規表現")

mvfindの結果はindex番号を返すだけなので次に説明するmvindexと使うと効果的です。
今回は結果が32であるのでマルチバリューの32番目にMozillaから始まる値があるということがわかります。
mvfindの実行結果

使用したSPL

index=squid 
| stats values(user_agent) as user_agent
| eval mv_find=mvfind(user_agent, "^Mozilla.*")
| table mv_find

mvindex

mv(multi value)フィールドの何番目(index)の値を取得するか指定するコマンドです。
インデックス番号の始まりは0からです、プログラミング言語の配列操作のイメージに近いと思います。
負の値を使うことで後ろからn番目を指定できます。
Syntaxはこちら

... | eval n=mvindex(MVFIELD,STARTINDEX, ENDINDEX)

先程のmvfindで32番目がmozillaで始まるとわかったので mvindexで32を指定しました。
Mozillaから始まっていることがわかります。
|eval mv_index=mvindex(user_agent,mvfind(user_agent, "^Mozilla.*"))とすればevalの記述は一回ですみます。
mvindexの実行結果

使用したSPL

index=squid 
| stats values(user_agent) as user_agent
| eval mv_find=mvfind(user_agent, "^Mozilla.*")
| eval mv_index=mvindex(user_agent,32)
| table mv_find mv_index

mvjoin

mv(multi value)をシングルバリューに変換するコマンドです。 Syntaxはこちら

... | eval SVFIELD=mvjoin(MVFIELD,STR)

マルチバリューのフィールドをシングルバリューにまとめました。
STRの部分に連結する文字列を記載することができます(今回はORを挟んでみました)。
mvjoinの実行結果

使用したSPL

| makeresults |  fields - _time
| eval initial_values="initial value"
| eval last_values="last value"
| eval fullName=mvappend(initial_values, "middle value", last_values)
| eval mv_join=mvjoin(fullName," OR ")
| table mv_join fullName

mvrange

特定の範囲(range)で連続値のmv(multi value)を生成するコマンドです。
Syntaxはこちら

... | eval mv=mvrange(X,Y,Z)

forの使い方に近いかもしれません。
X(開始条件)からY(終了条件)までZごとに(継続条件)という感じです。
以下が結果の画像ですが、Yは含まないです。
mvrangeの実行結果
また、UNIX時間を使って日付の連続値も生成できます。
| eval mv_range=mvrange(1565277893,1566277893,"1d")
convertコマンドを使うと見やすくなりますね。
mvexpandと組み合わせて色々できそうです。

mvrangeの実行結果2

使用したSPL

| makeresults |  fields - _time
| eval mv_range=mvrange(1,10,1)
| makeresults |  fields - _time
| eval mv_range=mvrange(1565277893,1566277893,"1d")
| convert ctime(mv_range) as mv_range2 timeformat="%F %T"

mvsort

mv(multi value)を並び替える(sort)コマンドです。
Syntaxはこちら

... | eval mv_sort=mvsort(X)

特にオプションも見当たらず、文字列としてソートされるようでした。
sortするならmvexpandしてからsortコマンドを使ったほうが良さそうです。
mvappendの実行結果

使用したSPL

| makeresults |  fields - _time
| eval mv_range=mvrange(2,30,5)
| eval mv_sort=mvsort(mv_range)

mvzip

2つのmv(multi value)フィールドを結合(zip)して一つのmvフィールドにするコマンドです。
第三引数のZには連結する間のデリミタを指定できます。
Syntaxはこちら

... | eval mv_zip=mvzip(X,Y,"Z")

mv_rangeとmv_sortフィールドを連結しmv_zipフィールドとした結果です。
mvzipの実行結果

おまけですが、マルチバリューの数が異なる場合は少ない方に合わせた結果になります。
例. 長さ6と7のmvをmvzipした場合、結果は6になります。
mvzipの実行結果2

使用したSPL

| makeresults |  fields - _time
| eval mv_range=mvrange(2,30,5)
| eval mv_sort=mvsort(mv_range)
| eval mv_zip=mvzip(mv_range, mv_sort," - ")

split

シングルバリューフィールドをデリミタごとに分割しマルチバリューを作成するコマンドです。
makemvのeval関数版といったところです。
Syntaxはこちら

... | eval mv_split=split(X,"Y")

user_agentフィールドからスペース区切りでmv_splitにマルチバリューとして分割した結果です。
splitの実行結果

使用したSPL

index=squid | head 1
| stats count by user_agent
| eval mv_split=split(user_agent," ")
| table mv_split user_agent

おしまい