ELK Stackでシステム監視 FilebeatでRaspberry Pi Zero WのVolumio楽曲再生ランキング

$ ssh volumio@192.168.2.117
volumio@192.168.2.117's password: 
                       ___                                      
                      /\_ \                        __           
         __  __    ___\//\ \    __  __    ___ ___ /\_\    ___   
        /\ \/\ \  / __`\\ \ \  /\ \/\ \ /' __` __`\/\ \  / __`\ 
        \ \ \_/ |/\ \L\ \\_\ \_\ \ \_\ \/\ \/\ \/\ \ \ \/\ \L\ \
         \ \___/ \ \____//\____\\ \____/\ \_\ \_\ \_\ \_\ \____/
          \/__/   \/___/ \/____/ \/___/  \/_/\/_/\/_/\/_/\/___/ 


        
             Free Audiophile Linux Music Player - Version 2.0

          C 2015 Michelangelo Guarise - Volumio Team - Volumio.org
                               

Volumioの出力するログが変更になったのでこの記事をそのまま真似ることはできなくなっています。

Volumioの内部では一応ログを出力していてどのような操作がされたのかなどを記録している。今回はそのログから楽曲の再生(再生開始)レコードをFilebeatで抽出してLogstashに送信する。Logstashでは送られたメッセージデータを加工して使えるデータにしてからelasticsearchに渡す。最後にKibanaで可視化(ランキング表を作成)するということにした。

volumioのログを覗いてみる

/var/log/volumio.log
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/*ネットラジオ再生直前から再生開始までのログの一部*/
---------------------------- MPD announces state update: player
2018-03-17T03:49:37.582Z - info: ControllerMpd::getState
2018-03-17T03:49:37.587Z - info: ControllerMpd::sendMpdCommand status
2018-03-17T03:49:37.592Z - info: parsing response...
2018-03-17T03:49:37.612Z - info: sending command...
2018-03-17T03:49:37.635Z - info: ControllerMpd::parseState
2018-03-17T03:49:37.641Z - info: ControllerMpd::sendMpdCommand playlistinfo
2018-03-17T03:49:37.652Z - info: sending command...
2018-03-17T03:49:37.665Z - info: parsing response...
2018-03-17T03:49:37.671Z - info: ControllerMpd::parseState
2018-03-17T03:49:37.676Z - info: ControllerMpd::sendMpdCommand playlistinfo
2018-03-17T03:49:37.681Z - info: sending command...
2018-03-17T03:49:37.690Z - info: parsing response...
2018-03-17T03:49:37.696Z - info: parsing response...
2018-03-17T03:49:37.706Z - info: ControllerMpd::parseTrackInfo
2018-03-17T03:49:37.714Z - info: ControllerMpd::parseTrackInfo
2018-03-17T03:49:37.722Z - info: ControllerMpd::pushState
2018-03-17T03:49:37.727Z - info: CoreCommandRouter::servicePushState
2018-03-17T03:49:37.748Z - info: CoreStateMachine::syncState
2018-03-17T03:49:37.752Z - info: CorePlayQueue::getTrack 0
2018-03-17T03:49:37.758Z - info: STATE SERVICE {"status":"play","position":0,"seek":490,"duration":0,"samplerate":"48 KHz","bitdepth":"24 bit","channels":2,"random":false,"updatedb":false,"repeat":false,"isStreaming":false,"title":"francemusiqueclassiqueplus-hifi.mp3","artist":null,"album":null,"uri":"http://direct.francemusique.fr/live/francemusiqueclassiqueplus-hifi.mp3","trackType":"mp3"}

/*下2つはメディアサーバーの楽曲を再生した際のログで不要行を除いたの。*/

/*再生開始時のレコード*/
2018-03-16T13:31:54.201Z - info: STATE SERVICE {"status":"play","position":0,"seek":557,"duration":251,"samplerate":"44.1 KHz","bitdepth":"16 bit","channels":2,"random":false,"updatedb":false,"repeat":false,"isStreaming":false,"title":"ロンリィ・ピーポー II","artist":"太田裕美","album":"太田裕美 BEST COLLECTION","uri":"http://192.168.2.128:32469/object/828f16cd63b069b696c4/file.flac","trackType":"flac"}

/*一時停止時のレコード*/
2018-03-16T13:35:24.015Z - info: STATE SERVICE {"status":"pause","position":0,"seek":210767,"duration":251,"samplerate":"44.1 KHz","bitdepth":"16 bit","channels":2,"random":false,"updatedb":false,"repeat":false,"isStreaming":false,"title":"ロンリィ・ピーポー II","artist":"太田裕美","album":"太田裕美 BEST COLLECTION","uri":"http://192.168.2.128:32469/object/828f16cd63b069b696c4/file.flac","trackType":"flac"}

