ようへいの日々精進XP

よかろうもん

小ネタ道場一本勝負 〜 logstash の Ruby filter メモ 〜

tl;dr

logstash を使っていて、filter でちょっと凝ったことをしたいと思って調べていたら Ruby のコードが直接書けるようなので導入してみた。

www.elastic.co

今回やりたかったこと

  • input で入ってきた event オブジェクトの中にある date 型フィールドデータのフォーマットを整形したデータを追加したい
  • 具体的には ISO8601 で入ってきた Datetime データを HH:MM:SSHH:MM に整形してそれぞれ個別のフィールドに追加したい

サンプル実装

logstash.conf

logstash 5.x とそれ以前のバージョンで書き方が若干異なるので注意。

  • logstash 5.x の場合
input {
  tcp {
    port => 5000
  }
}

filter {
  ruby {
    code => "
      event.set('datetime_hour_min_sec', DateTime.parse(event.get('message')).strftime('%H:%M:%S'));
      event.set('datetime_hour_min', DateTime.parse(event.get('message')).strftime('%H:%M'));
    "
  }
}

output {
  stdout {
    codec => "rubydebug"
  }
}
  • logstash 5.x 以前
input {
  tcp {
    port => 5000
  }
}

filter {
  ruby {
    code => "
      event['datetime_hour_min_sec'] = DateTime.parse(event['message']).strftime('%H:%M:%S');
      event['datetime_hour_min'] = DateTime.parse(event['message']).strftime('%H:%M');
    "
  }
}

output {
  stdout {
    codec => "rubydebug"
  }
}

詳細については、以下の注意点にて。

ELK Stack の用意

ちょっと脱線して Elasticsearch + Logstash + Kibana 環境については以下の docker-compose 用の YAML を利用した。

github.com

超簡単に ELK Stack を作成することが出来た。

$ git clone https://github.com/deviantony/docker-elk.git
$ cd docker-elk
$ docker-compose up -d
$ docker ps
CONTAINER ID        IMAGE                     COMMAND                  CREATED             STATUS              PORTS                                            NAMES
1ff0e05da5ab        dockerelk_logstash        "/usr/local/bin/do..."   15 minutes ago      Up 12 minutes       5044/tcp, 0.0.0.0:5000->5000/tcp, 9600/tcp       dockerelk_logstash_1
3099200a271e        dockerelk_kibana          "/bin/sh -c /usr/l..."   8 hours ago         Up 8 hours          0.0.0.0:5601->5601/tcp                           dockerelk_kibana_1
24b575c350b7        dockerelk_elasticsearch   "/bin/bash bin/es-..."   8 hours ago         Up 8 hours          0.0.0.0:9200->9200/tcp, 0.0.0.0:9300->9300/tcp   dockerelk_elasticsearch_1

以下のように logstash にメッセージを投げることが出来る。

$ echo "hello" | nc localhost 5000

デモ

  • MacOS X 上で以下のように logstash にメッセージを投げる
$ echo $(date +%FT%T.$(gdate +%3N)Z) | nc localhost 5000
  • logstash では以下のように出力される
$ docker-compose logs -f logstash
...
logstash_1       | {
logstash_1       |                "@timestamp" => 2017-06-15T14:49:44.455Z,
logstash_1       |         "datetime_hour_min" => "23:49",
logstash_1       |                      "port" => 58782,
logstash_1       |     "datetime_hour_min_sec" => "23:49:44",
logstash_1       |                  "@version" => "1",
logstash_1       |                      "host" => "172.18.0.1",
logstash_1       |                   "message" => "2017-06-15T23:49:44.426Z"
logstash_1       | }

datetime_hour_mindatetime_hour_min_sec というキーが追加され、意図した通りに時分秒、時分が値として設定されている。

event オブジェクトへのアクセス方法

Event API

logstash 5.0 で再実装された Event API に合わせて event オブジェクトへのアクセス方法が変更されている。

www.elastic.co

