Coyote vs Loadbalancer

The Blog for the Rest of Us

FluentdでYAMAHA RTX1200のログを収集してみる

なんとなく大量に溜め込んでいたYAMAHA RTX1200のログを死蔵するのではなく、勉強に使ってみようということでFluentd + Elasticsearch + Kiabanaでイケイケビューなログビューを作りたいと思った。まずはFluentd編ということで。

使用用途として合ってるのか知らないけれども、うまく行けば自宅に物理で140本を超える可愛い女の子と付き合うゲームの整理にも使えないかなと思う。流石に100本を超えだすとわからないですね。

fluentdの流れ

適当に設定して済ませたかったが、やはり無理だった。なので、fluentdの処理の流れを理解する必要がある。

FluentdにてやってきたデータがどのようにしてDBなどに保存されるかの流れを公式のスライドで示す。

www.slideshare.net わかりやすいような、わかりにくいようなスライドだけども、軽く目を通しておくとこのあとの流れがわかる。

fluentdでは基本的に(1)データを取得(source, where all the data come from?)し(2)fluentdでそのデータに対して何をやらせるか(match, tell fluentd what to do)を記述していく。なお、このデータ取得からデータ処理の間でなにか別の処理をさせる(ex: ホスト名を追記する)といったこともできる(filter, Event processing pipeline)。

source : Where all the data come from

fluentdにデータ(=ログデータ)がどのように入力されるかを記述する。 難しい話ではなく、ログデータのを取得するために純粋にファイルで入力しますか、標準入力ですか、HTTP APIを叩きますかを指定するということ。
例えば、公式ドキュメントに例として以下のようなconfigが示されている。

# Receive events from 24224/tcp
# This is used by log forwarding and the fluent-cat command
<source>
  @type forward
  port 24224
</source>

# http://this.host:9880/myapp.access?json={"event":"data"}
<source>
  @type http
  port 9880
</source>

1個目の sourcefluent-cat という echo '{"message":"hello"}' | fluent-cat debug.log といった形でパイプでfluentdにログを飛ばすことができるコマンドからログを取得するという設定。2個目は http://this.host:9880/myapp.access?json={"event":"data"} というようなAPIエンドポイントをHTTPで叩いてログを取得するという設定。

ここまでで「何をするためにsourceを書くのか」はわかったが「じゃあ、どう書くのか」が実際にコンフィグを書く段になって困ってくる。そこで登場するのが公式ドキュメントの"Plugin Common Parameters"と'Input Plugins" 。基本的に、ここにあるプラグインを使って source を記述していく。

docs.fluentd.org

docs.fluentd.org

例えば、ファイルからログデータを取得するとなると in_tail プラグインを使う。

docs.fluentd.org

<source>
  @type tail
  path /var/log/httpd-access.log
  pos_file /var/log/td-agent/httpd-access.log.pos
  tag apache.access
  <parse>
    @type apache2
  </parse>
</source>

Fluentdではプラグイン@type で指定し、そのあとに各プラグイン依存の設定を行っていくのがお作法感がある。

Routing

ここで、fluentdではルーティング(Routing)という概念が存在する。ネットワークのルーティングと同じ概念。fluentdでは tag, time, record の3つの要素でルーティングを制御していく。これらのうち、最もよく使用する tag のみをここで述べる。 tagは.(ドット)で区切られた文字列でFluentd内部でのルーティングに使用される。例えば myapp.access といったようなフォーマットになる。なお、小文字の英数字とアンダースコアのみを使用することが推奨されている。 このtagに応じて、後ほどのファイル出力などを行う match 節などが実行されていく。

match : Tell fluentd what to do

source にて指定した方法で取得したデータをどう処理するかを tag 毎に指定していく。 この match 節でデータの出力などを行うので、このmatch 節で使用するプラグインをFluentdでは "output plugins" と呼ぶ。じゃあ、説の名前もmatchじゃなくてoutputにしろよ。

docs.fluentd.org

例えば、ファイルに出力したい場合には、 out_file プラグインを使います。 https://docs.fluentd.org/v1.0/articles/output-plugin-overview

<match pattern>
  @type file
  path /var/log/fluent/myapp
  compress gzip
  <buffer>
    timekey 1d
    timekey_use_utc true
    timekey_wait 10m
  </buffer>
</match>

filter : Event processing pipline

sourcematch の間でデータ処理をしたいときは、この filter を使う。だから、やることと節の名前が対応してないって。 フィルタは入力(source)と出力(match/output)の間にいくつでも挟むことができる。

filter で使用できるプラグインは以下の通り。

https://docs.fluentd.org/v1.0/articles/filter-plugin-overviewdocs.fluentd.org

また、parserにもまたプラグインがある。

docs.fluentd.org