眺めた感じでは info: STATE SERVICE を含む行だけ抽出すればよいのかしら。
何故か1回の再生操作で再生開始のレコードが2回連続で出力されることがある。その出方の法則がわからない。だからこれを記録しても正しい楽曲再生記録にはならないかも。(しかし、無視して進める)

Filebeatのビルドとインストール

前回のMetricbeatのビルドとインストール手順の「metricbeat」を「filebeat」に置き換えたら同様で出来る。

Filebeatの設定

/etc/filebeat.yml (新規作成または雛形からの変更)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
filebeat.prospectors:
- type: log
  enabled: true
  paths:
    - /var/log/volumio.log
  fields:
    type: volumio
  include_lines: ['info:\sSTATE\sSERVICE']
#↑include_linesの行頭はenabled,paths,fieldsと揃える

filebeat.config.modules:
  path: ${path.config}/beats/file_*.yml    #今回は/etc/beatsには関連ファイル無し
  reload.enabled: false
  reload.period: 10s

output.logstash:
  hosts: ["192.168.2.24:5044"]             #Logstash 本番用ポート5044

logging.level: debug
logging.selectors: ["*"]
logging.to_syslog: false                   #syslogへの出力はOFF
logging.to_files: false                    #ログファイルへの出力はOFF
logging.files:
  path: /var/log
  name: filebeat.log                       #↑trueにすると/var/log/metricbeat.logにログ出力

Filebeatのサービス設定

/lib/systemd/system/filebeat.service (新規作成)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
[Unit]
Description=filebeat
Documentation=https://www.elastic.co/guide/en/beats/filebeat/6.2/index.html
Wants=userwork-online.target
After=network-online.target

[Service]
ExecStart=/usr/local/bin/filebeat -path.home /var/db/beats/filebeat -path.config /etc
Restart=always

[Install]
WantedBy=multi-user.target
# systemctl enable filebeat   #サービス有効化
# service filebeat start      #サービス開始

これでLogstashに渡ったデータは下のようになる。(Logstashのfilter設定無しで)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
{
    "@timestamp" => 2018-03-17T03:58:56.201Z,
        "offset" => 31949,
        "source" => "/var/log/volumio.log",
          "beat" => {
            "name" => "volumio",
        "hostname" => "volumio",
         "version" => "7.0.0-alpha1"
    },
    "prospector" => {
        "type" => "log"
    },
       "message" => "2018-03-17T03:58:52.126Z - info: STATE SERVICE {\"status\":\"play\",\"position\":0,\"seek\":557,\"duration\":251,\"samplerate\":\"44.1 KHz\",\"bitdepth\":\"16 bit\",\"channels\":2,\"random\":false,\"updatedb\":false,\"repeat\":false,\"isStreaming\":false,\"title\":\"雨の音が聞こえる\",\"artist\":\"太田裕美\",\"album\":\"BEST COLLECTION\",\"uri\":\"http://192.168.2.128:32469/object/0badacd7ea823bf2ed65/file.flac\",\"trackType\":\"flac\"}",
          "tags" => [
        [0] "beats_input_codec_plain_applied"
    ],
          "host" => "volumio",
        "fields" => {
        "type" => "volumio"
    },
         "input" => {
        "type" => "log"
    },
      "@version" => "1"
}

メッセージ(message)に含まれる情報をバラバラに分離してその中で欲しい項目だけelasticsearchに渡すことにする。

Logstashの設定

/usr/local/etc/logstash.conf
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
input {
    beats {
        port => 5044
    }
}

