🐨コアラでもわかるSplunkシリーズ　状態の変化を数える

やあ、みんな　:koala:だよ

:koala:いつもの作者は「:koala:の記事もわかりづらいですね」と言われて凹んだので、僕が呼ばれたよ。よろしくね。 

:koala:今回は単純に_status_が**ON**と**OFF**した数を数えたいだけなんだ。

:koala:題名はいつもの作者が考えているから難しめだよ。

Macosxで動かしているので、WindowsやLinuxの人はディレクトリやフォルダを読み替えてね。

#今回使うもの
<img width="1392" alt="スクリーンショット 2020-05-11 20.31.59.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130729/3592e332-a36f-139b-ab44-b1e2c997f313.png">
:koala:今回は、この起動した時のそのままの画面を使用するよ。
真っ黒い背景にSPL（エス・ピー・エル）を書いていくので、それを<font color="red">**赤枠**</font>の中、`ここにサーチを入力．．．`と書いているところにコピー＆ペーストしてもらって、🔍をクリックすると動くよ

:koala:時間:`過去２４時間`やモード:`スマートモード`は変更しないでね

#今回使うSPL
```sql:base.spl
index=_internal sourcetype=splunkd name=management thread=tcp* OR thread=tail*
| eval status=if(ratio>0,"OFF","ON")
| bin _time span=1h
| stats count by _time status thread
| fields - count
```

| _time | status | thread |
|:--|:--|:--|
| 2020-05-11 10:00 | OFF | tailreader0 | 
| 2020-05-11 10:00 | OFF | tcplistener | 
| 2020-05-11 10:00 | OFF | tcpouteloop | 
| 2020-05-11 10:00 | OFF | tcppqreaderthread | 
| 2020-05-11 10:00 | ON | tailreader0 | 
| 2020-05-11 10:00 | ON | tcpchannelthread | 
| 2020-05-11 11:00 | OFF | tailreader0 | 
| 2020-05-11 11:00 | OFF | tcplistener | 
| 2020-05-11 11:00 | OFF | tcpouteloop | 
| 2020-05-11 11:00 | OFF | tcppqreaderthread | 
| 2020-05-11 11:00 | ON | tailreader0 | 
| 2020-05-11 11:00 | ON | tcpchannelthread | 
| 2020-05-11 12:00 | OFF | ... |

:koala:多分どこでも動くSPLで無理やり状態の変化を作り出してみたよ。