例えば、 {"event": "data"} という入力を source で受け取り、 filter{"host_param" : "ホスト名"} を追加して、match でファイルとして出力するコンフィグは以下のようになる。(なお、fluentdはRubyで書かれているので、 Socket.gethostnameRubyのメソッド ref: https://docs.ruby-lang.org/ja/latest/method/Socket/s/gethostname.html )

# http://this.host:9880/myapp.access?json={"event":"data"}
<source>
  @type http
  port 9880
</source>

<filter myapp.access>
  @type record_transformer
  <record>
    host_param "#{Socket.gethostname}"
  </record>
</filter>

<match myapp.access>
  @type file
  path /var/log/fluent/access
</match>

label : bring order to chaos

label節自体はなくても動作するが、tagでの制御が複雑化していってしまうのを防ぐ事ができる。 なお、"label"自体は最初から入っているプラグインのパラメーターであるので、label節を使用する際には @ が頭に必要になってくる。
例えば、source にてtailプラグインで取得したデータを @SYSTEM というタグ付けをしたとするとき、 @SYSTEM というタグがつけられたデータの filtermatch をlabel節を使ってまとめると、以下のような形になる。

<source>
  @type forward
</source>

<source>
  @type tail
  @label @SYSTEM
</source>

<filter access.**>
  @type record_transformer
  <record>
    # ...
  </record>
</filter>
<match **>
  @type elasticsearch
  # ...
</match>

<label @SYSTEM>
  <filter var.log.middleware.**>
    @type grep
    # ...
  </filter>
  <match **>
    @type s3
    # ...
  </match>
</label>

とりあえず試す

既に自宅のRTX1200ではsyslogサーバにログを吐き出させていたので、それを素材にとりあえず試してみる。

インストール方法はドキュメントで様々なやり方を解説しているので、好きなのを選ぶ。

docs.fluentd.org

自分は面倒だったので、Dockerでやることにした。

hub.docker.com

適当に以下のようなファイル構成にしたディレクトリを作成

.
├── fluentd
│   └── fluent.conf
└── log
    ├── rtx1200.log
    └── rtx1200.log.org

2 directories, 3 files

このディレクトリ全体を /docker としてコンテナ内部でマウント docker run -it --rm -v /path/to/docker:/docker fluent/fluentd "/bin/sh"

fluentの公式イメージには最小限の構成しかないので、シェルがshしかない。まぁ、ホストでコンフィグいじったりして、コンテナ内部ではfluentdを実行するだけなので大きな問題はない。(というか、インタラクティブに実行することを想定しているものではない)

fluentdのインストール自体が終わったら、「Kibana|elasticsearchでイケイケでウェイウェイしたい」という気持ちを抑えて、とりあえずは以下の方針のようにシンプルな構成で試す。

結果として、以下のようなコンフィグを fluentd/fluent.conf に記述した。

# YAMAHA RTX
<source>
  @type tail
  @id yamaha_rtx_input_tail
  path /docker/log/rtx1200.log
  <parse>
    @type syslog
  </parse>
  tag yamaha.test.log
</source>

<match yamaha.test.*>
  @type file
  path /docker/yamaha_test.json
  <format>
    @type json
  </format>
</match>

ここでfluentでは実行前に source/path で指定した読み込むログファイルに存在するデータは処理されないので、まずは touch等で空のファイルを作成しておき、以下のコマンドで1回fluentを起動して、初期化処理が終わったら終了させる。 fluentd -c /docker/fluentd/fluent.conf -v その後、実際に読み込ませたいログファイルを置き、再度起動。そうすると、以下のような元のsyslog(抜粋、一部マスク済み)

Jul 22 06:25:23 192.168.12.1 PP[01] Rejected at IN(1012) filter: TCP  ***.***.***.**:***** > ***.***.**.**:****
Jul 22 06:51:52 192.168.12.1 PP[01] Rejected at IN(1030) filter: UDP ***.***.***.**:***** > ***.***.***.**:***** (DNS response)
Jul 22 07:00:00 192.168.12.1 [SCHEDULE] ntpdate ntp.nict.jp syslog
Jul 22 07:00:00 192.168.12.1 2018/07/22 07:00:00  +0second

がfluentdのsyslogプラグインで解析すると、以下のようなJSONになる。

{"host":"192.168.12.1","ident":"PP","pid":"01","message":"TCP ***.***.***.**:***** > ***.***.**.**:****"}
{"host":"192.168.12.1","ident":"PP","pid":"01","message":"UDP ***.***.***.**:***** > ***.***.***.**:***** (DNS response)"}
{"host":"192.168.12.1","ident":"","message":"[SCHEDULE] ntpdate ntp.nict.jp syslog"}
{"host":"192.168.12.1","ident":"2018/07/22","message":"00:00  +0second"}

一応、読み込めてJSON化できていることがわかる。ただ、RTX向けの設定を加えていないので重要な内容(ここでいうとRejectの内容)が message として丸められてしまっている。
このままでは困るので、filter を追加してmessageをもう少し細分化していく。

sourcematchなどの記法はさくらのナレッジがわかりやすく解説しているので、そちらを参照。但し、情報が少し古いのでそこは注意。新旧のdiffはFluentdの公式ドキュメントを参照してほしい(まぁ、でもQiitaやらの記事を見た感じではWARNが出るだけっぽい? ref:td-agentをv1からv2にバージョンアップした話 - Qiita)

knowledge.sakura.ad.jp

tail - Fluentd

file - Fluentd

上記を参考に、方針に沿ってやりたいことを/etc/td-agent/td-agent.confの末尾に書いてみる。結果は以下の感じ。

書き終わったら/etc/init.d/td-agenet configtestで書き損じがないかチェックしてから/etc/init.d/td-agenet restartでリスタート

正しくファイル等が配置されていれば、結果は以下のような感じになる。

fluentdでパースして吐き出せはしたが、だいぶ虚無な感じになっているのがわかる。無ですね。このままではだめそう。
Grokフィルターというものを使う例が以下のサイトにあるが、正規表現ゴリゴリ書きでやってみたいと思う。理由は様々です(主に仕事関係で慣れておきたいので)。面倒な人は素直に既にあるのを利用した方がいいかも(戒め)

mamori017.hatenablog.com

正規表現をゴリゴリ書く

まず、いちいち/etc/td-agent/td-agent.confに書いて云々なんてやってられないので、Fluentdの正規表現エディタを使う。

Fluentular: a Fluentd regular expression editor
なお、このエディタはHerokuの無料枠でやってるらしく、稀に落ちているらしい(ref:Fluentdの正規表現を攻略する - Qiita)。Dockerイメージがあるそうなので、落ちてた場合にはそっちを使う方がいいかも(GitHub - tomohiro/fluentular: Fluentular is a Fluentd regular expression editor)。

書き方の参考には以下のサイトが非常に有用なので、困ったら見てみるべき。

blog.glidenote.com

また、Ruby自体の正規表現の書き方は以下の公式ドキュメントを参考。

docs.ruby-lang.org

日付を取り出す。

まずはログから日付を取り出す。ここで、RTX1200のログにおける日付のフォーマットは以下のような感じになっている。

Jul  1 00:00:00 192.168.12.1 [SCHEDULE] ntpdate ntp.nict.jp syslog
Jul 22 07:00:00 192.168.12.1 [SCHEDULE] ntpdate ntp.nict.jp syslog

まず、日付はログの行頭に現れるので、行頭にマッチする^をつける。
次に月がJun, Julのようにアルファベット3文字の省略表現となっているので、書くべき正規表現Rubyのドキュメントでいうところの単語構成文字\wが3回連続({3})するものを表す \w{3}となる。
そして日が2桁の場合は普通に22のように表すが、1桁の場合には2桁目をスペースでパディングして1のようにしている。そのため、書くべき正規表現はスペース(\s)が0個、あるいは1個({0, 1})のあとに10進数(\d)が1個あるいは2個({1, 2})現れるものを表す\s{0, 1}\d{1, 2}となる。
最後に時間は日付のあとにスペース1個開けてから時間、分、秒ともに十進数2桁(\d{2})が:で区切られて表現されているので、書くべき正規表現\s\d{2}:\d{2}:\d{2}となる(まぁ、\s(\d{2}:){2}\dでもいいけど)

以上をまとめると、結果としてFluentdで書くべき正規表現

^(?<time>\w{3}\s{1,2}\d{1,2}\s\d{2}:\d{2}:\d{2})

となる。

ここで、Fluentdでは時間timeは特別な扱いをされるので(どうされるかはドキュメント参照:https://docs.fluentd.org/v1.0/articles/parser_regexp)、上記で取り出した日付のフォーマットに合わせたRubyのTime formatをtime_formatパラメータとして記載する。実際に書くと、以下のようになるはず。

%b %e %T

実際に先程のエディタに書けると以下のような感じになる(URLパラメータにすべて持たせていてすごい)

http://fluentular.herokuapp.com/parse?regexp=%5E%28%3F%3Ctime%3E%5Cw%7B3%7D%5Cs%7B1%2C2%7D%5Cd%7B1%2C2%7D%5Cs%5Cd%7B2%7D%3A%5Cd%7B2%7D%3A%5Cd%7B2%7D%29&input=Jul++1+01%3A06%3A56+192.168.12.1+LAN1%3A+PORT1+link+up+%281000BASE-T+Full+Duplex%29&time_format=%25b+%25e+%25T

ホスト名を取り出す

まぁ、今回はホスト名ではなくRTXの持っているIPアドレスなのだけれども。syslog的にはこれをホスト名と呼ぶらしいので、それに則ります。
これはIPv4のアドレスなので、日付に比べれば大変楽。大体いつもIPv4正規表現で使ってる以下を使う。

(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)

(ref:IPアドレスの正規表現 [IPv4] – 黒川仁の文具堂ブログ三昧)

Fluentdに記録する際には、このRTXのIPアドレスhost というkeyで登録したいので、結果としてFluentdで書くべき正規表現は今までのと合わせて

^(?<time>\w{3}\s{1,2}\d{1,2}\s\d{2}:\d{2}:\d{2}) (?<host>(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))

となる。

http://fluentular.herokuapp.com/parse?regexp=%5E%28%3F%3Ctime%3E%5Cw%7B3%7D%5Cs%7B1%2C2%7D%5Cd%7B1%2C2%7D%5Cs%5Cd%7B2%7D%3A%5Cd%7B2%7D%3A%5Cd%7B2%7D%29+%28%3F%3Chost%3E%28%3F%3A%28%3F%3A25%5B0-5%5D%7C2%5B0-4%5D%5B0-9%5D%7C%5B01%5D%3F%5B0-9%5D%5B0-9%5D%3F%29%5C.%29%7B3%7D%28%3F%3A25%5B0-5%5D%7C2%5B0-4%5D%5B0-9%5D%7C%5B01%5D%3F%5B0-9%5D%5B0-9%5D%3F%29%29&input=Jul++1+01%3A06%3A56+192.168.12.1+LAN1%3A+PORT1+link+up+%281000BASE-T+Full+Duplex%29&time_format=%25b+%25e+%25T

configtestで記法エラーは出ないが[FAIL] td-agent ... failed!だけ出てくる

ほとんどのケースで設定ファイルで指定したファイル出力先のパーミッションが不適切な場合にこうなってしまう。「(パーミッションがだめだと)そう言えや」感がすごい。

Example

/etc/td-agent/td-agent.conf

# YAMAHA RTX
<source>
  @type tail
  @id yamaha_rtx_input_tail
  path /home/vagrant/log/rtx1200.log
  format syslog
  tag yamaha.test.log
</source>

<match yamaha.test.*>
  @type file
  path /home/vagrant/fluentd_test/yamaha_test.json
  <format>
    @type json
  </format>
</match>

このとき、<match>/home/vagrant/fluentd_test/を指定しているので、このディレクトリのパーミッションが不適切だったりすると[FAIL] td-agent ... failed!だけ出てくる。いい感じに設定してあげよう。

whywaita Advent Calendar 2021 17日目:人はなぜ飛行機に乗るのか

f:id:tw1sm1k0:20211214002544j:plain:w800

皆が目指し始める沖縄には一体何があるのか?
その謎を解明するため、我々調査隊はプレミアムポイント/FLY ONポイントシミュレーターへ向かったーー。

この記事はwhywaita Advent Calendar 2021 - Adventarの17日目の記事です。
16日目は id:tochikuji さんでした。Tweetに重みがあってエモいですね...
自分はゲーミングチェアを使っているのですが、正直ゲームをあまりやらないので、次はプロの店員さんにおまかせして見繕ってみたいですね。(アーロンチェアコンテッサ程度しか知らなかったので、椅子の世界も奥深くて驚きです。)

さて、去年は沖縄那覇の話をしましたが、今年は沖縄つながりで飛行機の話です。

皆さん、飛行機に乗っていますか?

f:id:tw1sm1k0:20211214002855j:plain:w800
基本的に皆さん、飛行機には月1回以上乗ると思うのですが、今年自分は41回飛行機に乗っていたようです。 特に沖縄には14回も行ったようですね。

Date Departure Destination Fare type
2021/02/06 HND 14:30 OKA 17:25 SUPER VALUE 21
2021/02/06 OKA 20:50 HND 23:00 SUPER VALUE 21
2021/02/20 HND 14:30 CTS 17:25 SUPER VALUE 55
2021/02/22 CTS 20:50 HND 23:00 SUPER VALUE 55(アップグレード)
2021/03/27 HND 7:25 OKA 10:10 SUPER VALUE 28
2021/03/27 OKA 12:15 HND 14:35 SUPER VALUE 28
2021/03/27 HND 15:30 OKA 18:15 SUPER VALUE 28
2021/03/27 OKA 19:10 HND 21:30 SUPER VALUE 28
2021/04/03 HND 8:30 OKA 11:25 SUPER VALUE 28
2021/04/03 OKA 15:45 HND 18:15 SUPER VALUE 28
2021/04/10 HND 15:40 OKA 18:25 SUPER VALUE 28
2021/04/10 OKA 20:40 HND 23:00 SUPER VALUE 28
2021/04/17 HND 7:25 OKA 10:15 SUPER VALUE 28
2021/04/17 OKA 11:05 HND 13:25 SUPER VALUE 28
2021/04/17 HND 15:40 OKA 18:25 SUPER VALUE 28
2021/04/17 OKA 19:20 HND 21:40 SUPER VALUE 28
2021/05/22 HND 8:30 OKA 11:20 SUPER VALUE 45
2021/05/22 OKA 18:10 HND 20:35 SUPER VALUE 45
2021/05/23 HND 8:30 OKA 11:20 SUPER VALUE 45
2021/05/23 OKA 14:30 HND 17:00 SUPER VALUE 45
2021/05/29 HND 8:30 OKA 11:20 SUPER VALUE 55
2021/05/29 OKA 20:10 HND 22:30 SUPER VALUE 55
2021/06/05 HND 8:30 OKA 11:20 SUPER VALUE 75
2021/06/05 OKA 15:40 HND 18:15 SUPER VALUE 75
2021/07/25 HND 8:00 CTS 9:30 特典航空券
2021/07/25 CTS 17:00 HND 18:40 特典航空券
2021/09/18 HND 9:30 CTS 11:05 SUPER VALUE SALE
2021/09/18 CTS 12:50 RIS 13:40 株主優待
2021/09/19 RIS 14:15 CTS 15:10 株主優待
2021/09/19 CTS 18:30 HND 20:05 SUPER VALUE SALE
2021/09/21 HND 8:00 ITM 9:05 特典航空券
2021/09/21 ITM 19:00 HND 20:15 特典航空券
2021/10/09 HND 14:30 OKA 17:15 SUPER VALUE 28
2021/10/09 OKA 20:10 HND 22:30 SUPER VALUE 28
2021/11/13 HND 13:10 OKA 16:00 SUPER VALUE SALE
2021/11/13 OKA 20:00 HND 22:20 SUPER VALUE 45
2021/11/22 HND 8:00 CTS 9:30 特典航空券
2021/11/22 CTS 19:30 HND 21:10 特典航空券
2021/12/11 HND 7:35 OKA 10:35 特典航空券
2021/12/11 OKA 20:05 HND 22:20 特典航空券

沖縄に至っては日帰りで行くのになれすぎて、今年は一泊もしていないようです。

なぜ飛行機に乗るのか?

自分の身の回りにも飛行機にいっぱい乗っている人が多くいて、先日も都内の大学時代の先輩と、ゆいレール 小禄駅の改札でばったりお会いするという経験もしました。
そんなところから、なぜ人は飛行機に乗るのか?というところを自分なりに深堀りしてみました。

1. 非日常が味わえる

f:id:tw1sm1k0:20211214003207j:plain:w500
年間40回以上も飛行機に乗っていても、飛行機に乗るたびに非日常感が味わえます。これが一番の醍醐味でしょう。
飛行機に乗れば空高くから都心を眺めたり、富士山を見ることができます。数時間乗るだけで沖縄や北海道など、はるか遠くの土地まで行くことができます。飛行機に乗ったおかげで味わえる非日常感ですね。

2. 行った先でうまいものが食える

f:id:tw1sm1k0:20211214003038j:plain:w800
都心でもたいていなんでも食えますが、やはり行った先でその土地のものを食べると美味しいです。利尻で雲丹を食べたら、今まで食べていた雲丹はなんだったんだ・・・と思うくらい美味しかったです。沖縄では、裏路地のお店で在日米軍のお兄さんたちにまぎれてタコスを食べましたが、これも驚くほど美味しくて、気がついたら消えているレベルでした。これも飛行機に乗ったおかげです。

3. いい風景が見れる

f:id:tw1sm1k0:20211214003155j:plain:w800 行き先次第ですが、離島などはすごくいい景色が見れます。平日にディスプレイを眺めて過ごしているのに反して、海や空、山などを眺めることができて、とても心が洗われますね。これも飛行機に乗ったおかげです。

4. 新たな出会いがある

f:id:tw1sm1k0:20211217001131j:plain:w800
コロナ禍でなかなか現地の人と仲良くなることが今は難しいですが、現地の居酒屋でおじさんと意気投合して「時価」がある日本料理をおごってもらったり、離島をロードバイクで走ってたら現地のおばちゃんとなぜか一緒に観光をしたりと、新たな出会いが旅先でもあるのも旅行の醍醐味です(すべて実話)。これも飛行機に乗ったおかげです。

5. プレミアムポイント/FLY ONポイントがたまる

f:id:tw1sm1k0:20211214003508p:plain:w800
飛行機に乗ると各航空会社のステータス取得に必要なポイントを貯めることができます。1つ1つ積み重ねて目標に向かって進んでいる感が味わえます。これも飛行機に乗ったおかげです。(海外へ行ったこともないのに、地球3周分くらい飛行機に乗ってますね)

6. 1日に那覇羽田2往復すると虚無感が味わえて気持ちがいい

f:id:tw1sm1k0:20211214003858p:plain:w300
ステータス獲得のために、1日に那覇羽田2往復をして家についたとき「6000kmも1日で移動したのか〜と、でも今は振り出し・・・」と虚無を感じるとき、とても気持ちが良いですね。これも飛行機に乗ったおかげです。

結論

最後あたりが怪しくなりましたが、やはり非日常感を味わえる、旅行先で楽しむ、初めての人/会いたかった人に会えるというところが、やはり人が飛行機に乗って飛んでしまう所以なのでしょうね。特に最後の虚無感に気持ちよさを感じるのはやばいと思うので、ほどよく飛行機に乗るのがいいと思います。

コロナ禍でなかなか旅行に行くこともままならない世の中ですが、近いうちにまたwhywaitaとともにどこかに旅行に行きたいですね。身の回りがJAL派ばかりで、知り合いにスイートラウンジでイキれないのが無念なので、今度ANAに乗っていきましょう。

ちなみに、来年もすでにいっぱい飛行機に乗ることになっていますが、来年もこのAdvent Calendarがあったときには違うネタが用意できるようにしたいなぁと思います。
f:id:tw1sm1k0:20211217003045p:plain:w800

明日は kyontan です。まだ彼のマイカーに乗ったことがないのですが、修理を繰り返すあまり、テセウスの船みたいになっているので、新車になった頃に乗りたいですね。

蛇足

どうでも良いのですが、先日、社で同期の女性の方と研修でご一緒することがあり、アイスブレイクとしての自己紹介タイムで「飛行機によく乗ってて、この間も1日に那覇羽田2往復したんですよ〜」と言ったところ、ドン引きされました。

M1 MacでTensorflowを使う

院生時代に使ったっきりのTensorflowがM1に対応したのを今更見つけて、久しぶりに触ろうと思ったらちょっとハマったので備忘録的に書く。

Python環境構築(雑メモ)

当初はPyenvでAnaconda or minicondaを入れればよいかと思ったが、pyenvではApple Silicon版のAnacondaは未対応なためインストールできず。今のナウいARMに生きている若者の間ではMiniforge(Mambaforge)が使われているとのことで、そちらを利用することにした。
今回はpyenvでmambaforgeをインストールし、globalにmambaforgeを設定した。別にpyenvを入れずに、ダイレクトにMiniforgeのリポジトリにあるインストーラーでインストールしても良かった気はする。

pyenv install mambaforge
pyenv global mambaforge
pyenv versions
  system
  3.9.1
* mambaforge (set by /Users/user/.pyenv/version)

これはいらないかもしれないが、インストール時に.zshrcの掃除もしていたので、Miniforgeでcondaコマンドを使うには(というよりも、普通にcondaを使うには)以下も追加する必要があった。 conda init でいい感じに挿入されるのだが、condaのバイナリのパスなどがベタ書きされており、ちょっと気持ち悪かったので環境変数に押し出した。

export PYENV_ROOT="$HOME/.pyenv"
export MAMBA_HOME="$PYENV_ROOT/versions/mambaforge"

# conda(mamba/miniforge)
__conda_setup="$("$MAMBA_HOME/bin/conda" 'shell.zsh' 'hook' 2> /dev/null)"
if [ $? -eq 0 ]; then
    eval "$__conda_setup"
else
    if [ -f "$MAMBA_HOME/etc/profile.d/conda.sh" ]; then
        . "$MAMBA_HOME/etc/profile.d/conda.sh"
    else
        export PATH="$MAMBA_HOME/bin:$PATH"
    fi
fi
unset __conda_setup

とりあえずこの辺で普通にPythonが使えるようになるはず。

Tensorflowのインストール

基本的にはApple公式のARM64版手順のうち、Miniforgeをインストールし終えたあとからに従えばOK。

developer.apple.com

おもむろに仮想環境を作成

mamba create -n tensorflow_m1 python=3.9
conda activate tensorflow_m1

依存関係のインストール。

conda install -c apple tensorflow-deps
python -m pip install tensorflow-macos
python -m pip install tensorflow-metal

おわり。

試す

学部4年で研究室配属されたときに指導教官の顔よりも見たMNISTでサクッと試す。
感触として、結構早い気がする。あと学習中もMac miniの発熱も少なく、ファンの音も変わらず、なかなか。
もっと難しいモデルを食わせたときにどうなるかは今後試したい。

www.tensorflow.org

トラブルシュート:h5py

python -m pip install tensorflow-macos 時に依存関係でインストールされる h5py が、brew install hdf5でインストールしていても hdf5のライブラリが見つからずにこけてしまう。

  error: Unable to load dependency HDF5, make sure HDF5 is installed properly
  error: dlopen(libhdf5.dylib, 0x0006): tried: '/Users/user/.pyenv/versions/mambaforge/lib/libhdf5.dylib' (no such file), '/Users/user/.pyenv/versions/mambaforge/lib/libhdf5.dylib' (no such file), '/Users/user/.pyenv/versions/mambaforge/lib/python3.9/li
b-dynload/../../libhdf5.dylib' (no such file), '/Users/user/.pyenv/versions/mambaforge/lib/libhdf5.dylib' (no such file), '/Users/user/.pyenv/versions/mambaforge/bin/../lib/libhdf5.dylib' (no such file), 'libhdf5.dylib' (no such file), '/usr/local/lib/libhdf5.dyli
b' (no such file), '/usr/lib/libhdf5.dylib' (no such file), '/private/var/folders/1t/8rwk7l5x4ssf753522k2d5v40000gn/T/pip-install-jq0sx82l/h5py
_d3e3046cd7134f25a2ade50e9f4a162e/libhdf5.dylib' (no such file), '/usr/local/lib/libhdf5.dylib' (no such file), '/usr/lib/libhdf5.dylib' (no su
ch file)
  ----------------------------------------
  ERROR: Failed building wheel for h5py
Failed to build h5py
ERROR: Could not build wheels for h5py, which is required to install pyproject.toml-based projects

理由は、ARM64版とx86/64版ではbrewでインストールした際のインストール先ディレクトリが違うらしく、h5pyがそれを終えていない模様。
ワークアラウンドとして、x86/64でbrewをインストールしてHDF5をインストールする方法があるらしいが、あまりバイナリを混在させたくなかったので、h5pyインストール時にarm64のbrewでインストールしたHDF5のディレクトリを環境変数(HDF5_DIR)で指定の上、pipでバイナリパッケージを使用しないことを明示(--no-binary=h5py)してインストールして対応した。

export HDF5_DIR=/opt/homebrew/Cellar/hdf5/1.12.1/
pip install --no-binary=h5py h5py

参考:
- python - How to install h5py (needed for Keras) on MacOS with M1? - Stack Overflow
- M1 Macでのlibtorch、HDF5、Boostその他のintel版をインストール - Qiita

Juniper Telemetry Interfaceをfluentdで受ける

作業メモ

環境

  • Juniper vMX on AWS EC2(BYOL/Trial)
    • JUNOS 19.4R1.9
  • fluentd
    • AWS EC2 AMI 4.14.231-173.361.amzn2.x86_64
    • td-agent 1.10.2

したいこと

Junosから送られてくるJuniper Telemetry Interface(over UDP)をfluentdで受けたい。とりあえずはテキストでローカルに吐いてくれれば良い

作業

前提条件

  • fluentdはパッケージでインストール済み

Junosの設定

  • AWS Marketplaceで取得したJunos vMXにはrootパスワードが設定されておらず、commitが出来ないのでよしなに設定

  • 普段、Junosを触らないが、ドキュメント通りに設定すれば出来た

    • Configuring a Junos Telemetry Interface Sensor (CLI Procedure) | Junos OS | Juniper Networks
      • Export Profile, Streaming Server Profile, Sensor Profileの設定が必要
    • Export Profile
      • Junos自身がどういうIP/ポート...でテレメトリを出すか?を指定
      • set local-addressにはJunosのマネジメントIPを指定した
      • set local-portは適当に12345
      • set transportは今回、UDPにした
      • DSCP, forwarding class, packet loss priorityはoptionalで今回は作り込む気はないので、スキップ
    • Streaming Server Profile
      • テレメトリを受けるサーバの設定
      • set remote-addressにはJunosのマネジメントにつながっているAWSVPCのセグメント上に立てたfluentdを動かすEC2のIPアドレスを指定
      • set remote-portは適当に22000を指定
    • Sensor Profile
  • 最終的には以下の感じのconfigになった

services {
    analytics {
        streaming-server ec2 {
            remote-address 10.0.1.63;
            remote-port 22000;
        }
        export-profile fluentd {
            local-address 10.0.1.164;
            local-port 12345;
            reporting-rate 5;
            format gpb;
            transport udp;
        }
        sensor interface-1 {
            server-name ec2;
            export-name fluentd;
            resource /junos/system/linecard/cpu/memory/;
        }
    }
}

Pluginのインストール

git clone https://github.com/Juniper/fluent-plugin-udp-native-sensors   # 普通にclone
git fetch origin pull/3/head:with_keys_1.0  # fluentd最新版に対応したPRを取得
git checkout with_keys_1.0 
sudo td-agent-gem build fluent-plugin-udp-native-sensors.gemspec  # fluentd内蔵のgemでビルド
sudo td-agent-gem install fluent-plugin-udp-native-sensors-0.0.1.gem  # fluentd内蔵のgemでインストール

Pluginの設定

  • GithubのREADME通りだが、/etc/td-agent/td-agent.confに以下を追記
    • もしJunosの設定でStreaming Server Profileにあるremote-portを22000以外にしていたら、その変更したポートを指定する
<source>
    @type udp
    tag juniperNetworks
    format juniper_udp_native
    port 22000
    bind 0.0.0.0
</source>

<match juniperNetworks>
   @type file
   path /home/ec2-user/junos/
</match>
  • td-agentを再起動

参考文献

whywaitaと那覇へ異常行動をしに行きたい2020冬

f:id:tw1sm1k0:20201129125609j:plain

これはwhywaitaの人徳ゆえになんだかんだで埋まる、不思議なwhywaita Advent Calendarの2020年版、4日目の記事です。

昨日はkyontanでした。本記事は平日に時間がないと思い先週の土曜日に書いたのですが、まさかの以心伝心で今日は那覇ANAダイヤモンドメンバーの話になります。

一日に羽田-沖縄を2往復して何が楽しいんでしょうか?

那覇と羽田を1日2往復すると、1日の半分以上を空にいられるので事実上のあおかなというわけです。ましろちゃんとこの辛く厳しい現世でも会いたいと思い、空を飛んでいるのかもしれませんね。人は古来より、空を飛んでみたいと思い生きているのです。

f:id:tw1sm1k0:20201129172004p:plain
from: https://www.ana.co.jp/ja/jp/amc/reference/premium/

今年、ダイヤモンドになるために行った行程をご紹介しましょう。

Date Departure Destination Fare type
- - - -
2020/05/16 HND 7:30 OKA 10:10 株主優待
2020/05/16 OKA 11:00 HND 13:25 VALUE 3
2020/05/16 HND 15:40 OKA 18:15 VALUE 3
2020/05/17 OKA 11:00 HND 13:25 VALUE 3
2020/05/22 HND 7:30 OKA 10:10 VALUE 3
2020/05/22 OKA 11:00 HND 13:25 VALUE 3
2020/05/22 HND 15:40 OKA 18:15 SUPER VALUE 55L
2020/05/23 OKA 11:00 HND 13:25 SUPER VALUE PREMIUM 28
2020/05/24 HND 10:45 OKA 13:30 SUPER VALUE 55M
2020/05/24 OKA 14:30 HND 17:00 SUPER VALUE 55M
2020/05/30 HND 7:30 OKA 10:10 VALUE 3
2020/05/30 OKA 11:00 HND 13:25 VALUE 3
2020/05/30 HND 15:40 OKA 18:15 VALUE 3
2020/05/30 OKA 19:05 HND 21:30 SUPER VALUE 45M
2020/06/27 HND 7:30 OKA 10:10 国際線乗り継ぎ(SYSERROR)
2020/06/28 OKA 14:25 HND 17:00 SUPER VALUE 75M
2020/07/03 HND 15:40 OKA 18:10 SUPER VALUE 75M
2020/07/05 OKA 14:25 HND 17:00 SUPER VALUE 75L
2020/08/01 HND 7:30 OKA 10:10 VALUE 1
2020/08/01 OKA 20:35 HND 23:00 VALUE 1
2020/08/22 HND 7:30 OKA 10:05 VALUE 3
2020/08/22 OKA 10:55 HND 13:25 VALUE 3
2020/08/22 HND 14:30 OKA 17:05 VALUE 3
2020/08/22 OKA 19:00 HND 21:30 VALUE 3
2020/08/28 HND 20:00 OKA 22:30 VALUE 3
2020/08/30 OKA 8:00 HND 10:20 プレミアム株主優待
2020/08/30 HND 12:55 OKA 15:30 VALUE 3
2020/08/30 OKA 16:25 HND 19:00 VALUE 3
2020/09/04 HND 7:30 OKA 10:10 VALUE 3
2020/09/04 OKA 11:00 HND 13:25 VALUE 3
2020/09/04 HND 15:40 OKA 18:10 VALUE 3
2020/09/04 OKA 19:05 HND 21:30 VALUE 3
2020/09/05 CTS 12:35 RIS 13:25 SUPER VALUE 45L
2020/09/06 RIS 14:05 CTS 15:00 SUPER VALUE 45L
2020/09/12 HND 7:30 OKA 10:10 VALUE 3
2020/09/12 OKA 11:00 HND 13:25 VALUE 3
2020/09/12 HND 15:40 OKA 18:10 VALUE 3
2020/09/12 OKA 19:05 HND 21:30 VALUE 3
2020/09/13 HND 7:30 OKA 10:10 VALUE 3
2020/09/13 OKA 11:00 HND 13:25 VALUE 3

この修業ですっかり沖縄が好きになってしまいました。なので、ぜひ仲良しのwhywaitaと一緒に沖縄に行きたいと最近思っています。しかし、お互いに社会人で仕事もあり、時間がなかったりするのも事実。そこで、自分がこの修業で編み出した超短時間・爆速・満足度の高い(当社比)、那覇観光について記事を書きたいと思います。

本記事を参考に沖縄に行かれる方は、GOTOトラベル事務局作成の「新しい旅のエチケット」等をご覧になり、十分に対策をしてください!

goto.jata-net.or.jp

続きを読む

YAMAHA RTX1200のログをElasticsearch+logstash(+Grok)+Kibanaで可視化する話 on Docker

9割ポエムなサイトに唐突に現れる技術記事です。

完成図

とりあえず最終的に得たいもののイメージ。IPフィルターで破棄した通信の送信元国と回数、ポート番号をDashboardで表示しています。 f:id:tw1sm1k0:20190815103000p:plain (詳しく見るとChinaにTaiwanが含まれててアツいですね)

前提条件

以下の行程が終了していることを前提とします。適当にググるとやり方が載っているので、いい感じにしてください。

  • Docker、docker-composeがインストール済み
  • RTXルーターのsyslogがdockerを動かしているマシンに転送され保存されている

  • 以下のようなディレクトリ構成を想定して進めます

.
├── docker-compose.yaml
├── elasticsearch_data
└── pipeline
    └── pipeline.conf

docker-compose.yamlの準備

なにかいろいろなサイトを参考にして作ったdocker-compse.yamlは以下のような感じ。とりあえずで volumes相対パスになっているので、変えたい人はよしなに。 また、logstashvolumesでマウントしている /var/log は、自分のRTXのログが /var/log/rtx1200.log という名前で出力されるようにしているからなので、もし違う人はそこも合わせてあげてください。

version: "3"
services:
  elasticsearch:
    image: elasticsearch:7.2.0
    container_name: elasticsearch
    environment:
      discovery.type: single-node
    ports:
      - "9200:9200"
      - "9300:9300"
    volumes:
      - ./elasticsearch_data:/usr/share/elasticsearch/data

  logstash:
    image: docker.elastic.co/logstash/logstash:7.0.1
    container_name: logstash
    volumes:
      - ./pipeline:/usr/share/logstash/pipeline
      - /var/log:/var/log
    depends_on:
      - elasticsearch

  kibana:
    image: kibana:7.2.0
    container_name: kibana
    environment:
      ELASTICSEARCH_URL: http://elasticsearch:9200
    ports:
      - "5601:5601"
    depends_on:
      - elasticsearch

(どうでもいいですが、KubernetesYAMLが推奨されている理由が「Write your configuration files using YAML rather than JSON. Though these formats can be used interchangeably in almost all scenarios, YAML tends to be more user-friendly. 」ですが、この滅茶苦茶読みにくい、ゴミみたいな形式がJSONよりユーザーフレンドリーとは思わないんですけどね・・・。)

logstashのpipeline.conf作成

Pipelineの流れはElastic社の概念図がわかりやすいです。

https://www.elastic.co/guide/en/logstash/2.3/static/images/basic_logstash_pipeline.png

つまり、雑多なData Sourceからログを取得するために適切な方法をInput pluginで指定して、Filter pluginで整形、そのあとにOutput pluginでログを保存したいところに応じた保存方法を指定してあげるという流れ。その処理で適切なプラグインを指定して、プラグイン毎の設定をしてい\けばパイプラインの出来上がりというわけ。

今回の場合はsyslogでファイルとして取得できているRTX1200のログを読み込みたいので、Input pluginにfileプラグインを用います。細かい設定は公式ドキュメントに詳細が載っているので、そちらを参照。

www.elastic.co

今回はとりあえずという形なので、ファイルパス pathstart_position のみを指定します。 pathは普通にsyslogが吐かれるファイルパスを指定すればOK。 start_position はlogstashがファイルのどこから読み込むかという設定になります。実運用時には前回取得時からの差分だけ、つまりファイル末尾だけを見たいので end を指定しますが、今回は古いデータをまとめて取得したいので beginning を指定します。
そんな流れでpipelineを書くと以下のような感じになります。

input {
    file {
        path => "/var/log/rtx1200.log"
        start_position => "beginning"
    }
}

これでRTX1200のログがlogstashのpiplineに乗るので、次は内容をどう整形するかを filer で指定します。今回は充実した正規表現リストが予め組み込まれている、お手軽プラグインのgrokを使って整形していきます。
grokプラグインで使用できる正規表現リストは以下を参照。ほとんどこれで良いんじゃないか?というレベル。

https://github.com/logstash-plugins/logstash-patterns-core/blob/master/patterns/grok-patternsgithub.com

まず、syslogのヘッダー部を取り出します。つまりは、以下のようなsyslogの出力で言うところの日付とsyslogを発したホストIP、ログ内容のうち日付とホストのIPアドレスを抜き出す。

Aug 11 03:09:46 192.168.**.** [DHCPD] LAN1(port1) Allocates 192.168.**.**: **:**:**:**:**:**
Aug 11 03:54:50 192.168.**.** PP[01] Rejected at IN(1012) filter: TCP **.**.**.**:**** > ***.***.***.***:***
Aug 11 03:54:51 192.168.12.1 PP[01] Rejected at IN(1012) filter: TCP **.**.**.**:**** > ***.***.***.***:***

grokを使って日付を time、ホストIPアドレスhostname、ログ内容を messageというラベルをつけて抜き出すと以下のような感じになります。

    grok {
        match => { "message" => "%{SYSLOGTIMESTAMP:time} %{IPV4:hostname} %{GREEDYDATA:message}" }
        overwrite =>  [ "message" ]
    }

ここでoverwriteを使って日付とホストIPを除いた、ログ本文をmessageラベルとして上書きしています。こうすることで、未処理のログ範囲を狭めていっています。

で、ここで細かくやっていくべきなのですが、いきなりドカンと一気に内容をパースしていきます。

  • 定期実行処理のログ
    • cronで定期実行されるログを取り出す。自分の場合はNTP同期のログ程度しか出力されないので、定期実行された内容程度を取り出すだけにしている。
  • Inに対するIPフィルターで破棄された通信ログ
  • Outに対するIPフィルターで破棄された通信ログ
  • DHCP割当ログ
  • ログイン履歴
  • 残り
    • 上記フィルターで該当したなかった雑多なログ

以上の項目をフィルターに設定すると、以下のような感じになります。

    grok {
        match => {
            "message" => [
                "\[SCHEDULE\] %{GREEDYDATA:schedule_what}",
                "%{GREEDYDATA:in_rejected_interface} Rejected at IN\(%{NUMBER:in_rejected_filter_num:int}\) filter: %{WORD:in_rejected_protocol} %{IPV4:in_rejected_src_address}\:%{NUMBER:in_rejected_src_port:int} > %{IPV4:in_rejected_dst_address}\:%{NUMBER:in_rejected_dst_port:int}",
                "%{GREEDYDATA:out_rejected_interface} Rejected at OUT\(%{NUMBER:out_filter_num:int}\) filter: %{WORD:out_rejected_protocol} %{IPV4:out_rejected_src_address}\:%{NUMBER:out_rejected_src_port:int} > %{IPV4:out_rejected_dst_address}\:%{NUMBER:out_rejected_dst_port:int}",
                "\[DHCPD\] %{GREEDYDATA:dhcp_allocate_interface} Allocates %{IPV4:dhcp_allocate_address}: %{MAC:dhcp_allocate_mac_address}",
                "%{GREEDYDATA:interface}: %{GREEDYDATA:interface_what} ",
                "\'%{WORD:login_succeeded_user}\' succeeded for %{WORD:login_succeeded_protocol}: %{IPV4:login_succeeded_src_address}",
                "%{GREEDYDATA:other_logs}"
            ]
        }
    }

ごちゃごちゃと書かれているけれども、基本的にはログ文中の取り出したい文字列部分を %{} で括り、中に該当する正規表現リストの名前とラベルを記載しているだけ。多少クセはあるが、ちょっとずつ書いていくとなんとなく慣れます。
なお、自分がハマったポイントだけ解説しておきます。ポート番号やIPフィルターの番号など、Int型が来るものに対して上記では %{NUMBER:hogehoge:int} としています。このようにしないと、Int型が文字列として扱われてしまい、Elasticsearch側で文字列として扱われて数値統計などができなくなってしまいます。

そして、今回の主目的である「フィルターに該当した通信の発信/送信元を地図にマッピングしたい」を実現するため、 geoip プラグインを用いてIPアドレスを地理情報に変換します。ここで、if でIPフィルターに該当して破棄された通信のIPアドレスがある場合のみにgeoipプラグインで地理情報に変換するようにしています。こうしないと、エラーが出力されてしまいます。

    if [in_rejected_src_address]{
        geoip {
              source => "in_rejected_src_address"
              target => "in_rejected_src_geo"
        }
    }

    if [out_rejected_dst_address]{
        geoip {
              source => "out_rejected_dst_address"
              target => "out_rejected_dst_geo"
        }
    }

そして最後にelasticsearchに記録するためoutputを指定します。今回はdocker-composeでelasticsearchを立ててよしなにするにで、以下のような非常にかんたんな記述になります。

output {
    elasticsearch {
        hosts => [ "http://elasticsearch:9200" ]

    }

なお、Elasticsearchに直接突っ込まずにデバッグのために一旦ファイル出力したいなどの場合であれば以下のようにすればファイルに出力されます。

output {
 file {
   path => "/foo/bar/hogehoge.json"
 }
}

以上をすべて繋げると、YAMAHA RTX1200のログをElasticsearchに突っ込むpipelineは以下のような感じになります。

input {
    file {
        path => "/var/log/rtx1200.log"
        start_position => "beginning"
    }
}

filter {
    grok {
        match => { "message" => "%{SYSLOGTIMESTAMP:time} %{IPV4:hostname} %{GREEDYDATA:message}" }
        overwrite =>  [ "message" ]
    }

    grok {
        match => {
            "message" => [
                "\[SCHEDULE\] %{GREEDYDATA:schedule_what}",
                "%{GREEDYDATA:in_rejected_interface} Rejected at IN\(%{NUMBER:in_rejected_filter_num:int}\) filter: %{WORD:in_rejected_protocol} %{IPV4:in_rejected_src_address}\:%{NUMBER:in_rejected_src_port:int} > %{IPV4:in_rejected_dst_address}\:%{NUMBER:in_rejected_dst_port:int}",
                "%{GREEDYDATA:out_rejected_interface} Rejected at OUT\(%{NUMBER:out_filter_num:int}\) filter: %{WORD:out_rejected_protocol} %{IPV4:out_rejected_src_address}\:%{NUMBER:out_rejected_src_port:int} > %{IPV4:out_rejected_dst_address}\:%{NUMBER:out_rejected_dst_port:int}",
                "\[DHCPD\] %{GREEDYDATA:dhcp_allocate_interface} Allocates %{IPV4:dhcp_allocate_address}: %{MAC:dhcp_allocate_mac_address}",
                "%{GREEDYDATA:interface}: %{GREEDYDATA:interface_what} ",
                "\'%{WORD:login_succeeded_user}\' succeeded for %{WORD:login_succeeded_protocol}: %{IPV4:login_succeeded_src_address}",
                "%{GREEDYDATA:other_logs}"
            ]
        }
    }

    if [in_rejected_src_address]{
        geoip {
              source => "in_rejected_src_address"
              target => "in_rejected_src_geo"
        }
    }

    if [out_rejected_dst_address]{
        geoip {
              source => "out_rejected_dst_address"
              target => "out_rejected_dst_geo"
        }
    }
}

output {
    elasticsearch {
        hosts => [ "http://elasticsearch:9200" ]

    }
}

docker-compose up

以上で概ねの設定は終わったので、docker-compose.yamlがあるディレクトリで docker-compose up してElasticsearchその他を立ち上げましょう。
無事に立ち上がればdockerを動かしているマシンのIPアドレスの5601番でKibanaが立ち上がるはずです。結構、立ち上げに時間がかかります。

まだKibana側でElasticsearchのログを紐付けていないので、適当にサイドバーのDiscoverをクリックしてウィザードを立ち上げます。 f:id:tw1sm1k0:20190815103128p:plain
f:id:tw1sm1k0:20190815103234p:plain

適当にinedx patternにlogstashと打って、logstashで整形したログを登録します。
f:id:tw1sm1k0:20190815103317p:plain

タイムスタンプを指定 f:id:tw1sm1k0:20190815103348p:plain

登録終わり f:id:tw1sm1k0:20190815103441p:plain

実際にIPフィルターで破棄した通信を地図上にマッピングしていきます。Visualize→Create new visualizationでダイアログから Region Mapを選択、先程登録したlogstashのログを指定 f:id:tw1sm1k0:20190815103512p:plain
f:id:tw1sm1k0:20190815103517p:plain
f:id:tw1sm1k0:20190815103524p:plain

遷移後、 サイドで MericValueCount を選択。その後、国毎に検出数をまとめたいので BucketsAggregation から Terms を選択し、 Filed からin_rejected_src_geo.continent_code.keyword を選択。
f:id:tw1sm1k0:20190815103836p:plain

ここでデフォルト設定では直近15分のログからしか可視化をしないので、適当に上部からhoursではなくdaysに変更、UPDATE
f:id:tw1sm1k0:20190815104111p:plain

そうすると、欲しかった地図マッピングが完成。 f:id:tw1sm1k0:20190815103534p:plain

wrapup

最後あたり、凄まじく雑になりましたね。息切れです。そのうち、もうちょっとちゃんと書こう・・・。

Macintosh HDのイメージをディスクユーティリティで作成できない件

自分の備忘録用。

Genius BarMacBook Proを持っていきたくて、その前にバックアップのためにmacOSの入っているMacintosh HD自体のイメージを作成しようとしたところ、 ファイル -> 新規イメージ -> "Macintosh HD" からイメージ作成 がグレーアウトしていてクリックできなかった。
f:id:tw1sm1k0:20190221010650p:plain FileVaultを有効にしているせいなのかなんなのかよくわからないが、対処法は以下の通り。

  • (いらないかも)Command + Rを押しながら再起動して、リカバリーモードで起動。その後、ディスクユーティリティを起動する。

  • 表示 -> すべてのデバイスを表示 (あるいはCommand + 2)を押して、ボリューム表示のみではなくすべてを表示させる。
    f:id:tw1sm1k0:20190221010708p:plain

  • MacBook Proの場合、 コンテナdisk1 がサイドバーに登場するので、それをクリック

  • その後、ファイル -> 新規イメージ -> "コンテナdisk1" からイメージ作成 でイメージを作成する

macOSはわけのわからないところですごい不親切なので、謎。