filter {

    if [fields][type] == "hoge" {
        #他のフィルタ処理   省略
    }

    #今回の記事用のフィルタ処理 ここから
    if [fields][type] == "volumio" {
        mutate {
            gsub => ["message", "[\"]", ""]   #←messageフィールドの二重引用符を削除
        }
        grok {
            patterns_dir => ["/usr/local/etc/logstash/patterns"]

            match => { "message" => [
                '%{YEAR}-%{MONTHNUM}-%{MONTHDAY}T%{TIME}Z - info: STATE SERVICE \{status:%{DATA:[volumio]status},position:%{DATA},seek:%{DATA},duration:%{DATA},samplerate:%{DATA:[volumio]samplerate},bitdepth:%{DATA:[volumio]bitdepth},channels:%{DATA:[volumio]channels},random:%{DATA},updatedb:%{DATA},repeat:%{DATA},isStreaming:%{DATA:[volumio]isStreaming},title:%{DATA:[volumio]title},artist:%{DATA:[volumio]artist},album:%{DATA:[volumio]album},uri:%{DATA:[volumio]uri},trackType:%{DATA:[volumio]trackType}\}',
                '%{YEAR}-%{MONTHNUM}-%{MONTHDAY}T%{TIME}Z - info: STATE SERVICE \{status:%{DATA:[volumio]status},position:%{DATA},seek:%{DATA},duration:%{DATA},samplerate:%{DATA:[volumio]samplerate},bitdepth:%{DATA:[volumio]bitdepth},channels:%{DATA:[volumio]channels},random:%{DATA},updatedb:%{DATA},repeat:%{DATA},isStreaming:%{DATA:[volumio]isStreaming},title:%{DATA:[volumio]title},artist:%{DATA:[volumio]artist},album:%{DATA:[volumio]album},uri:%{DATA:[volumio]uri}\}'
                ]
            }
            remove_field => ["message", "beat", "tags", "source"]
        }
    }
    #今回の記事用のフィルタ処理 ここまで
}

output {
    #stdout { codec => rubydebug }
    elasticsearch { hosts => [ "localhost:9200" ] }
}

メッセージ(message)は中の各項目名と各値がダブルクォーテーションで括られているが、数値やtrue, falseなどは括られない。ここまでは良いのだが、文字列が入る筈の欄がnullだったりするとlogstashのmatchではダブルクォーテーションの有無の不一致でも簡単にマッチしなくなってしまうので非常に扱いづらい。そこで、ダブルクォーテーションは除去してからmatchさせることにした。
初稿ではstatusがstopのときのmatch条件が抜けていた。Volumioのログでstatus:stopでは何故かtrackTypeだけ出力しないのでtrackType入りのmatch条件では不適合になる。

Logstashの出力例

Volumio Selectionに入っているネットラジオ France Musique Classique Plusを再生してみた。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
{
          "host" => "volumio",
        "fields" => {
        "type" => "volumio"
    },
        "offset" => 494960,
       "volumio" => {
             "artist" => "null",
          "trackType" => "mp3",
        "isStreaming" => "false",
             "status" => "play",
         "samplerate" => "48 KHz",
           "channels" => "2",
           "bitdepth" => "24 bit",
              "title" => "francemusiqueclassiqueplus-hifi.mp3",
              "album" => "null",
                "uri" => "http://direct.francemusique.fr/live/francemusiqueclassiqueplus-hifi.mp3"
    },
         "input" => {
        "type" => "log"
    },
    "prospector" => {
        "type" => "log"
    },
      "@version" => "1",
    "@timestamp" => 2018-03-17T09:19:52.729Z
}

アーティストがnullなのは解るとしてisStreamingがfalseってネットラジオはストリーミングじゃないのかしら?(改めて見たらアレっ?)

メディアサーバーから楽曲再生してみた。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
{
          "host" => "volumio",
        "fields" => {
        "type" => "volumio"
    },
        "offset" => 487961,
       "volumio" => {
             "artist" => "太田裕美",
          "trackType" => "flac",
        "isStreaming" => "false",
             "status" => "play",
         "samplerate" => "44.1 KHz",
           "channels" => "2",
           "bitdepth" => "16 bit",
              "title" => "雨の音が聞こえる",
              "album" => "太田裕美 BEST COLLECTION",
                "uri" => "http://192.168.2.128:32469/object/0badacd7ea823bf2ed65/file.flac"
    },
         "input" => {
        "type" => "log"
    },
    "prospector" => {
        "type" => "log"
    },
      "@version" => "1",
    "@timestamp" => 2018-03-17T09:19:52.685Z
}

Kibanaで楽曲再生ランキング表作成

新しいフィールドが増えているがインデックスを更新しないとそれが反映されない。Kibanaの左列メニューの (Management)からIndex Patternsを選択し、右上の (Refresh)を押す。

FilebeatでVolumioの楽曲再生ランキング作成 1
Discover(Search)で確認する。とりあえず、hostでvolumioのホスト、fields.typeでvolumioという2つの条件で絞ってみた。
保存する必要はない。

FilebeatでVolumioの楽曲再生ランキング作成 2
左列でVisualizeを選択。 (新規作成)をクリック。
Data Tableを選択する。From a New Search, Select Indexのlogstash-* (或いはvolumioのデータが入っている筈のインデックス)を選択。
左上の方にあるAdd a filterで絞り込条件を追加する。

[host] [is][volumioのホスト名]
[volumio.status] [is] [play]

