Logstash cheat sheet

ELK (Elasticsearch + Logstash + Kibana)

splunk のデモをみて、自分の環境に logstash を入れてみた。 :)

(ELKの更新が速いので、随時記事をアップデートします。Elasticsearch 2.0.0, Logstash 2.0.0, Logstash Forwarder 0.4.0 (Filebeat 1.0.0-rc1), Kibana 4.2.0)
splunk のデモを見て、構造化ロギング・高速検索・可視化の素晴らしさが解ったので、それをオープンソースの ELK stack で実現する。
ELK でログ管理をしはじめて、いままで気付かなかった事がいろいろ見えて、かなり改善しました(実感!)

logstash の書籍

突っ込んだ内容ですの大変参考になります。
The Logstash Book

logstash

構成

Deploying with Message Queueing で構成してみた。(The Logstash Book に同様な構成の構築手順あり)

この構成を取ることで、ログ収集と、ログの解析・構造化の処理が分離でき、スケールの余地と、ログを落とす可能性を低減する。
logstash architecture イメージ検索
logstash-forwader/Filebeat(送る) ↘︎
logstash-forwader/Filebeat(送る) → logstash-shipper(受け取りredisに送る) → redis(ブローカー) → logstash-indexer(パース・構造化) → Elasticsearch(蓄積・検索エンジン) → Kibana(可視化)
logstash-forwader/Filebeat(送る) ↗︎                    ↗︎
logstash-shipper(redisに送る)ーーーーーーーーーーーーーーーーーーーーーー↗︎
beaver(redisに送る)ーーーーーーーーーーーーーーーーーーーーーーーーーー↗︎
私は各端末には Java 環境は入れたくないので logstash-forwarder (もうすぐ Filebeatに代わる) を使ってます。

logstash-forwarder (Filebeat):

端末(logstash-forwarder / Filebeat) ----> 解析サーバ(logstash-shipper)

logstash-shipper:

logstash-forwarder / Filebeat の待ち受け(input lumberjack / input beats)、ブローカーへそのまま吐き出す(output redis)

logstash-indexer:

ブローカーから逐次取り出し(input redis)、ログのパース・構造化(filter)、ESへ出力(output elasticsearch)
(解析サーバを1台で処理する場合は、indexer と shipper の java プロセスは別に起動したほうがいろいろ楽。パッケージ版の起動スクリプトを名前かえて二つにする)
INPUT  (PLUGINS)
FILTER (PLUGINS)
OUTPUT (PLUGINS)
簡単に言えば、なんらかの log (何かしらのデータ/IoTデバイスからも/この書式等は問わない/複数箇所からも) を input で取り込む。filter で正規表現でパターンマッチング (grok)して整形したり、さまざまな filter plugin で加工する。もちろん主キーになる時刻も定義する。その構造化した JSON を output elasticsearch で ES に送る。これだけです。(もちろん output 先は ES だけに限りません。output influxdb で influxDB に送って grafana で可視化も/複数箇所へも)


github に自分の設定をおいています。参考にしてください。
https://github.com/nxhack/logstash
logstash filter の geoip, ruby, kv, dns 逆引き等の典型的な使い方をしています。
たとえば apache のサーバでは IP の逆引きするのは無駄なので、解析サーバでホスト名を引くというような使い方ができます。
IP address から GeoIP データベースを引いたり、apache の user agent の解析をしたりして自分が見たい情報に加工しています。

logstash-forwarder (Filebeat)

SSL 証明書の件

IMPORTANT TLS/SSL CERTIFICATE NOTES
Logstash-forwarder is throwing SSL errors - Server Fault
IP address で サーバ指定している場合は、SAN (Subject Alternative Name) の証明書を作る必要がある。
/etc/logstash/openssl-logstash.cnf:
[req]
distinguished_name = req_distinguished_name
x509_extensions = v3_req
prompt = no

[req_distinguished_name]
C = AU
ST = Some-State
L =  Locality Name
O = Internet Widgits Pty Ltd
CN = *

[v3_req]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
basicConstraints = CA:TRUE
subjectAltName = @alt_names

[alt_names]
DNS.1 = *
DNS.2 = *.*
DNS.3 = *.*.*
DNS.4 = *.*.*.*
DNS.5 = *.*.*.*.*
DNS.6 = *.*.*.*.*.*
DNS.7 = *.*.*.*.*.*.*
IP.1 = 192.168.1.2
IP.2 = 127.0.0.1

[ v3_ca ]
subjectAltName = @alt_names
cd /etc/logstash
openssl req -config ./openssl-logstash.cnf -x509 -batch -nodes -days 365 -newkey rsa:2048 -sha256 -keyout ./logstash-forwarder.key -out ./logstash-forwarder.crt

