ELK Stackでシステム監視 Rspamd 1.7系のElasticsearchモジュールを試す

メールサーバの迷惑メール除去ツールRspamd1.7系がリリースされたけど、1.7.0が出てすぐに1.7.1が出た。Fixが多いところを見ると1.7.0はヤバかった?
1.7.0への更新準備を進めていたが、結果的に1.7.0にすることなく1.7.1を入れることになった。
また、1.7系ではElasticsearch moduleが追加されたので試してみた。(Rspamdの統計情報をelasticsearchに送信する機能)

Rspamdを1.7.1に更新

FreeBSDのportsの場合
# portupgrade rspamd-1.6.6_1

これで1.6.6_1から1.7.1に更新できた。

1.7.0への更新準備中にportsを確認していてファイルが1つ足りないと思ったが、1.7.1のportsでは直されていた。

# cp -p /usr/ports/mail/rspamd/work/rspamd-1.7.0/lualib/lua_squeeze_rules.lua /usr/local/share/rspamd/lua/

Rspamdを1.7.1の設定

更新したらコンフィグウィザード コマンドを実行。これはrspamadm configwizardを使ったことがなければ新規でも更新でも。更新の場合はclassifier-bayes.confとredis.confの設定の書き方変更に対応してるっぽい。

# rspamadm configwizard
symbol BAYES_SPAM has registered in multiple groups: statistics and bayes
symbol R_DKIM_REJECT has registered in multiple groups: policies and dkim
symbol R_DKIM_ALLOW has registered in multiple groups: policies and dkim
symbol R_DKIM_TEMPFAIL has registered in multiple groups: policies and dkim
symbol R_SPF_FAIL has registered in multiple groups: policies and spf
symbol R_SPF_DNSFAIL has registered in multiple groups: policies and spf
symbol R_SPF_ALLOW has registered in multiple groups: policies and spf
symbol R_SPF_SOFTFAIL has registered in multiple groups: policies and spf
cannot register delayed condition for DMARC_POLICY_ALLOW
cannot register delayed condition for R_SPF_ALLOW
cannot register delayed condition for R_DKIM_ALLOW
cannot find dependency on symbol FREEMAIL_FROM
cannot find dependency on symbol FREEMAIL_REPLYTO
  ____                                     _
 |  _ \  ___  _ __    __ _  _ __ ___    __| |
 | |_) |/ __|| '_ \  / _` || '_ ` _ \  / _` |
 |  _ < \__ \| |_) || (_| || | | | | || (_| |
 |_| \_\|___/| .__/  \__,_||_| |_| |_| \__,_|
             |_|

Welcome to the configuration tool
We use /usr/local/etc/rspamd/rspamd.conf configuration file, writing results to /usr/local/etc/rspamd
Modules enabled:
Modules disabled (explicitly):
Modules disabled (unconfigured):
Modules disabled (no Redis):
Modules disabled (experimental):
Modules disabled (failed):
Do you wish to continue?[Y/n]: y
Redis servers are not set:
The following modules will be enabled if you add Redis servers:
Do you wish to set Redis servers?[Y/n]: y
Input read only servers separated by `,` [default: localhost]:localhost
Input write only servers separated by `,` [default: localhost]:localhost
Do you have any password set for your Redis?[y/N]: n
Do you have any specific database for your Redis?[y/N]: n
Do you want to setup dkim signing feature?[y/N]:n
You are using an old schema for BAYES_HAM/BAYES_SPAM
Do you wish to convert data to the new schema?[Y/n]:y
Expire time for new tokens  [default: 100d]:100d
converted 107385 elements from symbol BAYES_SPAM
converted 73304 elements from symbol BAYES_HAM
Conversion succeed
File: /usr/local/etc/rspamd/local.d/classifier-bayes.conf, changes list:
new_schema => true
expire => 8640000

File: /usr/local/etc/rspamd/local.d/redis.conf, changes list:
write_servers => localhost
read_servers => localhost

Apply changes?[Y/n]: y
2 changes applied, the wizard is finished now
*** Please reload the Rspamd configuration ***

質問の後に表示されている標準値でよければ値を入力せずに[Enter]でも可。

1.7.0以降は /usr/local/etc/rspamd/override.d/metrics.conf または /usr/local/etc/rspamd/local.d/metrics.conf に、group{ hoge } があると動かないようなので消す。 action { hoge } はmetrics.confではなくactions.confに action {hoge}の hogeだけを書く。

場合によってはどうにもRspamdが起動しないことがあるようだが、既存の /var/db/rspamd または /var/db/redis を退避して新しい/var/db/rspamd, /var/db/redisで試すとか・・・
redisのデータを退避する場合はredisも再起動。

RspamdのElasticsearch moduleの設定

Rspamdに追加になったElasticsearch moduleだが、Rspamd側は簡単っぽい。

/usr/local/etc/rspamd/local.d/elastic.conf (新規作成)
1
2
server = "192.168.2.24:9200";    #elasticsearchのホストとポートを指定
use_https = false;               #非HTTPSの場合(これは効くのか不明)
Rspamd用のテンプレートをelasticsearchに登録する。
% curl -H "Content-Type: application/json" -XPUT 'http://192.168.2.24:9200/_template/rspamd' -d@/usr/local/share/rspamd/elastic/rspamd_template.json
{"acknowledged":true} %
192.168.2.24:9200はelasticsearchが動いているホストとポートとする。返答がacknowledged:trueであれば成功。elasticsearch6系以降では Content-Type: application/json の指定が必須。5系なら不要。
または、上のようにやらずに /usr/local/share/rspamd/elastic/rspamd_template.json の中身をコピーしてKibanaのDev Toolsで1行目に PUT /_template/rspamd と記入して2行目以下にrspamd_template.jsonの中身をペーストして実行でも可。

Rspamd側は設定終わり。Rspamdを再起動しておく。次のingest-geoipプラグインを入れてelasticsearchを再立ち上げしてからの方が良いかも。

elasticsearch側の準備

elasticsearchにingest-geoipプラグインが必要らしい。

# cd /usr/local/lib/elasticsearch/bin
# ./elasticsearch-plugin install ingest-geoip
-> Downloading ingest-geoip from elastic
[=================================================] 100%
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@     WARNING: plugin requires additional permissions     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
* java.lang.RuntimePermission accessDeclaredMembers
* java.lang.reflect.ReflectPermission suppressAccessChecks
See http://docs.oracle.com/javase/8/docs/technotes/guides/security/permissions.html
for descriptions of what these permissions allow and the associated risks.

Continue with installation? [y/N]y
-> Installed ingest-geoip
# chown -R elasticsearch:elasticsearch /usr/local/lib/elasticsearch/plugins

インストールしただけではファイルのオーナーの関係でelasticsearchが動かなくなるようなので変更しておく。
elasticsearchを起動して暫く様子をみてエラーにならないこと。

Rspamdからelasticsearchに送られる情報

 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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
{
  "_index": "rspamd-2018.03.23",
  "_type": "logs",
  "_id": "cfU_UmIBGcJ9bE3-_I6C",
  "_version": 1,
  "_score": null,
  "_source": {
    "rspamd_meta": {
      "rcpt": [
        "foobar@example.com"
      ],
      "geoip": {
        "continent_name": "North America",
        "city_name": "Albuquerque",
        "country_iso_code": "US",
        "region_name": "New Mexico",
        "location": {
          "lon": -10*.**07,
          "lat": 3*.*091
        }
      },
      "header_to": [
        "<foobar@example.com>"
      ],
      "header_subject": [
        "Google earth flight simulator controls"
      ],
      "ip": "64.***.***.212",
      "message_id": "3xu57y1dn6v3wyax-hgtchh9afoztlxi4-f20e3e91@*****.us",
      "header_date": [
        "Fri, 23 Mar 2018 04:43:39 -0500"
      ],
      "qid": "DC810177F4DA",
      "symbols": [
        {
          "score": -0.01591,
          "options": [
            "country: US(-0.08)"
          ],
          "name": "IP_SCORE",
          "group": "reputation"
        },
        {
          "score": 2,
          "options": [
            "212.***.***.64.zen.spamhaus.org : 127.0.0.3"
          ],
          "name": "RBL_SPAMHAUS_CSS",
          "group": "rbl"
        },
        {
          "score": 0.917949,
          "options": [
            "95.9%"
          ],
          "name": "R_PARTS_DIFFER",
          "group": "body"
        },
Spam判定要因部分
大量すぎるので中略
      ],
      "score": 36.406363,
      "header_from": [
        "\"Google Flight Simulator\" <virtualpilot@*****.us>"
      ],
      "action": "add header",
      "from": "8678-1348-4061019793-2725-foobar=example.com@mail.*****.us",
      "webmail": false,
      "is_local": false,
      "asn": {
        "country": "US",
        "ipnet": "64.***.***.0/24",
        "asn": "63018"
      },
      "user": "unknown",
      "direction": "Inbound"
    },
    "@timestamp": "1521798350369.5"
  },
  "fields": {
    "@timestamp": [
      "2018-03-23T09:45:50.369Z"
    ]
  },
  "sort": [
    1521798350369
  ]
}

省略と伏せ字とメールアドレスを置換した部分以外はそのままのデータ。
迷惑メールの情報だけがelasticsearchに送られるのかと思ってたら全メールの情報みたい。メール1件あたりのデータが多いのでメールが大量に届いたときが怖い。これは今後Rspamdのelastic.confで送信する情報を絞れるようにして欲しいところ。

Rspamdの情報をKibanaで表示。

うちの環境ではRspamdからelasticsearchに最初のデータが流れ始めるまで何故かとても時間がかかる。サーバーにメールが届くの関係なく数十分〜数時間?一度流れ始めれば問題ないようだが。
データが流れ始めたらおそらくrspamd-yyyy.mm.dd(←今日の日付)というインデックスでデータが溜まり始めている筈。Kibanaではインデックスパターンを登録してやらないと使えないデータなので左列メニューの (Management)からIndex Patternsを選択し、 Index Patterns をクリック、 左上の方の Create Index Pattern をクリック。
インデックスパターンには rspamd-* を指定、右の[ Next step ]ボタンを押す。タイムスタンプとしては@timestampを選択して作成。
なお、rspamd-yyyy.mm.dd(←今日の日付)というインデックスが作成されてそこに1件以上のデータが存在しないとインデックスパターンは作成できないのでデータが流れていることを確認してからとなる。

Rspamd付属のKibanaダッシュボード

Rspamd1.7.1に付属のKibanaダッシュボード&VisualizeのJsonファイル (/usr/local/share/rspamd/elastic/kibana.json)はかなり酷い造り。
雑なことにかけては定評のある「がとらぼ」の中の人から見ても凄い雑。というか、作りかけなのかしら?
部品のIDは合ってないわ、足りないわで逆に苦労するので使わない方が良さげ。おそらく自分で作る方が早い。

Rspamd付属のダッシュボードテンプレートを表示
いちおう、Rspamd付属のJsonファイルから直せる範囲で修正してKibanaで表示してみた。1つ足りない部品(Visualize)はそもそも何用なのか不明。
地図2つが同じ内容(地点)を表示してる気が・・・
一番下は数字(メール受信数)の下に受信者のメールアドレスが表示されているのをボカしている。

他人が作ったこういうのは何のデータから何を意図して表示しているのかすぐに解らないので個人的には好きじゃない。出来上がりがショボくても構わないから試行錯誤しながら自分で作りたい。もしくは他の人のを見るなら参考としてのレシピ程度?

2018年3月24日追記:

1つだけ作ってみた。受信メールのスループット、要するに受信したときのアクション別グラフ。RspamdのWebUIだとRspamd throughputのようなもの。上の画像の円グラフを時系列のグラフにした感じ。

VisualizeのTimelionで作った僅か1行の簡単なもの。
.es(interval=1m, q='rspamd_meta.direction:Inbound', split='rspamd_meta.action:6',  metric='count').bars(stack=false,width=1).label('$1', '^.* > rspamd_meta.action:(.+) > .*')

splitでアクションを6つに分けたのはRspamdのアクション数が6つの認識だから。もし違ったら要変更。

Rspamdの受信メールスループットをTimelionで表示
add headerが迷惑メール。本来はreject(破棄)なのかもだが、うちのメールサーバではrejectは無しで一定の判断基準点を超えたメールにはヘッダに迷惑メールのフラグを付けてスパムフォルダに振り分けるだけにしているのでこんなの。
greylistは機能をオフにしたいんだけど無効にできないので何とかしたい。no actionは非迷惑メールが普通にメールボックスに配送されたもの。

関連記事:

ELK Stackでシステム監視 FilebeatでNTP統計ログ取得 Logstashで加工

Filebeatで幾つかのログを読ませてKibanaで可視化するまでの記事を書いたが、「がとらぼ」の中の人の性格もあってとにかく「雑」これにつきる。
そこで、今回は少し丁寧にLogstashで加工してみる。

今回統計ログを取得するNTPサーバは以前にNanoPi NEOとGPSモジュールで作ったやつ。OSはarmbian (debian: Linux)
NanoPi NEOストレージが信頼性ゼロのmicroSDカードなのでログを書きまくると速攻でぶっ壊れる可能性があるため注意が必要。

NTPサーバの設定

/etc/ntp.conf (統計ログ周りだけ)
1
2
3
4
statsdir  /tmp/
statistics loopstats peerstats
filegen loopstats file loopstats type day enable
filegen peerstats file peerstats type day enable
出力先は/tmpとする。これはNanoPi NEOが動いているarmbianの標準構成では/tmpがtmpfsなので。microSDカードに書き込みまくって壊れるのを防ぐためメモリディスクに書き込ませる。
まともな機材でストレージに余裕があるなら/var/log, /var/log/ntpあたりを指定すれば良いはず。
出力する統計ログはloopstatsとpeerstatsの2つだけとする。
2つのログは日次で日付別ファイルに移すこととする。つまりloopstatsであれば日付が変わったら /tmp/loopstatsが /tmp/loopstats.20180320などの日付別ファイルに移動され、新しい/tmp/loopstatsが出来てそこに統計ログが追記される。ただし、UTCなので日付変更処理は日本時間だと午前9時。
tmpfsの場合は容量が非常に限られるということで、cronでloopstats.20* peerstats.20* を日次で削除するのが望ましい。tmpfsはシステムを再起動したら消えてしまうが、今回は統計ログをelasticsearchに送るので問題ないはず。

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
26
27
28
29
30
31
filebeat.prospectors:
                                    # loopstats
- type: log
  enabled: true
  paths:
    - /tmp/loopstats
  fields:
    type: loopstats
                                    #peerstats
- type: log
  enabled: true
  paths:
    - /tmp/peerstats
  fields:
    type: peerstats

filebeat.config.modules:
  path: ${path.config}/beats/file_*.yml  #今回も使わない
  reload.enabled: false
  reload.period: 60s

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

logging.level: debug
logging.selectors: ["*"]
logging.to_syslog: false
logging.to_files: true
logging.files:
  path: /var/log
  name: filebeat.log
NTPとFilebeatを再起動
# service ntp restart
# service filebeat restart

統計ログの確認

/tmp/peerstats
1
2
3
4
5
58197 5594.402 2001:3a0:0:2006::87:123 9344 0.001557429 0.011391145 0.002156915 0.000110542
58197 5601.391 127.127.20.0 968a 0.000422118 0.000000000 0.000301040 0.000840302
58197 5602.391 127.127.22.0 973a 0.000003027 0.000000000 0.000234952 0.000009770
58197 5617.391 127.127.20.0 968a 0.000395065 0.000000000 0.000270868 0.000847744
58197 5618.391 127.127.22.0 973a -0.000000919 0.000000000 0.000234496 0.000008626
半角スペース区切りで左から
  • 修正ユリウス日
  • 日付変更からの秒数(UTCなので日本時間では9:00からの秒数)
  • 時刻ソース
  • ステータス (16進)
  • 時間のオフセット(秒)
  • 遅延(秒)
  • 分散(秒)
  • RMSジッタ,スキュー (秒)
日時以外の数値データが秒単位というところが嫌らしいところ。ミリ秒単位にしといてくれたら楽なのに。
時刻ソースはNTPサーバを参照していればIPアドレスだが、127.127.*.*はIPアドレスではなくリファレンスクロックアドレス。 例えば127.127.20.0ならGPSのMNEA、127.127.22.0ならGPSのPPSなど。
/tmp/loopstats
1
2
3
4
5
58197 5666.391 0.000001450 -31.896 0.000025471 0.003549 4
58197 5682.391 -0.000004722 -31.897 0.000021987 0.003345 4
58197 5698.391 0.000004691 -31.896 0.000009533 0.003155 4
58197 5714.391 -0.000007993 -31.966 0.000022231 0.024948 4
58197 5730.391 -0.000006354 -31.967 0.000020404 0.023343 4
半角スペース区切りで左から
  • 修正ユリウス日
  • 日付変更からの秒数(UTCなので日本時間では9:00からの秒数)
  • 時間のオフセット(秒)
  • ドリフト, 周波数のオフセット(PPM)
  • RMS ジッタ(秒)
  • RMS 周波数ジッタ(PPM)
  • インターバル(log2秒)
最後をインターバルとしたのは便宜上でclock discipline loop time constantをどう表現して良いか解らなかった。直訳だと「時刻学習のループ時定数」

Logstashの設定

 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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
input {
    beats {
        port => 5044
    }
}

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

    if [fields][type] == "peerstats" {
        grok {
            patterns_dir => ["/usr/local/etc/logstash/patterns"]
            match => {"message" => "%{NUMBER:[temp]julian} %{NUMBER:[temp]pastsec} %{IP:[ntp]source} %{DATA} %{NUMBER:[temp]offset} %{NUMBER:[temp]delay} %{NUMBER:[temp]dispersion} %{NUMBER:[temp]skew}"}
            remove_field => ["message", "beat", "source", "offset", "input"]
        }
        ruby {
            init => "require 'bigdecimal'"
            code => "
                mjd = event.get('[temp]julian').to_i
                psec = event.get('[temp]pastsec').to_i
                ut = (mjd - 40587) * 86400 + psec
                event.set('[temp]unixtime', ut)
                event.set('[ntp]offset', BigDecimal(event.get('[temp]offset')) * 1000)
                event.set('[ntp]delay', BigDecimal(event.get('[temp]delay')) * 1000)
                event.set('[ntp]dispersion', BigDecimal(event.get('[temp]dispersion')) * 1000)
                event.set('[ntp]skew', BigDecimal(event.get('[temp]skew')) * 1000)
            "
        }
        date {
            match => ["[temp]unixtime", "UNIX"]
            remove_field => ["temp", "tags"]
        }
    }

    if [fields][type] == "loopstats" {
        grok {
            patterns_dir => ["/usr/local/etc/logstash/patterns"]
            match => {"message" => "%{NUMBER:[temp]julian} %{NUMBER:[temp]pastsec} %{NUMBER:[temp]offset} %{NUMBER:[temp]drift} %{NUMBER:[temp]jitter} %{NUMBER:[temp]freqjit} %{NUMBER}"}
            remove_field => ["message", "beat", "source", "offset", "input"]
        }
        ruby {
            init => "require 'bigdecimal'"
            code => "
                mjd = event.get('[temp]julian').to_i
                psec = event.get('[temp]pastsec').to_i
                ut = (mjd - 40587) * 86400 + psec
                event.set('[temp]unixtime', ut)
                event.set('[ntp]offset', BigDecimal(event.get('[temp]offset')) * 1000)
                event.set('[ntp]drift', BigDecimal(event.get('[temp]drift')))
                event.set('[ntp]jitter', BigDecimal(event.get('[temp]jitter')) * 1000)
                event.set('[ntp]freqjit', BigDecimal(event.get('[temp]freqjit')) * 1000)
            "
        }
        date {
            match => ["[temp]unixtime", "UNIX"]
            remove_field => ["temp", "tags"]
        }
    }
}

output {
    elasticsearch { hosts => [ "localhost:9200" ] }
}

NTPサーバの統計ログは出力日時が修正ユリウス日(MJD)という殆ど目にしないものと、UTCで日付が変わってからの秒数。こういうの困るよね。
でも、珍しくやる気になったので、このログに記録されている日時をTimeStampとして使いたいと思う。修正ユリウス日と秒数ということなので計算してUnixtimeにしてやれば良さげ。
matchでログから切り分けた修正ユリウス日と秒数は「数値に見える文字列」なのでhoge.to_iで数値に変換してから使う。
Unixtimeは1970年1月1日がエポック。その日は修正ユリウス日で40587。 修正ユリウス日から40587を引いたものに1日の秒数86400を掛ける。それに日付が変わってからの秒数を足す。それがUnixtime。これをLogstashのフィルタのdate{ }で読ませるとタイムスタンプになる。

NTPサーバのログはミリ秒とかPPBで良いと思うんだけど、何故か秒とかPPMとか大きめの単位で出力されるので小数点以下にゼロが並ぶ数値になっている。これをLogstashで数値として扱うために迂闊にconvertでFloat型に変えると困ったことになる。
そこで、rubyプラグインでBigDecimalに読ませる。matchで切り分けした「数値に見える文字列」をそのまま読ませて大丈夫(というか文字列専用)なので都合も良い。さらに幾つかの値は1000を掛けて単位を変更する。

計算した数値は「数値に見える文字列」ではなくなっているので型変換は不要。
また、elasticsearchのタイムスタンプもUTCなのでタイムゾーンによる差分計算も不要。

これでLogstashからelasticsearchに送信されるデータは以下のようになる。

peerstatsの出力例
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
{
  "fields": {
    "type": "peerstats"
  },
  "@timestamp": "2018-03-20T05:01:54.000Z",
  "host": "hoge.localnet",
  "@version": "1",
  "ntp": {
    "delay": 0,
    "dispersion": 0.234296,
    "skew": 0.007733,
    "offset": -0.007931,
    "source": "127.127.22.0"
  },
  "prospector": {
    "type": "log"
  }
}

loopstatsの出力例
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
{
  "fields": {
    "type": "loopstats"
  },
  "@timestamp": "2018-03-20T04:56:50.000Z",
  "host": "hoge.localnet",
  "@version": "1",
  "ntp": {
    "jitter": 0.022946,
    "drift": -31.98,
    "freqjit": 8.763,
    "offset": -0.002991
  },
  "prospector": {
    "type": "log"
  }
}

Kibanaで可視化

例によってフィールドが追加されたらインデックスを更新する。Kibanaの左列メニューの (Management)からIndex Patternsを選択し、右上の (Refresh)を押す。

peerstatsのNMEAをTimelionでグラフ化するならこんな感じ。
1
2
3
4
.es(q='host:hoge.localnet AND fields.type:peerstats AND ntp.source:127.127.20.0', metric='max:ntp.skew').lines(width=1).label('skew ms'),
.es(q='host:hoge.localnet AND fields.type:peerstats AND ntp.source:127.127.20.0', metric='max:ntp.offset').lines(width=1).label('offset ms'),
.es(q='host:hoge.localnet AND fields.type:peerstats AND ntp.source:127.127.20.0', metric='max:ntp.delay').lines(width=1).label('delay ms'),
.es(q='host:hoge.localnet AND fields.type:peerstats AND ntp.source:127.127.20.0', metric='max:ntp.dispersion').lines(width=1).label('dispersion ms')

一応、時刻ソース別で項目を並べるんじゃなくて項目別にして時刻ソースを並べるべきじゃねという意見もあるかというのは認識している。

peerstatsのNMEAをTimelionでグラフ化するならこんな感じ。
1
2
3
4
.es(q='host:hoge.localnet AND fields.type:loopstats', metric='max:ntp.jitter').lines(width=1).label('jitter ms ←').yaxis(1),
.es(q='host:hoge.localnet AND fields.type:loopstats', metric='max:ntp.offset').lines(width=1).label('offset ms ←').yaxis(1),
.es(q='host:hoge.localnet AND fields.type:loopstats', metric='max:ntp.drift').lines(width=1).label('drift ppm →').yaxis(2),
.es(q='host:hoge.localnet AND fields.type:loopstats', metric='max:ntp.freqjit').lines(width=1).label('freq Jitter ppb →').yaxis(2)

一応、左右の振り分けをしているが、気に入らなければ適当に変える。

NTP統計ログをKibanaで可視化
下半分の6つのグラフが今回の記事のNTP統計ログを可視化したもの。左列は上からloopstats、peerstatsのPPS, peerstatsのNMEA。右列はpeerstatsで外部のNTPサーバ(MFEEDのIPv6のサーバ3つ)。
左下のNMEAのグラフの赤線(offset)が規則正しいのこぎり状になっているのはNanoPi NEOにまともな時計が載っていないのにそれに同期しているからかと思われる。

右列の外部NTPサーバのグラフは3つ子かと思うほど同じだが、ネットワーク的に同じ(等距離)で全てMFEEDのサーバなので大幅に違うグラフになる方が変かなと。

と、いうことで、collectdに続いてfilebeatsでもNTPの統計情報を可視化できるようになった。でも、NTPの統計情報はcollectdでやる方が圧倒的に簡単かな・・・

関連記事:
Up