以下、ドキュメントの抜粋。

In 5.0, we’ve re-implemented the Event class and its supporting classes in pure Java. Since Event is a critical component in data processing, a rewrite in Java improves performance and provides efficient serialization when storing data on disk.

Pure Jave で書き換えることで、データ保存時のシリアライズのパフォーマンス向上を図った(と読める)ようだ。

GitHub issue

github.com

github.com

logstash 5.0 から event オブジェクトへのアクセス方法は従来の hash like なアクセス方法を廃止して、getter と setter でアクセスするように変更されたというのが概要。

5.x 以前

hash にアクセスするような書き方でアクセス出来る。

filter {
  ruby {
    code => "
      event['datetime_hour_min_sec'] = DateTime.parse(event['message']).strftime('%H:%M:%S');
      event['datetime_hour_min'] = DateTime.parse(event['message']).strftime('%H:%M');
    "
  }
}

5.x 移行

GetAPI と SetAPI を利用してアクセスする。

filter {
  ruby {
    code => "
      event.set('datetime_hour_min_sec', DateTime.parse(event.get('message')).strftime('%H:%M:%S'));
      event.set('datetime_hour_min', DateTime.parse(event.get('message')).strftime('%H:%M'));
    "
  }
}

影響範囲

きっと、ちゃんとフォローされている環境であれば、何てこと無いんだろうけど、うっかりバージョンアップしたり、ググった設定をそのまま利用しようとするとハマりそう(実際にハマった)。

その他の filter

mutate

Ruby filter を利用する前に導入を検討していた。

www.elastic.co

add_field で任意のキーと値を追加したり…

filter {
  mutate {
    add_field => { "foo_%{somefield}" => "Hello world, from %{host}" }
  }
}

split で任意のキーの値を分割したり出来る。

filter {
  mutate {
     split => { "fieldname" => "," }
  }
}

全てを網羅出来ていないが、ドキュメントを見る限りではかなり柔軟に mutate 出来る。

grok

logstash に適当に入ってきたレコードを一定のルールに従って構造化してくれるスゴイやつ(という認識)。

www.elastic.co

こちら の例を見ると解りやすいので、そのまま写経。

入ってくるログレコードは Web サーバーのアクセスログっぽい。

55.3.244.1 GET /index.html 15824 0.043

Grok フィルタを以下のように定義する。

filter {
  grok {
    match => { "message" => "%{IP:client} %{WORD:method} %{URIPATHPARAM:request} %{NUMBER:bytes} %{NUMBER:duration}" }
  }
}

出力は stdout プラグインの codec は rubydebug を利用して確認。

$ docker-compose logs -f logstash
...
logstash_1       | {
logstash_1       |       "duration" => "0.043",
logstash_1       |        "request" => "/index.html",
logstash_1       |     "@timestamp" => 2017-06-16T23:49:13.404Z,
logstash_1       |         "method" => "GET",
logstash_1       |           "port" => 36390,
logstash_1       |          "bytes" => "15824",
logstash_1       |       "@version" => "1",
logstash_1       |           "host" => "172.18.0.1",
logstash_1       |         "client" => "55.3.244.1",
logstash_1       |        "message" => "55.3.244.1 GET /index.html 15824 0.043"
logstash_1       | }

上記のように clientmethod 等、よしなに解析してくれている。

以上

logstash 奥深い。

2017 年 06 月 16 日(金)

ジョギング

日課

  • (腕立て x 30 + 腹筋 x 30) x 3

夕飯

昨日、JAYA のお兄ちゃんが作っていた作り方を参考にしつつ、乳化に気を使いながら作った。

唐辛子を入れすぎて激辛パスタになって奥さんに詰められた。

明日は

先月亡くなった義父の 49 日法要。

小ネタ道場一本勝負 〜 date コマンドの出力を ISO 8601 フォーマットにしたい 〜

date コマンドで

ISO 8601 フォーマットで出力したい時がたまにあるのでメモっておく。