Filebeat Migration

Logtash-Forwarder to Filebeat Migration

logstash-input-beats へ入れ替え

LS 1.5.x でも 2.x も可

cd /opt/logstash
./bin/plugin install logstash-input-beats

shipper.conf:

input {
  beats {
    port => 5000
    type => "ctrllogs"
    target_field_for_codec => "line"
    ssl => true
    ssl_certificate => "/etc/logstash/logstash-forwarder.crt"
    ssl_key => "/etc/logstash/logstash-forwarder.key"
  }
}
plugin 名を 'lumberjack' から 'beats' へ変更。'ssl => true' 行を追加 (SSL はデフォルト false)
クライアントが LSF のときは、 target_field_for_codec => "line" 行が必要。Filebeat になれば不要。

Filebeat 設定

(クライアント側はリリースされてパッケージが出たら作業する)

1.0.0-beta4 でちょっと動かしてみたら、LSF でよくあった証明書問題にひっかかるようだ。コードをみたら tls なんかまだおかしい気がするのでもう少し様子見したほうが良さそう。(insecure: true にしているのに InsecureSkipVerify がちゃんと設定されてない?)
やっぱり insesure option がうごいてなかった。 TLS insecure option is ignored for logstash · Issue #238 · elastic/libbeat
1.0.0-rc1 まで待つ...1.0.0-rc1 出たが...動かない...configかなりかわってる...LSFマイグレーションガイドはほぼ無かったことになってる...
shipper: セクション書くとうごいた...とりあえずテストする。
LSF 互換性が微妙(違うものであるからこれで良いのかもしれないが、違いを押さえておきたい)
LSF ではある host field がない。その代わり shipper field がある。また、file field が source field になってる。とりあえず issue あげといた。
offset field の mapping が long になってる。logstash 側で対処してみた。
/usr/bin/filebeat[9999]: transport.go:129: SSL client failed to connect with: x509: certificate signed by unknown authority
log.go:126: File reading error. Stopping harvester. Error: EOF
filebeat:
  prospectors:
    -
      paths:
        - /var/log/syslog
        - /var/log/mail.log
        - /var/log/auth.log
      input_type: log
      document_type: syslog

    -
      paths:
        - /var/log/apache2/access.log
      input_type: log
      document_type: apache

    -
      paths:
        - /var/log/apache2/other_vhosts_access.log
      input_type: log
      document_type: apache-other-vhost

    -
      paths:
        - /var/log/apache2/error.log
      input_type: log
      document_type: apache-error

    -
      paths:
        - /var/log/dpkg.log
      input_type: log
      document_type: dpkg

  #registry_file: /var/lib/logstash-forwarder/.logstash-forwarder
  #registry_file: /var/lib/logstash-forwarder/.filebeat
  registry_file: /var/lib/filebeat/registry

output:
  logstash:
    enabled: true

    # The Logstash hosts
    hosts: ["127.0.0.1:5000"]

    tls:
      disabled: false

      # List of root certificates for HTTPS server verifications
      certificate_authorities: ["/etc/logstash/logstash-forwarder.crt"]

      # Certificate for TLS client authentication
      #certificate: "/etc/logstash/logstash-forwarder.crt"

      # Client Certificate Key
      #certificate_key: "/etc/logstash/logstash-forwarder.key"

      # Controls whether the client verifies server certificates and host name.
      # If insecure is set to true, all server host names and certificates will be
      # accepted. In this mode TLS based connections are susceptible to
      # man-in-the-middle attacks. Use only for testing.
      insecure: true

shipper:
  # The name of the shipper that publishes the network data. It can be used to group
  # all the transactions sent by a single shipper in the web interface.
  # If this options is not defined, the hostname is used.
  name: ShipperHostName

  # The tags of the shipper are included in their own field with each
  # transaction published. Tags make it easy to group servers by different
  # logical properties.
  #tags: ["service-X", "web-tier"]

  # Uncomment the following if you want to ignore transactions created
  # by the server on which the shipper is installed. This option is useful
  # to remove duplicates if shippers are installed on multiple servers.
  #ignore_outgoing: true

logging:
  # Send all logging output to syslog. On Windows default is false, otherwise
  # default is true.
  #to_syslog: true
  to_syslog: false

  # Write all logging output to files. Beats automatically rotate files if configurable
  # limit is reached.
  #to_files: false
  to_files: true

  # Enable debug output for selected components.
  #selectors: []

  # Set log level
  #level: error
  level: INFO

  files:
    # The directory where the log files will written to.
    path: /var/log/filebeat

    # The name of the files where the logs are written to.
    name: filebeat.log

    # Configure log file size limit. If limit is reached, log file will be
    # automatically rotated
    rotateeverybytes: 10485760 # = 10MB

    # Number of rotated log files to keep. Oldest files will be deleted first.
    keepfiles: 7