選択或いは入力して[Save]を押す。本当はさらに先にLogstashのFilterで分離したisStreamingでストリーミングの有無で絞り、2つのVisualizeを作成するつもりだったが、試した限りではisStreamingがtrueになることがないので絞っていない。
MetricsはMetric:Countにする。(初期値なので触らない)
今回はBucketsを3つ作成。3つともSplit Rowsにする。(好みで作れば良い)

1つめのSplit Rows:
Aggregation: Terms、 Fields: volumio.title.keword、 Order By: metric:Count

2つめのSplit Rows:
Aggregation: Terms、 Fields: volumio.artist.keword、 Order By: Terms

3つめのSplit Rows:
Aggregation: Terms、 Fields: volumio.album.keword、 Order By: Terms

任意の名称で保存する。

FilebeatでVolumioの楽曲再生ランキング作成 3
ダッシュボードに貼ったらこんな感じ。(左下の表)

関連記事:

ELK Stackでシステム監視 MeticbeatでRaspberry Pi Zero WのVolumioを監視

$ ssh volumio@192.168.2.117
volumio@192.168.2.117's password: 
                       ___                                      
                      /\_ \                        __           
         __  __    ___\//\ \    __  __    ___ ___ /\_\    ___   
        /\ \/\ \  / __`\\ \ \  /\ \/\ \ /' __` __`\/\ \  / __`\ 
        \ \ \_/ |/\ \L\ \\_\ \_\ \ \_\ \/\ \/\ \/\ \ \ \/\ \L\ \
         \ \___/ \ \____//\____\\ \____/\ \_\ \_\ \_\ \_\ \____/
          \/__/   \/___/ \/____/ \/___/  \/_/\/_/\/_/\/_/\/___/ 


        
             Free Audiophile Linux Music Player - Version 2.0

          C 2015 Michelangelo Guarise - Volumio Team - Volumio.org
                               

以前にNanoPi NEO2用にFilebeatをビルドする記事を書いたが、同じやり方でMetricbeatをビルドできるかと思ったらNaniPi NEO2 (armbian)ではエラーが出てビルドできなかった。
Goに詳しくなくてエラーメッセージからは何が悪いのか推測できなかったのでNaniPi NEOではなくデスクトップPCとして常用している Gekko Linux (openSUSE亜種)でビルドすることにした。ビルドにあたりGo (golang)とgitをインストールした。

なお、記事の題名にはVolumioと書いているが実はMetricbeatがVolumioと関係する部分は全く無い。armまたはarm64のLinuxなら殆ど動くかと。(次のFilebeatの記事でVolumioが関係する予定)

$ printenv | grep GOPATH        #環境変数を表示
$ export GOPATH=$HOME/go        #GOPATHが未設定の場合に実行
                                #またはGOPATHが2つ以上のPathならホームディレクトリ下のgoを再指定

# arm用(RPi0Wなど)の作業ディレクトリの準備例 (ビルド環境が64bitのLinuxでgo1.9の場合)
$ sudo mkdir /usr/lib64/go/1.9/pkg/linux_arm
$ sudo chmod 777 /usr/lib64/go/1.9/pkg/linux_arm

# arm64用 (NanoPi NEO2など)の作業ディレクトリの準備例 (ビルド環境が64bitのLinuxでgo1.9の場合)
$ sudo mkdir /usr/lib64/go/1.9/pkg/linux_arm64
$ sudo chmod 777 /usr/lib64/go/1.9/pkg/linux_arm64

$ mkdir -p ${GOPATH}/src/github.com/elastic
$ cd ${GOPATH}/src/github.com/elastic
$ git clone https://github.com/elastic/beats.git
$ cd ./beats/metricbeat

#ビルド
$ GOOS=linux GOARCH=arm make            #arm用 (RPi0Wなど)
# or
$ GOOS=linux GOARCH=arm64 make          #arm64用 (NanoPi NEO2)など

#完成したmetricbeatをとりあえずホームディレクトリにコピー
$ cp -p metricbeat ~/
$ cp metricbeat.yml ~/

ホームディレクトリに置いた2つのファイル(metricbeat.ymlは正直どうでもいい)をRPi0WやNanoPi NEO2などに何らかの方法でコピーする。
もしもvolumioからftpを使うなら先に apt-get install ftp しておく。

Volumioのホスト側の設定

ここからはMetricbeatをインストールするホスト、Volumio(Raspbian?)が動くRPi0Wやarmbianの動くNanoPi NEO2の側の設定。

metricbeatを /usr/local/bin/ に置く。この記事では /usr/local/bin/としたが、任意の場所で可。ただし、下のサービス設定ファイル内のpathもそれに合わせること。