Mac だと

date +%FT%T%z

実行。

$ date +%FT%T%z
2017-06-15T19:26:43+0900

Linux だと

date --iso-8601=seconds

実行。

$ date --iso-8601=seconds
2017-06-13T19:06:52+0900

Ruby だと

irb(main):008:0> require 'time'
=> true
irb(main):009:0> Time.now.iso8601
=> "2017-06-15T19:39:15+09:00"

Python だと

>>> import datetime
>>> from pytz import timezone
>>> datetime.datetime.now(timezone('Asia/Tokyo')).strftime('%Y-%m-%dT%H:%M:%S%z')
'2017-06-15T19:57:48+0900'

以上

メモでした。

2017 年 06 月 14 日(水)

ジョギング

日課

  • (腕立て x 30 + 腹筋 x 30) x 3

kazukin

かずきんと香椎で呑んだ。

数少ないかもしれない、同年代で異業種の友人で色々と語り合った。

二軒目に寄った場末のスナックではっちゃけてるかずきんに昭和の匂いを感じた(笑

2017 年 06 月 12 日(月)

今日も

Bluetooth キーボードと Nexus7 で日記を書いてみる。

ジョギング

テンポよく走っているお兄さんを追っ掛けていたので多少オーバーペースになった。

日課

  • (腕立て x 30 + 腹筋 x 30) x 3

しば漬け

奥さんがキューピー三分クッキングを見ながら作ったしば漬けを色々な食べ方で食べている。

バッファローの折り畳み式キーボード(BSKBB15BK)試用メモ

はじめに

f:id:inokara:20170611212027j:plain

スマフォ用にバッファローの折り畳み式キーボードを購入した。ヨドバシカメラ博多店で 2000 円也。

簡単に試用メモを書いてみる。

そもそもどんな製品か?

http://m.buffalo.jp/product/input/keyboard/bskbb15/

使ってみた感じ

打鍵感

値段相応だけど、特に打ちづらいということはなくサクサク入力出来ている。

キーボードの配列は残念ながら US 配列なので日本語入力の際には注意が必要。

端末とのペアリング

Galaxy S6 Edge とペアリングさせたけど、速攻で繋がって嬉しかった。

ケースが嬉しい

キーボードを納めているケースがそのままスタンドになるので嬉しい。

その他

ESC キーでスマフォロックが出来るのが嬉しい。

tips

入力言語の切り替え

Shift + Space でいける。

アプリの切り替え

Alt + Tab もしくは Win + Tab でいける。

コピペ

普通に Ctrl + c と Ctrl + v でいける。

Caps Lock と Ctrl キーを入れ替える

以下のアプリを入れて対応した。

2017 年 06 月 11 日(日)

昨晩のつけ

軽い二日酔いで辛い。

1P とおやまつさん

PHP カンファレンスに来ていた同僚の 1P さんとおやまつさんの三人で博多駅のほろ酔い横丁でお寿司をつまみながら昼呑み。

業務で直接からむことはないけど、色々と楽しい話を聞けたので良かった。

スマフォ用に Bluetooth キーボードを買った

以前から欲しかったスマフォ用のキーボードをヨドバシで購入した。2000 円也。

http://m.buffalo.jp/product/input/keyboard/bskbb15/

Galaxy S6 Edge とも特に難しい設定は必要なくサクッと繋がった。配列が英語配列なので慣れは必要かもしれないけどなかなか快適。

2017 年 6 月 10 日(土)

ジョギング

  • 香椎浜 x 2.5 周

  • 走り始めたら気持ちが良かったので少し多目に走ってみた

午後からは

気になっていた事の調査、検証等を行う。

夕飯

久しぶりによし本の千ベロセットと天ぷら盛り合わせ。コスパ最高。

帰り際に酒屋でお水とか買っていたら小山さんと出会ってそのまま小山さんに連れられるがままに二次会、三次会へ。

だいぶん酔ってしもた。