これ忘れそうなので注意する事

The registry file stores the state and location from which Filbeat was reading last. Under Logstash-Forwarder it was called .logstash-fowarder. For Filebeat it was renamed to .filebeat or /usr/lib/filebeat/registry if you install from packages or C:\ProgramData\filebeat\registry if you run as a Windows service.
ここが rc1 とは違う...
   registry_file: /var/lib/filebeat/registry
とすることで記述にあわせられそうだが、どうもフォーマットも違っていそう...

メンテナンス

cd /opt/logstash
./bin/plugin list
./bin/plugin list --verbose
./bin/plugin update

plugin version 指定の方法

cd /opt/logstash
./bin/plugin install --version=2.0.2 logstash-input-redis

2015/08/21 LS 1.5.4 のバグ

Logstash 1.5.4 で配布されている logstash-input-lumberjack 1.0.4 で、
The error reported is: 
  uninitialized constant Concurrent::Delay::Executor

1.0.5 で fix : https://github.com/ph/logstash-input-lumberjack/commit/a3499b25cb2f03587ce8598c0df70fc80ce9beeb

cd /opt/logstash
./bin/plugin update --version=1.0.5 logstash-input-lumberjack
もちろん LS 1.5.5 や LS 2.0.0 は大丈夫

2015/11/06 LS 2.0.0 のバグ

jruby concurrent-ruby が 0.9.2 になって
RuntimeError: Logstash expects concurrent-ruby version 0.9.1 and version 0.9.2 is installed, please verify this patch: /opt/logstash/vendor/bundle/jruby/1.9/gems/logstash-core-2.0.0-java/lib/logstash/patches/silence_concurrent_ruby_warning.rb
Since concurrent-ruby 0.9.2 this patch isnt necessary. · elastic/logstash@972e13d
logstash-input-beats 0.9.5 で FIX

lightweight shipper

  • beaver (redis に直接送る事ができる)
beaver : python daemon that munches on logs and sends their contents to logstash
  • logstash-forwarder (昔の名前は lumberjack) (次の名前は Filebeat)
logstash-forwarder
elastic.co の repository に ubuntu i386 版がなくってアセった....
Filebeat というのに置き換わるそうだ。
Filebeat

parser / grok patterns

各種ログのパターン

  • logstash-patterns-core
logstash-patterns-core
  • apache
grok-patterns の COMBINEDAPACHELOG 
apache grok pattern
  • postfix
postfix grok pattern
  • sshd
sshd grok pattern
  • zimbra (mailbox.log, amavis)
mailbox.log grok pattern
amavis grok pattern

パターンの作成

  • デバッグ
Grok Debugger
  • 正規表現を思い出す ;)
正規表現の構文

geoip, user-agent

http://dev.maxmind.com/geoip/legacy/geolite/
http://download.maxmind.com/download/geoip/database/asnum/GeoIPASNum.dat.gz
http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz
https://github.com/ua-parser/uap-core/blob/master/regexes.yaml
https://raw.githubusercontent.com/ua-parser/uap-core/master/regexes.yaml

enable high precision timestamps

ログ管理は時刻がキーになるので、時刻の精度を高めたい (TraditionalFileFormat を前提にしている処理も多いので変更する際は要注意)

rsyslog の timestamp を milliseconds まで取る

/etc/rsyslog.conf の
# Use traditional timestamp format.                                                                                           
# To enable high precision timestamps, comment out the following line.                                                        
#                                                                                                                             
$ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat
の指示通り、"ActionFileDefaultTemplate" 行をコメントアウトする。
#$ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat

traditional と high precision 両方対応した syslog 用の logstash filter

    grok {
      match => { "message" => "(?:%{SYSLOGTIMESTAMP:syslog_timestamp}|%{TIMESTAMP_ISO8601:syslog_timestamp}) %{SYSLOGHOST:syslog_hostname} %{DATA:syslog_program}(?:[%{POSINT:syslog_pid:int}\])?: %{GREEDYDATA:syslog_message}" }                                                             
      add_field => {
	"syslog_received_at" => "%{@timestamp}"
	"syslog_received_from" => "%{host}"
      }
    }
    syslog_pri {
    }
    date {
      match => [ "syslog_timestamp", "MMM  d HH:mm:ss", "MMM dd HH:mm:ss", "ISO8601" ]
      timezone => "Asia/Tokyo"
      locale => "en"
    }
    mutate {
      replace => { "syslog_timestamp" => "%{@timestamp}" }
    }