# mv metricbeat /usr/local/bin/
# chmod +x /usr/local/bin/metricbeat        #実行権限を付けるのを忘れずに
# mv metricbeat.yml /etc/                   #これはどうでもいい
# mkdir /etc/beats
# mkdir /var/lib/metricbeat
# metricbeat version                        #バージョン確認
metricbeat version 7.0.0-alpha1 (arm), libbeat 7.0.0-alpha1 [5426852a0971bb148b6ca60590ee47f68e6eaf24 built 2018-03-16 02:37:25 +0000 UTC]

Metricbeatのサービス設定

/lib/systemd/system/metricbeat.service (新規作成)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
[Unit]
Description=metricbeat
Documentation=https://www.elastic.co/guide/en/beats/metricbeat/6.2/index.html
Wants=userwork-online.target
After=network-online.target

[Service]
ExecStart=/usr/local/bin/metricbeat -path.home /var/db/beats/metricbeat -path.config /etc
Restart=always

[Install]
WantedBy=multi-user.target
/etc/metricbeat.yml (変更または新規作成)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
metricbeat.config.modules:
  path: ${path.config}/beats/metric_*.yml   #標準的な構成と違うので注意        
  reload.enabled: false

processors:
  - drop_fields:
      fields: ["metricset.rtt", "beat.name", "beat.version"]
                                     #全般の出力不要なフィールド名を指定
output.logstash:
  hosts: ["192.168.2.24:5043"]       #テスト用Logstash 192.168.2.24  ポート5043
#  hosts: ["192.168.2.24:5044"]      #本番用Logstash 192.168.2.24  ポート5044

logging.level: debug
logging.selectors: ["*"]
logging.to_syslog: false
logging.to_files: false              #動作確認段階ではtrueにしておく
logging.files:
  path: /var/log
  name: #↑trueにすると/var/log/metricbeat.logにログ出力

ログの出力は動作確認時だけ。ファイルが肥大化するので通常稼働時には出力させない。

/etc/beats/metric_system.yml (新規作成)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
- module: system
  metricsets: ["cpu"]
  cpu.metrics: [percentages, normalized_percentages, ticks]
  enabled: true
  period: 60s

- module: system
  metricsets: ["filesystem"]
  enabled: true
  period: 60s

- module: system
  metricsets: ["fsstat"]
  enabled: false            #←無効にした
  period: 60s

- module: system
  metricsets: ["load"]
  enabled: true
  period: 60s

- module: system
  metricsets: ["memory"]
  enabled: true
  period: 60s

- module: system
  metricsets: ["network"]
  enabled: true
  period: 60s

- module: system
  metricsets: ["process"]
  enabled: true
  period: 60s
  processors:
  - drop_fields:            #↓(MetricSet別) processで出力しないフィールド名を指定
      fields: ["system.process.cmdline", "system.process.cwd","system.process.cpu", "system.process.pid", "system.process.ppid", "system.process.pgid", "system.process.username", "system.process.fd"]

- module: system
  metricsets: ["uptime"]
  enabled: true
  period: 60s
# systemctl enable metricbeat   #サービス有効化
# service metricbeat start      #サービス開始

Kibanaでグラフ化

Vilumioに仕掛けたMetricbeatから送信される情報をLogstashで受け取るが、Metricbeatのデータは加工無しでいける筈。
で、Kibanaの側だが、すでに作成済みの推移データを見るためのVisualizeはTimeLionあたりが使われているかと思われるので、既存の他のホストのVisualizeを開いてクエリーのホスト名だけあるいは単位周りを少し修正して新しいVisualizeとして保存すれば1つのVisualizeあたり1分もかからずに作成できる筈。まさか何でもかんでもSearchオブジェクトを保存してそれを使ってArea Chart等のVisualizeを作成してないよね?

Kibanaの画面でVolumioを監視
ダッシュボードに貼り付けるとこんな感じ。

ということで、Volumioが動いているRaspberry Pi Zero WをELK Stackで監視できるようになった。
Metricbeatで1分に1度の頻度で情報を取得するように設定したが、Volumioで音楽再生中に1分ごとに音が途切れるとかそういうのは如何にRaspberry Pi Zero Wが非力とはいえどさすがに無いみたい。もしかしたら世の中にたくさんいらっしゃるらしい人の能力を遥かに超えた耳を持つオーディオマニアさんなら ゆらいでない音のゆらぎ、途切れてない音の途切れ、ありもしない音の違いをはっきり聞き分けられるのかもしれないけど。

関連記事:
Up