Logstash cheat sheet

Elastic stack / ELK (Elasticsearch + Logstash + Kibana)

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

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

logstash の書籍

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

logstash

構成

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

この構成を取ることで、ログ収集と、ログの解析・構造化の処理が分離でき、スケールの余地と、ログを落とす可能性を低減する。
logstash architecture イメージ検索
Filebeat(送る) ↘︎
Filebeat(送る) → logstash-shipper(受け取りredisに送る) → redis(ブローカー) → logstash-indexer(パース・構造化) → Elasticsearch(蓄積・検索エンジン) → Kibana(可視化)
Filebeat(送る) ↗︎                      ↗︎
logstash-shipper(redisに送る)--------------↗︎
beaver(redisに送る)-------------------↗︎
私は各端末には Java 環境は入れたくないので Filebeat を使ってます。
(私は IoT ごっこと称して遊んでいるのですが) Arduino YUN の 32U4 部で計測したデータを AR9331 部 OpenWrt 上の python beaver を用いて redis に直接送ってます。

Filebeat:

端末(filebeat) ----> 解析サーバ(logstash-shipper)

logstash-shipper:

Filebeat の待ち受け(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 データベースを引いたり、AS 番号引いたり、apache の user agent の解析をしたりして自分が見たい情報に加工しています。

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 設定

filebeat.yml 例 (1.x -> 5.0 仮)

############################# Filebeat ######################################
filebeat:
  # List of prospectors to fetch data.
  prospectors:
    # Each - is a prospector. Below are the prospector specific configurations
    -
      paths:
        - /var/log/syslog
        - /var/log/mail.log
        - /var/log/auth.log
      input_type: log
      document_type: syslog
      fields_under_root: true

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

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

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

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

  # General filebeat configuration options
  #
  # Event count spool threshold - forces network flush if exceeded
  #spool_size: 2048

  # Defines how often the spooler is flushed. After idle_timeout the spooler is
  # Flush even though spool_size is not reached.
  #idle_timeout: 5s

  # Name of the registry file. Per default it is put in the current working
  # directory. In case the working directory is changed after when running
  # filebeat again, indexing starts from the beginning again.
  registry_file: /var/lib/filebeat/registry

  # Full Path to directory with additional prospector configuration files. Each file must end with .yml
  # These config files must have the full filebeat config part inside, but only
  # the prospector part is processed. All global options like spool_size are ignored.
  # The config_dir MUST point to a different directory then where the main filebeat config file is in.
  #config_dir:


###############################################################################
############################# Libbeat Config ##################################
# Base config file used by all other beats for using libbeat features

############################# Output ##########################################

# Configure what outputs to use when sending the data collected by the beat.
# Multiple outputs may be used.
output:
  ### Logstash as output
  logstash:
    # The Logstash hosts
    hosts: ["localhost:5044"]

    # Number of workers per Logstash host.
    #worker: 1

    # Set gzip compression level.
    #compression_level: 3

    # Optional load balance the events between the Logstash hosts
    #loadbalance: true

    # Optional index name. The default index name depends on the each beat.
    # For Packetbeat, the default is set to packetbeat, for Topbeat
    # top topbeat and for Filebeat to filebeat.
    #index: filebeat

    # Optional TLS. By default is off.
    ssl:
      # 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
      #key: "/etc/logstash/logstash-forwarder.key"

      #verification_mode: none
      verification_mode: none

      # Configure cipher suites to be used for TLS connections
      #cipher_suites: []

      # Configure curve types for ECDHE based cipher suites
      #curve_types: []

############################# Logging #########################################

# There are three options for the log ouput: syslog, file, stderr.
# Under Windos systems, the log files are per default sent to the file output,
# under all other system per default to syslog.
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 rotateeverybytes
  # limit is reached.
  #to_files: false
  to_files: true

  # To enable logging to files, to_files option has to be set to true
  files:
    # The directory where the log files will written to.
    #path: /var/log/mybeat
    path: /var/log/filebeat

    # The name of the files where the logs are written to.
    #name: mybeat
    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
    keepfiles: 7

  # Enable debug output for selected components. To enable all selectors use ["*"]
  # Other available selectors are beat, publish, service
  # Multiple selectors can be chained.
  #selectors: [ ]

  # Sets log level. The default log level is error.
  # Available log levels are: critical, error, warning, info, debug
  #level: error
  level: info

メンテナンス

/usr/share/logstash/bin/logstash-plugin list
/usr/share/logstash/bin/logstash-plugin list --verbose
/usr/share/logstash/bin/logstash-plugin update

plugin version 指定の方法

/usr/share/logstash/bin/logstash-plugin install --version=2.0.2 logstash-input-redis

lightweight shipper

  • beaver (redis に直接送る事ができる)
beaver : python daemon that munches on logs and sends their contents to logstash
  • 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
  • fail2ban
fail2ban grok pattern

パターンの作成

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

バグ?

どうも ":int" や ":float" 指定しているパターンで、パターンがマッチしたりしなかったりして、フィールドの有り無しが混在するケースで cast というか data type conversion が失敗するようにおもう。

対処としては、 grok pattern で data type 指定をしないで、filter 側で mutate convert するようにする。

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 以外はエラーになる。

tag or field

私もよく理解できていない。最近になって input-beats が tag に "beats_input_codec_plain_applied" とつけるようになって、いろいろ考えた。

Tags vs Fields - Logstash - Discuss Elasticsearch, Logstash and Kibana | Elastic

よく確認する tag は "_grokparsefailure" で、これは文字通りパースを失敗した時。こいつをトリガーで grok pattern を修正している。beaver は tag をつけて(空でも)送ってくる。これはいろいろな filter で "add_tag" や "remove_tag" で操作される。tag は filter 処理の制御フラグとして使われたりする。なので不審がらずに tag を利用する方針がよい。

名前が "tags" の array type の特殊な field であり、処理の制御等に利用される という理解でいいのかな?

rsyslog limit 解除

/etc/rsyslog.conf:

$SystemLogRateLimitInterval 0
$RepeatedMsgReduction off

JMX

私が出した issue に対する公式見解がでた。

https://github.com/elastic/logstash/issues/4319

Logstash 5.0 でメトリックスが LS 自体からとれるようになるらしい。

それはでは JMX うごかすw

LS 2.3.1 geoip issue

illegal latitude value
https://github.com/elastic/logstash/issues/4961

mapping type "geo_point" の型(変換)が 2.2.x と変わっている感じでエラー

この設定が影響しているっぽいが...(これを削除すればエラーは出ない)

          mutate { remove_field => [ "[postfix_geoip][location]" ] }
          mutate { add_field    => { "[postfix_geoip][location]"         => "%{[postfix_geoip][longitude]}" } }
          mutate { add_field    => { "[postfix_geoip][location]"         => "%{[postfix_geoip][latitude]}" } }

私の処理では固定の location だったのでこれでやりたいことはできたのだが、変数の場合はどうしたらよいのか?

          mutate { replace      => { "[postfix_geoip][location]"         => "-77.4875, 39.044" } }

geo_point は string type でないといけなさそう。

うーーーーむ。意識してないなぁ...

https://github.com/elastic/logstash/issues/5114


ちなみに elasticsearch-template.json が 5.0 版になっているらしくって注意。

Fix template for 5.0


Elastic Stack 5.0.0 upgrade memo

アップグレードは filebeat, logstash, elasticsearch, kibana の順番で行う。

Java8 が必要。(以下 Ubuntu の場合)

sudo add-apt-repository ppa:openjdk-r/ppa
sudo apt-get update
sudo apt-get install openjdk-8-jre openjdk-8-jre-headless
sudo update-alternatives --config java

repository setting

Install Elasticsearch with Debian Package

wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo apt-key add -
echo "deb https://artifacts.elastic.co/packages/5.x/apt stable main" | sudo tee -a /etc/apt/sources.list.d/elastic-5.x.list
sudo apt-get update
順番に upgrade するので、apt-get upgrade はしない。

filebeat upgrade

Upgrading

Upgrading from 1.x to 5.x

  • filebeat を停止する。
  • 設定ファイルを更新スクリプトを起動する。
sudo apt-get install filebeat
cd etc/logstash
sudo /usr/share/filebeat/scripts/migrate_beat_config_1_x_to_5_0.py filebeat.yml


  • 私は filebeat.yml を /etc/logstash に置いているので、/etc/default/filebeat を変更する。
DAEMON_ARGS="-c /etc/logstash/filebeat.yml -path.home /usr/share/filebeat -path.config /etc/filebeat -path.data /var/lib/filebeat -path.logs /var/log/filebeat"
  • filebeat を起動する。
ERR State for /var/log/hoge.log should have been dropped, but couldn't as state is not finished.
更新後 filebeat を起動するが、なぜかエラーになる。一旦停止し、再起動すると正常に稼動する。おそらく registry file の変更処理が問題。

logstash upgrade

Upgrading Logstash

  • logstash を停止する。
sudo apt-get install logstash
  • 起動スクリプトの args に追加
--path.settings /etc/logstash

複数個 logstash を起動する場合は、logfile の名前が衝突する。 (logstash-plain.log)

/etc/logstash/log4j2.properties でなんとかするか、もしくは log directory を変える。
  • ruby filter の記述を変更する。

Ruby Filter and Custom Plugin Developers

filter {
  ruby {
    codec => "event['name'] = 'Logstash'"
  }
  ruby {
    codec => "event['product']['version'] = event['major'] + '.' + event['minor']"
  }
}
filter {
  ruby {
    codec => "event.set('name', 'Logstash')"
  }
  ruby {
    codec => "event.set('[product][version]', event.get('major') + '.' + event.get('minor'))"
  }
}
カスタムプラグインをつかっている場合も同様の変更が必要。


  • Java系のオプションは /etc/logstash/jvm.options に記述する。
  • logstashを起動する。

elasticsearch upgrade

Upgrading Elasticsearch

慎重に。バックアップをとること。一度更新されるとロールバックできないので、完全バックアップをとる事。
指示にしたがい作業する。
kibana の index が reindex されたら kibana4 からは名前が変わってしまうので、kibana4 で確認作業をする場合は kibana の設定を変える。
elasticsearch 5.x と kibana5 になると alias が機能するので、元の名前に戻して大丈夫。
logstash の elasticsearch-template を 5.x 用に変える。(かなり変わっているので、よく調査すること)
.raw が .keyword になる。.raw を使いたければ template を変更すること。
logstash を停止して、elasticsearch 更新後起動する。
  • elasticsearch を停止する。
sudo apt-get install elasticsearch
  • Java系のオプションは /etc/elasticsearch/jvm.options に記述する。
  • elasticsearch を起動する。

kibana upgrade

Upgrading Kibana

  • kibana を停止する。
  • kibana の設定データをコピーする。
sudo mkdir /etc/kibana
sudo cp /opt/kibana/conf/kibana.yml /etc/kibana/
  • kibana をインストールする。
sudo apt-get install kibana
  • kibana を起動する。

.raw が .keyword になっているので注意。Object の変更が必要。

これは logstash の elasticsearch template の変更による。
.raw を使い続けたければ、template を変更する事。(私は もともと .raw を使わない template にしていたが、今回は .keyword を使って見る事にした)

elasticsearch の elasticsearch_deprecation.log にメッセージ出まくり。

Deprecated field [type] used, replaced by [match_phrase and match_phrase_prefix query]
github issue や discuss.elastic.co を漁り中だが見つからない。
おそらく query を
{
  "query": {
    "match": {
      "foo": {
        "query": "bar",
        "type": "phrase"
      }
    }
  }
}

から

{
  "query": {
    "match_phrase": {
      "foo": "bar"
    }
  }
}

でOK

kibana

ES 5.0.0 から、かなり mapping が変わったので、一旦様子見にはいる。 ES 2.x の .raw は .keyword

filter edit

"Discover" filter の編集ボタンを押して query 書く。

{
  "query": {
    "wildcard": {
      "foo": "bar*"
    }
  }
}

dashboard Timepicker を変更

relative でお好きに。

Field が未定義という filter

"Discover" で Field をクリックして "Quick Count" ででてくる数字をクリック。そして Invert すればよい。
5.x から '*' マークをクリックで Invert でも可能


dashboard URL

dashboard の URL の GET パラメータ

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

kibana screen shots

Elastic Stack 5.0.0

 

kibana4 の黒い画面で

 

Arduino YUN で計測した気象データを TimeLion で
YUN の AR9331 で python supervisord 配下の beaver から SSH tunnel で logstash broker である redis に送信。

 

kibana 4 で kibana 3 風に

 

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

 

迷惑メール

 


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

設定

実験環境(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'
/usr/bin/curator --config /etc/logstash/curator.yml  /etc/logstash/curator-delet-indexs.conf --dry-run
curator4 で大幅に書式変わった。
kopf web admin interface for elasticsearch
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]*)