(切り戻してもエラーがでないように mutate, replace 処理追加)

apache2.4 のログの場合(未確認)

%{%Y-%m-%dT%H:%M:%S}t.%{msec_frac}t%{%z}t

注意点

traditional timestamp から high precision timestamp に変える場合は、mapping type が string に代入するので問題は起こらない。
逆に high precision timestamp から traditional timestamp に戻す場合は、mapping type が date なので dateOptionalTime という format 以外はエラーになる。

kibana

ES 2.0.0 ではいま(2015/10/29)のところ kibana 4.1.2 が動かない。kibana 4.2.0 は apache-proxy 環境でうまく動作しない。早急に hack しまする...(ということはまだ ES 2.0.0 は入れちゃダメかな)

とりあえず ssh tunneling で
ssh -L 127.0.0.1:80:127.0.0.1:5601 USER@KIBANA_HOST

kibana 4

apache reverse proxy で network 制限と basic 認証をかける(できたら mod_ssl も)
    ProxyRequests Off
    ProxyPreserveHost On
    ProxyPass              /kibana/  http://127.0.0.1:5601/ disablereuse=On ttl=120 timeout=3000
    ProxyPassReverse       /kibana/  http://127.0.0.1:5601/ timeout=3000

    <Location /kibana>
      Order Allow,Deny
      Allow from 127.0.0.1 *ALLOW-NETWORKS*
      <IfModule mod_authn_file.c>
        AuthUserFile /path/htpasswd
	AuthType Basic
      </IfModule>
      require valid-user
    </Location>

kibana 3 から kibana 4

map

map 用の geoip の field に geo_point 属性を付けてやる必要がある。elasticsearch-template.json を元に必要な設定を追加する。
you need to alter the template provided with the Elasticsearch output and configure the output to use the new template.
logstash ES output に template 行を追加する。
output {
  elasticsearch {
    hosts => ["127.0.0.1"]
    template => "/etc/logstash/elasticsearch-template.json"
    template_overwrite => true
  }
}
もちろん各フィールドについても適切なマッピングをするべき。ES 2.x では(以前より早くなった) doc_values をうまく使うことも考慮する。
私は、type: string はすべて not_analyzed にして、本当に必要なフィールドのみ analyzed にするようにした。

(2015/11/02) LS 2.0.0 の logstash-output-elasticsearch (2.1.2) で配布される elasticsearch-template.json は ".raw" が生成されない。2.1.3 で元に戻しそうだが、やはり analyzed not_analyzed とか field type の mapping は自分でコントロールする癖をつけたほうが良いと思う。

".raw" がないから kibana でエラー出まくりだった...

filter edit

kibana 4 の "Discover" filter は kibana 3 のように柔軟な編集機能がまだ実装されていない

いったん Save しておいて "Setting" -> "Objects" から "Edit visualization Object" や "Edit search Object" で直接編集すれば可能。
      "query": {
        "wildcard": {
          "foo": "bar*"
        }
      }

dashboardの初期 Timepicker を任意に変更

いったん Save しておいて "Setting" -> "Objects" から "Edit dashboard Object" の timeFrom で直接編集すれば可能。

Field が未定義という filter

"Discover" で Field をクリックして "Quick Count" ででてくる数字をクリック。そして Invert すればよい。
このあたりの改善は kibana 4.3.0 ぐらいには実装されそう。

dashboard URL

dashboard の URL の GET パラメータ

  • panels
    • row  : 一番上は1
    • col  : size_x が 12より小さいときの横の開始位置
    • size_x : 横幅全部は12、横幅半分は6
    • size_y : パネルの高さ(縦方向の大きさ)
    • type  : visualization, search

kibana screen shots

kibana 4 で kibana 3 風に

ファイル:Kibana4-apache.png

kibana 4 で ssh の攻撃元マップ Heatmap カッコイイ

ファイル:Kibana4-sshd-heatmap.png

迷惑メール

ファイル:Kibana4-amavis.png

メモ

テスト用途で Kibana index の replica を作りたく無い場合 (Standalone な ES の health status を Green にしたい場合)

./src/plugins/elasticsearch/lib/create_kibana_index.js:
        number_of_replicas: 0

Elasticsearch

構造