:koala:`stats`で作っているのは、[前回のtimechartとuntableとstats](https://qiita.com/toshikawa/items/8fa44753bc8f2a4c9cb0#timechart%E3%81%A8untable%E3%81%A8stats)を参考にしてね。

:koala:実際はこんなに頻繁に状態って変わらないよね。

:koala:あと、`timechart`で作ったときは`untable`してこの形にしてね。

##一つだけ取り出して確認する
```sql:select_one_value.spl
index=_internal sourcetype=splunkd name=management thread=tcp* OR thread=tail*
| eval status=if(ratio>0,"OFF","ON")
| bin _time span=1h
| stats count by _time status thread
| fields - count
| where thread="tailreader0"
```

| _time | status | thread |
|:--|:--|:--|
| 2020-05-11 10:00 | OFF | tailreader0 |
| 2020-05-11 10:00 | ON | tailreader0 |
| 2020-05-11 11:00 | OFF | tailreader0 |
| 2020-05-11 11:00 | ON | tailreader0 |
| 2020-05-11 12:00 | OFF | tailreader0 |
| 2020-05-11 13:00 | OFF | tailreader0 |
| 2020-05-11 13:00 | ON | tailreader0 |
| 2020-05-11 14:00 | OFF | tailreader0 |
| 2020-05-11 14:00 | ON | tailreader0 |
| 2020-05-11 15:00 | OFF | tailreader0 |
| 2020-05-11 15:00 | ON | tailreader0 |
| 2020-05-11 16:00 | OFF | tailreader0 |
| 2020-05-11 16:00 | ON | ... |

:koala: `where`を使って_thread_の一つを指定してみたよ。

:koala: **`search`と違って`"`は必須だよ。**

#状態の変化を数える
```sql:change_status.spl
index=_internal sourcetype=splunkd name=management thread=tcp* OR thread=tail*
| eval status=if(ratio>0,"OFF","ON")
| bin _time span=1h
| stats count by _time status thread
| fields - count
| streamstats current=f last(status) as prev by thread
| eval changed=nullif(status,prev)
| streamstats count(changed) as session by thread
| where thread="tailreader0"
```

| _time | status | thread | changed | prev | session |
|:--|:--|:--|:--|:--|--:|
| 2020-05-11 10:00 | OFF | tailreader0 | OFF |   | 1 |
| 2020-05-11 10:00 | ON | tailreader0 | ON | OFF | 2 |
| 2020-05-11 11:00 | OFF | tailreader0 | OFF | ON | 3 |
| 2020-05-11 11:00 | ON | tailreader0 | ON | OFF | 4 |
| 2020-05-11 12:00 | OFF | tailreader0 | OFF | ON | 5 |
| 2020-05-11 13:00 | OFF | tailreader0 |   | OFF | 5 |
| 2020-05-11 13:00 | ON | tailreader0 | ON | OFF | 6 |
| 2020-05-11 14:00 | OFF | tailreader0 | OFF | ON | 7 |
| 2020-05-11 14:00 | ON | tailreader0 | ON | OFF | 8 |
| 2020-05-11 15:00 | OFF | tailreader0 | OFF | ON | 9 |
| 2020-05-11 15:00 | ON | tailreader0 | ON | OFF | 10 |

:koala: いきなりばばばと作っちゃった。

:koala: _session_の**5**に注目してね。_status_が**OFF**から変化していないから、数が増えていないよね。

##直前の値を表示する。

:koala:さっきのSPLの中に`| streamstats current=f last(status) as prev by thread`ってあったよね。

:koala: これは、直前の値を表示する定番のSPLだよ。[Splunk>docs](https://docs.splunk.com/Documentation/Splunk/latest/SearchReference/Streamstats)にも載っているよ。

:koala:`autoregress`を知っているなら違いを確かめて欲しいな。

##フィールドを比較して、一致した場合NULL値とする。
:koala:中の人が`nullif`が好きなので、`| eval changed=nullif(status,prev)`なんてことをしているよ。

:koala:[Splunk>docs](https://docs.splunk.com/Documentation/Splunk/latest/SearchReference/CommonEvalFunctions)には`この関数は，フィールドを比較するために利用されます．この関数はXとYの2つの引数を取り、X = Yの場合はNULLを返します。`と書いてあるね。

:koala:_status_と_prev_が一緒、つまり_status_が変化していないときはNULLにして、変化した場合は_status_の値を入れているんだ。

:koala:これで**変化した時だけ値が入っている**ことになるよね。

##変化を数える
:koala:さっき下準備をしたので、あとは数えるだけだよ。

:koala:`where`しているのはわかりやすくするためなので、外してもらえると、_tread_毎全部を数えているよ。

#停止期間を数える
```sql:duration.spl
index=_internal sourcetype=splunkd name=management thread=tcp* OR thread=tail*
| eval status=if(ratio>0,"OFF","ON")
| bin _time span=1h
| stats count by _time status thread
| dedup _time thread
| fields - count
| streamstats current=f last(status) as prev by thread
| eval changed=nullif(status,prev)
| streamstats count(eval(changed="OFF")) as session by thread
| stats min(_time) as _time range(_time) as duration list(changed) as changed_list first(status) as status by thread session
| where thread="tcpchannelthread" AND status!="ON"
```

| thread | session | _time | duration | changed_list | status |
|:--|--:|:--|--:|:--|:--|
| tcpchannelthread | 1 | 2020-05-11 14:00 | 18000 | OFF ON | OFF |
| tcpchannelthread | 2 | 2020-05-11 20:00 | 21600 | OFF ON | OFF |
| tcpchannelthread | 3 | 2020-05-12 03:00 | 28800 | OFF | OFF |

:koala:よく停止期間を数えたいと思うので作ってみたよ。

:koala:**OFF**から**ON**になった期間は数えることができているよね。

:koala:`| streamstats count(eval(changed="OFF")) as session by thread`で**OFFからONになるまでを一塊にしているんだ**

:koala:**塊にする最初の状態（今回だとOFFだね）から数えてあげると、ちょうどよくなるよ**

:koala:`first(status)`を入れているのは一番最初が**ON**なものを除外するためだよ。

:koala:あと、_changed_list_をあえて作っているのは、確認のため。**こんな感じで、結果をわかりやすくするフィールドは作ってみるのがいいよ。**

:koala:あとでいらないのは`fileds -`すればいいしね。

#まとめ
:koala:いろいろと話してきたけど、大丈夫かな？

:koala:状態の変化を数えるには`streamstats`を使うと便利だよ。

:koala:ただ、ログに書いてあることじゃなくて、ログからわかることを数えているから少し難しいかな

:koala:`streamstats`はもっといろいろなことができるんだけど、これ以上話すと👹が出てきそうなのでやめとくね。

:koala:じゃ、またね〜

:koala:リクエストまってま〜す