http://127.0.0.1:9200/{INDEX}/{TYPE:mapping}/{ID:Document}
http://127.0.0.1:9200/{INDEX}/{TYPE:mapping}/{ID:Document}/_source
http://127.0.0.1:9200/{INDEX}/{TYPE:mapping}/_mapping
http://127.0.0.1:9200/{INDEX}/{TYPE:mapping}/_mapping?pretty
http://127.0.0.1:9200/_search?q=tags:_grokparsefailure
http://127.0.0.1:9200/_cluster/health?pretty
http://127.0.0.1:9200/_template?pretty
http://127.0.0.1:9200/kibana-int/_search?q=*:*&pretty
http://127.0.0.1:9200/kibana-int/_search?q=*:*&size=100&pretty
http://127.0.0.1:9200/kibana-int/_search/?size=100&pretty
http://127.0.0.1:9200/_nodes?clear&all&pretty

設定

実験環境(m3.large)で 7.5GB しかメモリがないので、まだ時々 "java.lang.OutOfMemoryError: Java heap space" がでてしまう。 少しずつ手なずけ中...
elasticsearch.yml で特別に意識して設定して実験しているのは、
bootstrap.mlockall: true
あとは tcsh の rmstar 的な "action.destructive_requires_name: true" か
起動スクリプトでは
ES_HEAP_SIZE=3g (主メモリーの半分以下で)
MAX_LOCKED_MEMORY=unlimited
まだまだノウハウが足りないで実験中。
デフォルト値で無制限の indices.fielddata.cache.size を設定することで OOM は少なくなりそう。実験中...
http://www.elastic.co/guide/en/elasticsearch/guide/master/_limiting_memory_usage.html#fielddata-size
これによると indices.fielddata.cache.size を設定するのは、あくまでもメモリ不足を緩和する為だけで、本来はもっとメモリーを増やすのが本道とのこと。
まー OOM になるよるはましなので、無制限ではなくって ギリギリ目一杯 の設定にしておくのがいいかも。
http://evertrue.github.io/blog/2014/11/16/3-performance-tuning-tips-for-elasticsearch/
ES_HEAP_SIZE=3g の場合 indices.fielddata.cache.size: 30% が限界かも...
いちど頭打つとかなり処理速度が遅くなるようだ。
新しいハマりどころで、kibana で index pattern を再構築しようとして、
failed to execute [org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsIndexRequest@XXXXXXXX]
対処はメモリー増やすか、index 削除ぐらい。(curator で定期的に削除する方法をとるかな...)

メンテナンス

elasticsearch-curator
/usr/local/bin/curator --host 127.0.0.1 delete indices --older-than 90 --time-unit days --timestring '%Y.%m.%d'
elasticsearch-head
Elastic HQ
メモメモ (sysdig の パース実験中なので、type:sysdig をいろいろ削除したい
curl -XDELETE 'http://127.0.0.1:9200/logstash-YYYY.MM.DD/sysdig/_query?q=tags:_grokparsefailure'
curl -XDELETE 'http://127.0.0.1:9200/logstash-YYYY.MM.DD/sysdig'

memo

munin

logstash をモニタリングする munin plugin (なんか微妙なのですが munin ファンなので私)
https://raymii.org/s/software/Munin_plugin_Logstash_Kibana_messages_per_hour.html
elasticsearch の日付は UTC なので、マシンの時刻が JST な場合は、スクリプト内に date を date -u にしておく。
日付またぎ問題を大胆に処理してみた。
TOTAL_EVENTS=$(curl -s -k -XGET http://127.0.0.1:9200/logstash-`/bin/date -u --date "1 day ago" +%Y.%m.%d`,logstash-`/bin/date -u +%Y.%m.%d`/_search -d '{ "size": 0, "query": { "filtered": { "query": { "match_all": { } }, "filter": { "range": { "@timestamp": { "from": "'`/bin/date -u --date "1 hours ago" +%Y-%m-%dT%H:00:00`'", "to": "'`/bin/date -u +%Y-%m-%dT%H:00:00`'" } } } } }, "from": 0, "sort": { "@timestamp": { "order": "desc" } }}' | /bin/grep --only \"hits\"\:\{\"total\"\:[0-9]*,\" | /bin/grep -o [0-9]*)

おもいっきりメモ

stty -f /dev/tty.usbserial-XXXXXX 9600
cat /dev/tty.usbserial-XXXXXX | logstash-forwarder -config logstash-forwarder-arduino.conf
{
  "network": {
    "servers": [ "172.16.2.3:5000" ],
    "timeout": 15,
    "ssl strict verify": false,
    "ssl ca": "/usr/local/etc/logstash/logstash-forwarder.crt"
  },
  "files": [
    {
      "paths": [ "-" ],
      "fields": { "type": "stdin" }
    }
  ]
}