Logstash cheat sheet: Difference between revisions

From misc notes
Jump to navigation Jump to search
(ページの作成:「splunk のデモをみて、自分の環境に logstash を入れてみた。 :) [http://logstash.net/ logstash - open source log management] どうせやるなら...」)
 
 
(901 intermediate revisions by the same user not shown)
Line 1: Line 1:
splunk のデモをみて、自分の環境に logstash を入れてみた。 :)
= Elastic stack / ELK (Elasticsearch + Logstash + Kibana) =


  [http://logstash.net/ logstash - open source log management]
'''諸般の事情により更新休止します'''
 
== 久しぶりの追記 ==
久しぶりに logstash.conf を修正したら、割と重要な仕様変更がたくさんあり、過去の記述は現在の仕様に合ってないです。ちなみに ruby code を追記したのですが、event.get event.set とかになっている。
<syntaxhighlight lang="javascript" enclose="div">
  ruby {
      code => "event.set('foo',event.get('foo')+ 5.1)"
  }
</syntaxhighlight>
こんな感じ。
 
その他、認証系強化による仕様の混乱はとりあえずなんとかするしかないw
 
== splunk のデモをみて、自分の環境に logstash を入れてみた。 :) ==
:(ELKBの更新が速いので、随時記事をアップデートします。[https://www.elastic.co/downloads/elasticsearch Elasticsearch 7.6.2], [https://www.elastic.co/downloads/logstash Logstash 7.6.2], [https://www.elastic.co/downloads/beats/filebeat Filebeat 7.6.2], [https://www.elastic.co/downloads/kibana Kibana 7.6.2])
 
:[http://ja.splunk.com/ splunk] のデモを見て、構造化ロギング・高速検索・可視化の素晴らしさが解ったので、それをオープンソースの Elastic stack (ELK stack) で実現する。
:ELK でログ管理をしはじめて、いままで気付かなかった事がいろいろ見えて、かなり改善しました(実感!)
 
最近の Elastic Stack は logstash いらずで簡易にという方向を狙ってきている。それはそれで嬉しいが、いろいろ細かく触りたい場合には、まだまだ logstash をホゲらないと逝けない。
 
::完全に通常の運用につかっているので、アグレッシブな変更はできなくなってるので突っ込んだ記事がかけない^^;;;
 
 
7.6.0 は kibana の index の変換するのだが、elasticseach のサーキットブレーカーが作動して完了しない。
:一時的に elasticsearch の heap 増やした。(最終的には、今回の件がギリギリ回避できるメモリー量に増やした)
 
7.6.0 から X-Pack の概念が変わった(なくなった?)
:logstash.yml から xpack の設定をコメントアウト
 
timelion の位置付けが変わった。
 
kibana.ymlに
<syntaxhighlight lang="yaml" enclose="div">
timelion.ui.enabled: true
</syntaxhighlight>
で元に戻る。設定を確認して、新しいビジュアライズに移行する。
 
 
7.4.1 の logstash がダメっぽい。ヘビー io-wait
:以前よりメモリー食いになってるようで、ES も含めて頑張って使用メモリー削減してかろうじて稼働中
:: dns filter がぁ failed_cache_size ちゃんと設定しないとまずい。
 
'''ようやく 7.x にあげた'''
 
あら...意外と簡単に入った 7.4.0...でもないぞ。
 
よく見たら index 名が変わって Index Lifecycle Management がよしなにしてしまうようで、昔に戻すには elasticsearch output pulgin で
<syntaxhighlight lang="javascript" enclose="div">
ilm_enabled => false
</syntaxhighlight>
 
kibana の index pattern を削除したあとトラブル。新しい index pattern 作っているのに index pattern が無いので作れといわれる
 
解決策は、新しい index pattern を作るときに、advanced options を表示して、Custom index pattern ID に index pattern と同じ文字をいれる。たとえば index pattern が "logstash-*" なら Custom index pattern ID も "logstash-*" とする。
 
私は '*' という文字が嫌なので(あとで問題起きそう)、全部 id を書き換えた。
 
filebeat.yml で filebeat.registry_file 行削除すること
 
logstash の elasticsearch-template を変更
<syntaxhighlight lang="javascript" enclose="div">
    "_default_" : {
    ****
    }
</syntaxhighlight>
を削除
 
python beaver から送られる 'host' を remove
<syntaxhighlight lang="javascript" enclose="div">
    mutate {
      rename => { "host" => "my_host" }
    }
    mutate {
      add_field => { "[host][name]" => "%{my_host}" }
    }
</syntaxhighlight>
 
beats が送っていた "host" は host.name に
[host][name]
 
agent.* が増えた
 
7.0.0 出た! テストは気力があるときwにします。。。
 
6.6.1 で geoip.postal_code の型がコンフリクト
 
[https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/788/files#diff-c1b7e63b1e6f2c2cfe8656fa847ecba5 "postal_code" : { "type" : "keyword" }]
 
6.5.0 で kibana の index が変更されて .kibana_1 .kibana_2 というのができた。これですこしハマった。
 
6.2.0 で /etc/elasticsearch/jvm.options
-Djava.io.tmpdir=${ES_TMPDIR}
:: ES_TMPDIR の定義がないのでエラーになる。
 
'''filebeat 6.3.0 は問題ありそう。6.2.4 のままで様子を見る。'''
"error"=>{"type"=>"mapper_parsing_exception", "reason"=>"failed to parse [host]"
:::[https://github.com/elastic/beats/issues/7050 Metricbeat `host` namespace causes mapping conflict when used with Logstash]
:::[https://discuss.elastic.co/t/logstash-errors-after-upgrading-to-filebeat-6-3-0/135984/5 Logstash errors after upgrading to filebeat-6.3.0]
 
 
[https://github.com/elastic/beats/blob/master/libbeat/docs/breaking.asciidoc#breaking-changes-in-63 Breaking changes in 6.3]
:ここに着地
 
<syntaxhighlight lang="javascript" enclose="div">
  "mappings" : {
      "properties" : {
        "host"  : {
          "dynamic": true,
          "properties" : {
            "name": { "type": "keyword" },
            "id" : { "type" : "keyword" },
            "architecture" : { "type" : "keyword" },
            "os" : {
              "dynamic" : true,
              "properties" : {
                "platform": { "type": "keyword" },
                "version": { "type": "keyword" },
                "family": { "type": "keyword" }
            }
            "ip" : { "type" : "ip" },
            "mac" : { "type" : "keyword" }
          }
        }
      }
    }
  }
</syntaxhighlight>
:こんな感じの template でいいのかねぇ
::[https://github.com/elastic/ecs Elastic Common Schema] こんなこと計画してるらしい
 
それか無視するか
<syntaxhighlight lang="javascript" enclose="div">
  # For Beat and LSF compatibility
  if [beat][name] {
    # Remove host metadata
    mutate {
      remove_field => [ "[host]" ]
    }
    mutate {
      add_field => {
        "host" => "%{[beat][name]}"
      }
    }
</syntaxhighlight>
:beat.hostname ではなく beat.name つかえと...
 
===logstash の書籍===
:突っ込んだ内容ですの大変参考になります。
  [http://www.logstashbook.com/ The Logstash Book]
 
= logstash =
== 構成 ==
[https://www.elastic.co/guide/en/logstash/current/deploying-and-scaling.html#deploying-message-queueing Deploying with Message Queueing] で構成してみた。([http://www.logstashbook.com/ The Logstash Book] に同様な構成の構築手順あり)
:この構成を取ることで、ログ収集と、ログの解析・構造化の処理が分離でき、スケールの余地と、ログを落とす可能性を低減する。
:[https://www.google.co.jp/search?q=logstash+architecture&tbm=isch logstash architecture イメージ検索]


どうせやるなら、Centralized Setup with Event Parsing で構成してみた。
[http://www.logstash.net/docs/1.1.9/tutorials/getting-started-centralized]
このページの構成図のようにしたが、Web インターフェースは [http://kibana.org/ Kibana] のほうがいい感じ。
<pre>
<pre>
logstash-shipper -> redis -> logstash-indexer -> Elasticsearch -> Kibana
Filebeat(送る) ↘︎
Filebeat(送る) → logstash-shipper(受け取りredisに送る) → redis(ブローカー) → logstash-indexer(パース・構造化) → Elasticsearch(蓄積・検索エンジン) → Kibana(可視化)
Filebeat(送る) ↗︎                      ↗︎
logstash-shipper(redisに送る)--------------↗︎
beaver(redisに送る)-------------------↗︎
Filebeat(redisに送る)-----------------↗︎
</pre>
</pre>
:最近は Kafka を broker にするのが良さげか?
:私は各端末には Java 環境は入れたくないので [https://github.com/elastic/filebeat Filebeat] を使ってます。
::(私は IoT ごっこと称して遊んでいるのですが) Arduino YUN の 32U4 部で計測したデータを AR9331 部 OpenWrt 上の python beaver を用いて redis に直接送ってます。
Filebeat:
端末(filebeat) ----> 解析サーバ(logstash-shipper)
[端末(filebeat) ----> 解析・蓄積(Elasticsearch Ingest Node)]
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 https://github.com/nxhack/logstash]
:logstash filter の '''geoip''', '''ruby''', '''kv''', '''dns''' 逆引き等の典型的な使い方をしています。
:たとえば apache のサーバでは IP の逆引きするのは無駄なので、解析サーバでホスト名を引くというような使い方ができます。
:IP address から GeoIP データベースを引いたり、AS 番号引いたり、apache の user agent の解析をしたりして自分が見たい情報に加工しています。
== Filebeat ==
=== SSL 証明書の件 ===
[https://github.com/elastic/logstash-forwarder/blob/master/README.md#important-tlsssl-certificate-notes IMPORTANT TLS/SSL CERTIFICATE NOTES]
[http://serverfault.com/questions/633681/logstash-forwarder-is-throwing-ssl-errors Logstash-forwarder is throwing SSL errors - Server Fault]
:IP address で サーバ指定している場合は、SAN (Subject Alternative Name) の証明書を作る必要がある。
:/etc/logstash/openssl-logstash.cnf:
<syntaxhighlight lang="text" enclose="div">
[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
</syntaxhighlight>
<syntaxhighlight lang="bash" enclose="div">
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
</syntaxhighlight>
<!--
=== Logtash-Forwarder to Filebeat Migration ===
[https://github.com/elastic/beats/blob/master/filebeat/docs/migration.asciidoc Logtash-Forwarder to Filebeat Migration]
-->
<!--
==== logstash-input-lumberjack から logstash-input-beats へ入れ替え ====
LS 1.5.x でも 2.x も可
<syntaxhighlight lang="bash" enclose="div">
cd /opt/logstash
./bin/logstash-plugin install logstash-input-beats
</syntaxhighlight>
shipper.conf:
<syntaxhighlight lang="javascript" enclose="div">
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"
  }
}
</syntaxhighlight>
: plugin 名を 'lumberjack' から 'beats' へ変更。'ssl => true' 行を追加 (SSL はデフォルト false)
: クライアントが LSF のときは、 target_field_for_codec => "line" 行が必要。Filebeat になれば不要。
-->
==== Filebeat 設定 ====
'''filebeat.yml 例 (6.0 仮)'''
: 6.0 は type が使えないので log_type という名前のカスタムフィールドに変更する。
::logstash 使うので filebeat modules は使わない。
:::modules 勉強しないといけない。
::::もともと logstash から入ったので modules は私には不要かも...
<syntaxhighlight lang="yaml" enclose="div">
######################## Filebeat Configuration ############################
#=========================== Filebeat prospectors =============================
filebeat.inputs:
#filebeat.prospectors:
- type: log
  paths:
    - /var/log/syslog
    - /var/log/mail.log
    - /var/log/auth.log
  fields:
    log_type: syslog
  fields_under_root: true
- type: log
  paths:
    /var/log/apache2/access.log
  fields:
    log_type: apache
  fields_under_root: true
- type: log
  paths:
    /var/log/apache2/other_vhosts_access.log
  fields:
    log_type: apache-other-vhost
  fields_under_root: true
- type: log
  paths:
    /var/log/apache2/error.log
  fields:
    log_type: apache-error
  fields_under_root: true
- type: log
  paths:
    /var/log/varnish/varnishncsa.log
  fields:
    log_type: varnish
  fields_under_root: true
- type: log
  paths:
    /var/log/dpkg.log
  fields:
    log_type: dpkg
  fields_under_root: true
- type: log
  paths:
    /var/log/fail2ban.log
  fields:
    log_type: fail2ban
  fields_under_root: true
#========================= Filebeat global options ============================
filebeat.registry_file: /var/lib/filebeat/registry
#================================ Outputs ======================================
#----------------------------- Logstash output ---------------------------------
output.logstash:
  # The Logstash hosts
  hosts: ["localhost:5044"]
  # Optional SSL. By default is off.
  # List of root certificates for HTTPS server verifications
  ssl.certificate_authorities: ["/etc/logstash/logstash-forwarder.crt"]
  # Certificate for TLS client authentication
  #ssl.certificate: "/etc/logstash/logstash-forwarder.crt"
  # Client Certificate Key
  #ssl.key: "/etc/logstash/logstash-forwarder.key"
  # Configure SSL verification mode. If `none` is configured, all server hosts
  # and certificates will be accepted. In this mode, SSL based connections are
  # susceptible to man-in-the-middle attacks. Use only for testing. Default is
  # `full`.
  #ssl.verification_mode: full
  ssl.verification_mode: none
#================================ Logging ======================================
# There are three options for the log output: syslog, file, stderr.
# Under Windows systems, the log files are per default sent to the file output,
# under all other system per default to syslog.
# Sets log level. The default log level is info.
# Available log levels are: critical, error, warning, info, debug
#logging.level: info
logging.level: info
# Enable debug output for selected components. To enable all selectors use ["*"]
# Other available selectors are "beat", "publish", "service"
# Multiple selectors can be chained.
#logging.selectors: [ ]
# Send all logging output to syslog. The default is false.
#logging.to_syslog: true
logging.to_syslog: false
# If enabled, filebeat periodically logs its internal metrics that have changed
# in the last period. For each metric that changed, the delta from the value at
# the beginning of the period is logged. Also, the total values for
# all non-zero internal metrics are logged on shutdown. The default is true.
#logging.metrics.enabled: true
# The period after which to log the internal metrics. The default is 30s.
#logging.metrics.period: 30s
# Logging to rotating files files. Set logging.to_files to false to disable logging to
# files.
logging.to_files: true
logging.files:
  # Configure the path where the logs are written. The default is the logs directory
  # under the home path (the binary location).
  #path: /var/log/filebeat
  path: /var/log/filebeat
  # The name of the files where the logs are written to.
  #name: filebeat
  name: filebeat.log
  # Configure log file size limit. If limit is reached, log file will be
  # automatically rotated
  #rotateeverybytes: 10485760 # = 10MB
  rotateeverybytes: 10485760 # = 10MB
  # Number of rotated log files to keep. Oldest files will be deleted first.
  #keepfiles: 7
  keepfiles: 7
  # The permissions mask to apply when rotating log files. The default value is 0600.
  # Must be a valid Unix-style file permissions mask expressed in octal notation.
  #permissions: 0600
# Set to true to log messages in json format.
#logging.json: false
</syntaxhighlight>
== メンテナンス ==
<syntaxhighlight lang="bash">
/usr/share/logstash/bin/logstash-plugin list
/usr/share/logstash/bin/logstash-plugin list --verbose
/usr/share/logstash/bin/logstash-plugin update
</syntaxhighlight>
===plugin version 指定の方法===
<syntaxhighlight lang="bash">
/usr/share/logstash/bin/logstash-plugin install --version=3.1.1 logstash-input-redis
</syntaxhighlight>
== lightweight shipper ==
*beaver (redis に直接送る事ができる)
[https://github.com/josegonzalez/beaver beaver : python daemon that munches on logs and sends their contents to logstash]
*Filebeat
[https://github.com/elastic/beats Filebeat]
== parser / grok patterns ==
===各種ログのパターン===
*logstash-patterns-core
[https://github.com/logstash-plugins/logstash-patterns-core/tree/master/patterns logstash-patterns-core]
*apache
[https://github.com/logstash-plugins/logstash-patterns-core/blob/master/patterns/httpd 公式 pattern の COMBINEDAPACHELOG]
[https://github.com/nxhack/logstash/blob/master/patterns/apache apache grok pattern]
*postfix
[https://github.com/nxhack/logstash/blob/master/patterns/postfix postfix grok pattern]
*sshd
[https://github.com/nxhack/logstash/blob/master/patterns/sshd sshd grok pattern]
*zimbra (mailbox.log, amavis)
[https://github.com/nxhack/logstash/blob/master/patterns/zimbra mailbox.log grok pattern]
[https://github.com/nxhack/logstash/blob/master/patterns/amavis amavis grok pattern]
*fail2ban
[https://github.com/nxhack/logstash/blob/master/patterns/fail2ban fail2ban grok pattern]
===パターンの作成===
*デバッグ
[https://grokdebug.herokuapp.com/ Grok Debugger]
*正規表現を思い出す ;)
[https://msdn.microsoft.com/ja-jp/library/cc392020.aspx 正規表現の構文]
=== バグ? ===
どうも ":int" や ":float" 指定しているパターンで、パターンがマッチしたりしなかったりして、フィールドの有り無しが混在するケースで cast というか data type conversion が失敗するようにおもう。
対処としては、 grok pattern で data type 指定をしないで、filter 側で mutate convert するようにする。
== geoip, user-agent ==
http://dev.maxmind.com/geoip/geoip2/geolite2/
http://geolite.maxmind.com/download/geoip/database/GeoLite2-City.mmdb.gz
http://geolite.maxmind.com/download/geoip/database/GeoLite2-Country.mmdb.gz
http://geolite.maxmind.com/download/geoip/database/GeoLite2-ASN.tar.gz
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
geoip 更新処理
<syntaxhighlight lang="bash" enclose="div">
wget http://geolite.maxmind.com/download/geoip/database/GeoLite2-City.mmdb.gz
wget http://geolite.maxmind.com/download/geoip/database/GeoLite2-Country.mmdb.gz
wget http://geolite.maxmind.com/download/geoip/database/GeoLite2-ASN.tar.gz
rm *.old
mv GeoLite2-City.mmdb GeoLite2-City.mmdb.old
mv GeoLite2-Country.mmdb GeoLite2-Country.mmdb.old
mv GeoLite2-ASN.mmdb GeoLite2-ASN.mmdb.old
gunzip GeoLite2-City.mmdb.gz
gunzip GeoLite2-Country.mmdb.gz
tar xfz GeoLite2-ASN.tar.gz --strip=1 --wildcards */GeoLite2-ASN.mmdb
rm GeoLite2-ASN.tar.gz
</syntaxhighlight>
== 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===
<syntaxhighlight lang="javascript" enclose="div">
    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}" }
    }
</syntaxhighlight>
:(切り戻してもエラーがでないように 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" とつけるようになって、いろいろ考えた。
[https://discuss.elastic.co/t/tags-vs-fields/24014 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:
<syntaxhighlight lang="text" enclose="div">
$SystemLogRateLimitInterval 0
$RepeatedMsgReduction off
</syntaxhighlight>
== JMX ==
私が出した [https://github.com/elastic/logstash/issues/4666 issue] に対する公式見解がでた。
[https://github.com/elastic/logstash/issues/4319 https://github.com/elastic/logstash/issues/4319]
Logstash 5.0 でメトリックスが LS 自体からとれるようになるらしい。
:それはでは JMX うごかすw
Logstash 5.0.0 GA につき、Monitor API を使った munin plugin 作ってみた。
[https://github.com/nxhack/munin-plugin-logstash https://github.com/nxhack/munin-plugin-logstash]
Elastic Stack 純正のモニタリングパッケージ [https://www.elastic.co/products/x-pack X-Pack] はこれから試す。
== X-Pack ==
Basic ライセンスというのが Free で、ライセンスを1年ごとに更新していけば、ずっと無料でつかえそうだ。
:6.3.0 から Basic ライセンスは有効期限が無制限になった。また面倒だったアップテート時の x-pack のインストース作業も不要になった。
自分のテスト環境はシングルノードなので status が YELLOW にならないように、
/usr/share/elasticsearch/plugins/x-pack/x-pack-core/x-pack-core-6.2.4.jar
:テンプレート json の index.number_of_replicas を変更する。
curl -XDELETE 'http://127.0.0.1:9200/_template/.monitoring-logstash'
curl -XDELETE 'http://127.0.0.1:9200/_template/.monitoring-alerts'
curl -XDELETE 'http://127.0.0.1:9200/_template/.monitoring-es-2'
curl -XDELETE 'http://127.0.0.1:9200/_template/.monitoring-es'
curl -XDELETE 'http://127.0.0.1:9200/_template/.monitoring-data-2'
curl -XDELETE 'http://127.0.0.1:9200/_template/.monitoring-kibana-2'
curl -XDELETE 'http://127.0.0.1:9200/_template/.monitoring-kibana'
作ってしまった index の index.number_of_replicas を変更する。
<syntaxhighlight lang="bash" enclose="div">
curl -XPUT 'http://localhost:9200/.monitoring-es-6-2017.12.05/_settings' -H 'Content-Type: application/json' -d'
{
    "index" : {
        "number_of_replicas" : "0"
    }
}
'
curl -XPUT 'http://localhost:9200/.monitoring-logstash-6-2017.12.05/_settings' -H 'Content-Type: application/json' -d'
{
    "index" : {
        "number_of_replicas" : "0"
    }
}
'
curl -XPUT 'http://localhost:9200/.monitoring-kibana-6-2017.12.05/_settings' -H 'Content-Type: application/json' -d'
{
    "index" : {
        "number_of_replicas" : "0"
    }
}
'
</syntaxhighlight>
Elastic Stack がアップデートされたら、いちいち明示的に X-Pack をアップデートしなければいけないのは萎える。
:6.3.0 から標準パッケージにはいったっぽい。
<syntaxhighlight lang="bash" enclose="div">
systemctl stop logstash
systemctl stop kibana
systemctl stop elasticsearch
cd /usr/share/logstash
./bin/logstash-plugin install logstash-output-statsd
./bin/logstash-plugin install logstash-filter-throttle
./bin/logstash-plugin install logstash-filter-sleep
systemctl start elasticsearch
systemctl start kibana
systemctl start logstash
</syntaxhighlight>
また、elasticsearch を(再)起動する時点で、kibana や logstash が稼働している場合に、monitor を突きにくるので、認証エラーが多発する。
これは無視してよいが気持ち悪い。
Authentication of [kibana] was terminated by realm [reserved] - failed to authenticate user [kibana]
Authentication of [logstash_system] was terminated by realm [reserved] - failed to authenticate user [logstash_system]
== LS 2.3.1 geoip issue ==
illegal latitude value
[https://github.com/elastic/logstash/issues/4961 https://github.com/elastic/logstash/issues/4961]
mapping type "geo_point" の型(変換)が 2.2.x と変わっている感じでエラー
この設定が影響しているっぽいが...(これを削除すればエラーは出ない)
<syntaxhighlight lang="javascript" enclose="div">
          mutate { remove_field => [ "[postfix_geoip][location]" ] }
          mutate { add_field    => { "[postfix_geoip][location]"        => "%{[postfix_geoip][longitude]}" } }
          mutate { add_field    => { "[postfix_geoip][location]"        => "%{[postfix_geoip][latitude]}" } }
</syntaxhighlight>
私の処理では固定の location だったのでこれでやりたいことはできたのだが、変数の場合はどうしたらよいのか?
<syntaxhighlight lang="javascript" enclose="div">
          mutate { replace      => { "[postfix_geoip][location]"        => "-77.4875, 39.044" } }
</syntaxhighlight>
geo_point は string type でないといけなさそう。
うーーーーむ。意識してないなぁ...
[https://github.com/elastic/logstash/issues/5114 https://github.com/elastic/logstash/issues/5114]
ちなみに elasticsearch-template.json が 5.0 版になっているらしくって注意。
[https://github.com/logstash-plugins/logstash-output-elasticsearch/commit/4abd353ff7b058f8142fe2d4ee2dd06408d0aab1 Fix template for 5.0]
<!--
== redis version ==
logstash-input-redis 2.0.3 でとうとう redis 2.2 がうごかなくなった。
:message=>"Redis connection problem", :exception=>#<Redis::CommandError: ERR unknown command 'script'>, :level=>:warn
これは Lua EVAL 機能を使い始めたかららしい(ストアドプロシージャみないなものかな)。ppa の redis 3.0 に上げた。
-->
== geoip support for GeoIPLite2-ASN database ==
4.2.1 でうごくか...
<syntaxhighlight lang="bash" enclose="div">
/usr/share/logstash/bin/logstash-plugin update logstash-filter-geoip
Updating logstash-filter-geoip
Updated logstash-filter-geoip 4.1.1 to 4.2.1
</syntaxhighlight>
<syntaxhighlight lang="json" enclose="div">
geoip {
          database => "/etc/logstash/geoip/GeoLite2-ASN.mmdb"
          source => "postfix_client_ip"
          target => "postfix_bgp"
        }
</syntaxhighlight>
いけた!
<syntaxhighlight lang="json" enclose="div">
    "postfix_bgp": {
      "as_org": "Towerstream I, Inc.",
      "ip": "64.17.249.242",
      "asn": 33224
    },
</syntaxhighlight>
== Raspberry Pi ==
[https://beats-nightlies.s3.amazonaws.com/index.html?prefix=jenkins/filebeat/ https://beats-nightlies.s3.amazonaws.com/index.html?prefix=jenkins/filebeat/]
にある純正スタティックリンク版がさっくり動いた。
filebeat-god はコンパイルした
<syntaxhighlight lang="bash" enclose="div">
git clone https://github.com/tsg/go-daemon.git
cd go-daemon
make
mv god filebeat-god
</syntaxhighlight>
config ファイル等は deb から流用
<syntaxhighlight lang="bash" enclose="div">
curl -L -O https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-5.5.1-amd64.deb
dpkg-deb -x filebeat-5.5.1-amd64.deb ./
</syntaxhighlight>
== RLIMIT_MEMLOCK ==
systemd 配下の場合は /usr/lib/systemd/system/elasticsearch.service
<syntaxhighlight lang="text" enclose="div">
[service]
LimitMEMLOCK=infinity
</syntaxhighlight>
こっちで対処するのが良いそうだ。
<syntaxhighlight lang="bash" enclose="div">
systemctl edit elasticsearch
</syntaxhighlight>
このコマンドで、
/etc/systemd/system/elasticsearch.service.d/override.conf
ここに、
<syntaxhighlight lang="text" enclose="div">
[service]
LimitMEMLOCK=infinity
</syntaxhighlight>
== sigle node / standalone ==
<syntaxhighlight lang="text" enclose="div">
discovery.type: single-node
</syntaxhighlight>
== Elastic Stack 6.0.0 upgrade memo ==
"type" がつかえない
https://www.elastic.co/guide/en/elasticsearch/reference/master/removal-of-types.html
statsd が標準プラグインから消えた。
./bin/logstash-plugin install logstash-output-statsd
kibana の '.kibana' のフォーマット変換が必要
https://www.elastic.co/guide/en/kibana/6.0/migrating-6.0-index.html
"type" が使えなくなったので "log_type" というカスタムフィールドにかえた。その変更をコツコツした。
変換後いろいろ確認して、無駄なものを削除した
curl -XGET 'http://127.0.0.1:9200/.kibana/_search/?size=1000&pretty'
curl -XDELETE 'http://127.0.0.1:9200/.kibana/doc/#{_id}
python beaver も 6.0 には対応できてない。
とりあえず type を送らないようにした。
<syntaxhighlight lang="diff" enclose="div">
--- ./beaver/transports/base_transport.py.orig 2017-11-30 10:57:01.546311555 +0900
+++ ./beaver/transports/base_transport.py 2017-11-24 11:40:34.962587490 +0900
@@ -36,21 +36,19 @@
        self._logstash_version = beaver_config.get('logstash_version')
        if self._logstash_version == 0:
            self._fields = {
-                'type': '@type',
                'tags': '@tags',
                'message': '@message',
                'file': '@source_path',
                'host': '@source_host',
-                'raw_json_fields': ['@message', '@source', '@source_host', '@source_path', '@tags', '@timestamp', '@type'],
+                'raw_json_fields': ['@message', '@source', '@source_host', '@source_path', '@tags', '@timestamp'],
            }
        elif self._logstash_version == 1:
            self._fields = {
-                'type': 'type',
                'tags': 'tags',
                'message': 'message',
                'file': 'file',
                'host': 'host',
-                'raw_json_fields': ['message', 'host', 'file', 'tags', '@timestamp', 'type'],
+                'raw_json_fields': ['message', 'host', 'file', 'tags', '@timestamp'],
            }
        def raw_formatter(data):
@@ -122,7 +120,6 @@
            formatter = self._default_formatter
        data = {
-            self._fields.get('type'): kwargs.get('type'),
            self._fields.get('tags'): kwargs.get('tags'),
            '@timestamp': timestamp,
            self._fields.get('host'): self._current_host,
</syntaxhighlight>
== Elastic Stack 5.0.0 upgrade memo ==
アップグレードは filebeat, logstash, elasticsearch, kibana の順番で行う。
Java8 が必要。(以下 Ubuntu の場合)
<syntaxhighlight lang="bash" enclose="div">
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
</syntaxhighlight>
=== repository setting ===
[https://www.elastic.co/guide/en/elasticsearch/reference/5.0/deb.html Install Elasticsearch with Debian Package]
<syntaxhighlight lang="bash" enclose="div">
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
</syntaxhighlight>
:順番に upgrade するので、apt-get upgrade はしない。
=== filebeat upgrade ===
[https://www.elastic.co/guide/en/beats/libbeat/5.0/upgrading.html Upgrading]
[https://www.elastic.co/guide/en/beats/libbeat/5.0/upgrading-1-to-5.html Upgrading from 1.x to 5.x]
*filebeat を停止する。
*古い設定ファイルを自動更新するスクリプトを起動する。
<syntaxhighlight lang="bash" enclose="div">
sudo apt-get install filebeat
cd etc/logstash
sudo /usr/share/filebeat/scripts/migrate_beat_config_1_x_to_5_0.py filebeat.yml
</syntaxhighlight>
*私は filebeat.yml を /etc/logstash に置いているので、/etc/default/filebeat を変更する。
<syntaxhighlight lang="text" enclose="div">
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"
</syntaxhighlight>
*filebeat を起動する。
<syntaxhighlight lang="text" enclose="div">
ERR State for /var/log/hoge.log should have been dropped, but couldn't as state is not finished.
</syntaxhighlight>
:更新後 filebeat を起動するが、なぜかエラーになる。一旦停止し、再起動すると正常に稼動する。おそらく registry file の変更処理が問題。
=== logstash upgrade ===
[https://www.elastic.co/guide/en/logstash/5.0/upgrading-logstash.html Upgrading Logstash]
*logstash を停止する。
<syntaxhighlight lang="bash" enclose="div">
sudo apt-get install logstash
</syntaxhighlight>
*起動スクリプトの args に追加
<syntaxhighlight lang="text" enclose="div">
--path.settings /etc/logstash
</syntaxhighlight>
複数個 logstash を起動する場合は、logfile の名前が衝突する。 (logstash-plain.log)
: /etc/logstash/log4j2.properties でなんとかするか、もしくは log directory を変える。
::Monitor API 用のポートも明示的に指定しているほうがよい。 --http.port 9600
*ruby filter の記述を変更する。
[https://www.elastic.co/guide/en/logstash/5.0/breaking-changes.html#_ruby_filter_and_custom_plugin_developers Ruby Filter and Custom Plugin Developers]
旧:
<syntaxhighlight lang="javascript" enclose="div">
filter {
  ruby {
    codec => "event['name'] = 'Logstash'"
  }
  ruby {
    codec => "event['product']['version'] = event['major'] + '.' + event['minor']"
  }
}
</syntaxhighlight>
新:
<syntaxhighlight lang="javascript" enclose="div">
filter {
  ruby {
    codec => "event.set('name', 'Logstash')"
  }
  ruby {
    codec => "event.set('[product][version]', event.get('major') + '.' + event.get('minor'))"
  }
}
</syntaxhighlight>
:カスタムプラグインをつかっている場合も同様の変更が必要。
*Java系のオプションは /etc/logstash/jvm.options に記述する。
*logstashを起動する。
=== elasticsearch upgrade ===
[https://www.elastic.co/guide/en/elasticsearch/reference/5.0/setup-upgrade.html Upgrading Elasticsearch]
:'''慎重に。バックアップをとること。一度更新されるとロールバックできないので、完全バックアップをとる事。'''
*更新前の elasticsearch で [https://github.com/elastic/elasticsearch-migration/ Elasticsearch Migration Plugin] を実行する。
:指示にしたがい作業する。
::kibana の index が reindex されたら kibana4 からは名前が変わってしまうので、kibana4 で確認作業をする場合は kibana の設定を変える。
:::elasticsearch 5.x と kibana5 になると alias が機能するので、元の名前に戻して大丈夫。
::logstash の elasticsearch-template を 5.x 用に変える。(かなり変わっているので、よく調査すること)
:::.raw が .keyword になる。.raw を使いたければ template を変更すること。
::logstash を停止して、elasticsearch 更新後起動する。
*elasticsearch を停止する。
<syntaxhighlight lang="bash" enclose="div">
sudo apt-get install elasticsearch
</syntaxhighlight>
*Java系のオプションは /etc/elasticsearch/jvm.options に記述する。
*elasticsearch を起動する。
*elasticsearch_deprecation.log にこんなのがでたら
<syntaxhighlight lang="text" enclose="div">
ES has detected the [path.data] folder using the cluster name as a folder [/xxx], Elasticsearch 6.0 will not allow the cluster name as a folder within the data path
</syntaxhighlight>
[https://www.elastic.co/guide/en/elasticsearch/reference/master/breaking_60_cluster_changes.html#_cluster_name_no_longer_allowed_in_path_data Breaking changes in 6.0 » Cluster changes]
:DATA_DIR をクラスタネーム付きのパスまでにしてあげる(ex: /foo -> /foo/cluster_name_bar)
::もちろん /foo/cluster_name_bar 直下には nodes ディレクトリのみがある。
*ingest node
[https://www.elastic.co/blog/new-way-to-ingest-part-1 A New Way To Ingest - Part 1]
[https://www.elastic.co/blog/new-way-to-ingest-part-2 A New Way To Ingest - Part 2]
:Logstash の filter 機能を Elasticsearch に取り込んだのか...私の場合は不要なので '''node.ingest: false'''
=== kibana upgrade ===
[https://www.elastic.co/guide/en/kibana/5.0/upgrade.html Upgrading Kibana]
*kibana を停止する。
*kibana の設定データをコピーする。
<syntaxhighlight lang="bash" enclose="div">
sudo mkdir /etc/kibana
sudo cp /opt/kibana/conf/kibana.yml /etc/kibana/
</syntaxhighlight>
*kibana をインストールする。
<syntaxhighlight lang="bash" enclose="div">
sudo apt-get install kibana
</syntaxhighlight>
*kibana を起動する。
.raw が .keyword になっているので注意。Object の変更が必要。
:これは logstash の elasticsearch template の変更による。
::.raw を使い続けたければ、template を変更する事。(私は もともと .raw を使わない template にしていたが、今回は .keyword を使って見る事にした)
elasticsearch の elasticsearch_deprecation.log にメッセージ出まくり。
<syntaxhighlight lang="text" enclose="div">
Deprecated field [type] used, replaced by [match_phrase and match_phrase_prefix query]
</syntaxhighlight>
:github issue や discuss.elastic.co を漁り中だが見つからない。
::おそらく query を
<syntaxhighlight lang="javascript" enclose="div">
{
  "query": {
    "match": {
      "foo": {
        "query": "bar",
        "type": "phrase"
      }
    }
  }
}
</syntaxhighlight>
から
<syntaxhighlight lang="javascript" enclose="div">
{
  "query": {
    "match_phrase": {
      "foo": "bar"
    }
  }
}
</syntaxhighlight>
でOK
*/var/log/kibana/kibana.stderr を確認する。
もし下記のエラーがあれば、
<syntaxhighlight lang="text" enclose="div">
FATAL { Error: EACCES: permission denied, open '/usr/share/kibana/optimize/bundles/graph.entry.js'
</syntaxhighlight>
:これは X-Pack のインストールした場合の権限がうまく処理できてないのが理由。(X-Pack を消しても残る)
<syntaxhighlight lang="bash" enclose="div">
cd /usr/share/kibana/optimize/bundles
sudo chmod g+w *
</syntaxhighlight>
= kibana =
<!--
kibana 4.3.0 で apache-proxy 環境で動作した。
:timelion を評価してるので ssh tunneling をつかう運用に変えつつある...
<syntaxhighlight lang="bash" enclose="div">
ssh -n -N -o BatchMode=yes -L 127.0.0.1:80:127.0.0.1:5601 USER@KIBANA_HOST
</syntaxhighlight>
== kibana 4 ==
:apache reverse proxy で network 制限と basic 認証をかける(できたら mod_ssl も)
<syntaxhighlight lang="apache" enclose="div">
    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>
</syntaxhighlight>
== kibana 3 から kibana 4 ==
=== map ===
:map 用の geoip の field に geo_point 属性を付けてやる必要がある。[https://github.com/logstash-plugins/logstash-output-elasticsearch/blob/master/lib/logstash/outputs/elasticsearch/elasticsearch-template.json elasticsearch-template.json] を元に必要な設定を追加する。
[http://www.elastic.co/guide/en/logstash/current/plugins-filters-geoip.html#plugins-filters-geoip-target you need to alter the template provided with the Elasticsearch output and configure the output to use the new template.]
:logstash ES output に template 行を追加する。
<syntaxhighlight lang="javascript" enclose="div">
output {
  elasticsearch {
    hosts => ["127.0.0.1"]
    template => "/etc/logstash/elasticsearch-template.json"
    template_overwrite => true
  }
}
</syntaxhighlight>
:もちろん各フィールドについても適切なマッピングをするべき。ES 2.x では(以前より早くなった) '''doc_values''' をうまく使うことも考慮する。
:私は、type: string はすべて '''not_analyzed''' にして、本当に必要なフィールドのみ '''analyzed''' にするようにした。
logstash-output-elasticsearch 2.1.2 で配布された elasticsearch-template.json は ".raw" が生成されなかった。2.1.3 以降ですぐに元に戻したが、やはり '''analyzed''' '''not_analyzed''' とか field type の mapping は自分でコントロールする癖をつけたほうが良いと思う。[https://github.com/nxhack/logstash/blob/master/elasticsearch-template.json 自分は ".raw" を付けないように変更した。]
:".raw" がないから kibana でエラー出まくりだったが...
-->
ES 5.0.0 から、かなり mapping が変わったので、一旦様子見にはいる。 ES 2.x の .raw は .keyword
=== filter edit ===
"Discover" filter の編集ボタンを押して query 書く。
<syntaxhighlight lang="javascript" enclose="div">
{
  "query": {
    "wildcard": {
      "foo": "bar*"
    }
  }
}
</syntaxhighlight>
===dashboard Timepicker を変更===
:relative でお好きに。
===Field が未定義という filter===
:"Discover" で Field をクリックして "Quick Count" ででてくる数字をクリック。そして Invert すればよい。
::5.x から '*' マークをクリックで Invert でも可能
<!--
== kibana 4.5.2 ==
deb パッケージに不具合あり。
インストール前に kibana service を stop しないといけない。
<syntaxhighlight lang="text" enclose="div">
# dpkg -i kibana_4.5.2_amd64.deb
(Reading database ... 168492 files and directories currently installed.)
Preparing to replace kibana 4.5.1 (using kibana_4.5.2_amd64.deb) ...
Unpacking replacement kibana ...
userdel: user kibana is currently logged in
dpkg: warning: subprocess old post-removal script returned error exit status 8
dpkg - trying script from the new package instead ...
userdel: user kibana is currently logged in
dpkg: error processing kibana_4.5.2_amd64.deb (--install):
subprocess new post-removal script returned error exit status 8
userdel: user kibana is currently logged in
dpkg: error while cleaning up:
subprocess new post-removal script returned error exit status 8
Processing triggers for ureadahead ...
Errors were encountered while processing:
kibana_4.5.2_amd64.deb
</syntaxhighlight>
権限も怪しそうなので変えておいた。
<syntaxhighlight lang="bash" enclose="div">
chown -R kibana: /opt/kibana
</syntaxhighlight>
[https://github.com/elastic/kibana/issues/6729 https://github.com/elastic/kibana/issues/6729]
/var/log/kibana/kibana.stdout が肥大化していたので logrotate 設定した。
-->
=== IPv6 address の抽出 ===
単純な方法があった。
<syntaxhighlight lang="text" enclose="div">
client_ip: *\:*
</syntaxhighlight>
:これだとマッチしないのがあるっぽいな。要調査
<syntaxhighlight lang="text" enclose="div">
client_ip: ["::" TO "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"]
</syntaxhighlight>
:これでも抜けるな
::これかな? [https://github.com/elastic/elasticsearch/issues/29288 unable to CIDR match IPv4-mapped IPv6]
:::あちゃ。type ipになってなかった。もうすこしホゲる。
:::: type ip にしてみたが、うまくマッチする方法がみつからない。
どうやら type ip ではこれで良い。このアドレスはインターネットに広報してよいブロックのみ。これ以外は変えないといけない。
<syntaxhighlight lang="text" enclose="div">
client_ip: "2000::/3"
</syntaxhighlight>
ちなみに logstash だとこんなコードでマッチする。実運用では logstash 側のロジックで新しいフィールドつくった。
結局 type ip ならこれでよさそうだ。
<syntaxhighlight lang="text" enclose="div">
if [client_ip] =~ /:/ {
  # is IPv6, do something
  mutate {
    add_field => { "client_ipv6" => "%{client_ip}" }
  }
}
</syntaxhighlight>
== 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
[[File:kibana-5.x.png]]
:kibana4 の黒い画面で
[[File:kibana4-black.png]]
:Arduino YUN で計測した気象データを TimeLion で
::YUN の AR9331 で python supervisord 配下の beaver から SSH tunnel で logstash broker である redis に送信。
[[File:timelion.png]]
:kibana 4 で kibana 3 風に
[[File:Kibana4-apache.png]]
:kibana 4 で ssh の攻撃元マップ Heatmap カッコイイ
[[File:Kibana4-sshd-heatmap.png]]
:迷惑メール
[[File:Kibana4-amavis.png]]
<!--
== メモ ==
テスト用途で Kibana index の replica を作りたく無い場合 (Standalone な ES の health status を Green にしたい場合)
:./src/plugins/elasticsearch/lib/create_kibana_index.js:
<syntaxhighlight lang="javascript" enclose="div">
        number_of_replicas: 0
</syntaxhighlight>
kibana 4.4.0 で replica 設定は削除された。
[https://github.com/elastic/kibana/commit/f6c611ba85baa35aad4a6b61232edc26d1cb6deb Don't bother setting the number of index replicas when creating kiban… · elastic/kibana@f6c611b]
-->
= Elasticsearch =
== 構造 ==
curl -XGET 'http://127.0.0.1:9200/{INDEX}/{TYPE:mapping}/{ID:Document}'
curl -XGET 'http://127.0.0.1:9200/{INDEX}/{TYPE:mapping}/{ID:Document}/_source'
curl -XGET 'http://127.0.0.1:9200/{INDEX}/{TYPE:mapping}/_mapping'
curl -XGET 'http://127.0.0.1:9200/{INDEX}/{TYPE:mapping}/_mapping?pretty'
curl -XGET 'http://127.0.0.1:9200/_search?q=tags:_grokparsefailure'
curl -XGET 'http://127.0.0.1:9200/_cluster/health?pretty'
curl -XGET 'http://127.0.0.1:9200/_template?pretty'
curl -XGET 'http://127.0.0.1:9200/kibana-int/_search?q=*:*&pretty'
curl -XGET 'http://127.0.0.1:9200/kibana-int/_search?q=*:*&size=100&pretty'
curl -XGET '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 で定期的に削除する方法をとるかな...)
== メンテナンス ==
[https://github.com/elasticsearch/curator elasticsearch-curator]
<syntaxhighlight lang="bash" enclose="div">
###/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
</syntaxhighlight>
:curator4 で大幅に書式変わった。
Disk full で index がロックされた場合
<syntaxhighlight lang="bash" enclose="div">
curl -XPUT -H "Content-Type: application/json" http://localhost:9200/_all/_settings -d '{"index.blocks.read_only_allow_delete": null}'
</syntaxhighlight>
[https://github.com/lmenezes/elasticsearch-kopf kopf web admin interface for elasticsearch]
[http://mobz.github.io/elasticsearch-head/ elasticsearch-head]
[http://www.elastichq.org/ Elastic HQ]
:メモメモ (sysdig の パース実験中なので、type:sysdig をいろいろ削除したい
<syntaxhighlight lang="bash" enclose="div">
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'
</syntaxhighlight>
X-Pack 削除したら...
curl -XGET 'http://127.0.0.1:9200/_cluster/health?level=shards&pretty'
curl -XDELETE 'http://127.0.0.1:9200/.security'
curl -XDELETE 'http://127.0.0.1:9200/.triggered_watches'
curl -XDELETE 'http://127.0.0.1:9200/.watches'
curl -XDELETE 'http://127.0.0.1:9200/.monitoring-es-6-YYYY.MM.DD'
curl -XDELETE 'http://127.0.0.1:9200/.monitoring-alerts-6'
curl -XDELETE 'http://127.0.0.1:9200/.watcher-history-6-YYYY.MM.DD'
= 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 にしておく。
:日付またぎ問題を大胆に処理してみた。
<syntaxhighlight lang="bash" enclose="div">
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]*)
</syntaxhighlight>
ES 5.x で [https://www.elastic.co/guide/en/elasticsearch/reference/5.0/query-dsl-filtered-query.html filterd query が廃止になった]ので対応した。
[https://github.com/nxhack/munin-plugins https://github.com/nxhack/munin-plugins]
Logstash monitor API を使った plugin も作った。
[https://github.com/nxhack/munin-plugin-logstash https://github.com/nxhack/munin-plugin-logstash]
Munin plugin for elasticsearch も Pull Request がマージされた。


Kibana で細かなアクセス権限を与える場合は、フロントに apache + mod_proxy で実装する。
[https://github.com/y-ken/munin-plugin-elasticsearch https://github.com/y-ken/munin-plugin-elasticsearch]
[https://github.com/y-ken/munin-plugin-elasticsearch/commit/389725c05a8c43815e38bc30a81216891cc43720 Merge pull request #14 from nxhack/patch_for_ES_5.0.0 ]

Latest revision as of 11:57, 16 January 2024

Elastic stack / ELK (Elasticsearch + Logstash + Kibana)

諸般の事情により更新休止します

久しぶりの追記

久しぶりに logstash.conf を修正したら、割と重要な仕様変更がたくさんあり、過去の記述は現在の仕様に合ってないです。ちなみに ruby code を追記したのですが、event.get event.set とかになっている。

  ruby {
      code => "event.set('foo',event.get('foo')+ 5.1)"
  }

こんな感じ。

その他、認証系強化による仕様の混乱はとりあえずなんとかするしかないw

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

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

最近の Elastic Stack は logstash いらずで簡易にという方向を狙ってきている。それはそれで嬉しいが、いろいろ細かく触りたい場合には、まだまだ logstash をホゲらないと逝けない。

完全に通常の運用につかっているので、アグレッシブな変更はできなくなってるので突っ込んだ記事がかけない^^;;;


7.6.0 は kibana の index の変換するのだが、elasticseach のサーキットブレーカーが作動して完了しない。

一時的に elasticsearch の heap 増やした。(最終的には、今回の件がギリギリ回避できるメモリー量に増やした)

7.6.0 から X-Pack の概念が変わった(なくなった?)

logstash.yml から xpack の設定をコメントアウト

timelion の位置付けが変わった。

kibana.ymlに

timelion.ui.enabled: true

で元に戻る。設定を確認して、新しいビジュアライズに移行する。


7.4.1 の logstash がダメっぽい。ヘビー io-wait

以前よりメモリー食いになってるようで、ES も含めて頑張って使用メモリー削減してかろうじて稼働中
dns filter がぁ failed_cache_size ちゃんと設定しないとまずい。

ようやく 7.x にあげた

あら...意外と簡単に入った 7.4.0...でもないぞ。

よく見たら index 名が変わって Index Lifecycle Management がよしなにしてしまうようで、昔に戻すには elasticsearch output pulgin で

 ilm_enabled => false

kibana の index pattern を削除したあとトラブル。新しい index pattern 作っているのに index pattern が無いので作れといわれる

解決策は、新しい index pattern を作るときに、advanced options を表示して、Custom index pattern ID に index pattern と同じ文字をいれる。たとえば index pattern が "logstash-*" なら Custom index pattern ID も "logstash-*" とする。

私は '*' という文字が嫌なので(あとで問題起きそう)、全部 id を書き換えた。

filebeat.yml で filebeat.registry_file 行削除すること
logstash の elasticsearch-template を変更
    "_default_" : {
     ****
    }

を削除

python beaver から送られる 'host' を remove
    mutate {
      rename => { "host" => "my_host" }
    }
    mutate {
      add_field => { "[host][name]" => "%{my_host}" }
    }
beats が送っていた "host" は host.name に 
[host][name]
agent.* が増えた

7.0.0 出た! テストは気力があるときwにします。。。

6.6.1 で geoip.postal_code の型がコンフリクト

"postal_code" : { "type" : "keyword" }

6.5.0 で kibana の index が変更されて .kibana_1 .kibana_2 というのができた。これですこしハマった。

6.2.0 で /etc/elasticsearch/jvm.options

-Djava.io.tmpdir=${ES_TMPDIR}
ES_TMPDIR の定義がないのでエラーになる。

filebeat 6.3.0 は問題ありそう。6.2.4 のままで様子を見る。

"error"=>{"type"=>"mapper_parsing_exception", "reason"=>"failed to parse [host]"
Metricbeat `host` namespace causes mapping conflict when used with Logstash
Logstash errors after upgrading to filebeat-6.3.0


Breaking changes in 6.3
ここに着地
  "mappings" : {
      "properties" : {
        "host"  : {
          "dynamic": true,
          "properties" : {
            "name": { "type": "keyword" },
            "id" : { "type" : "keyword" },
            "architecture" : { "type" : "keyword" },
            "os" : {
              "dynamic" : true,
              "properties" : {
                "platform": { "type": "keyword" },
                "version": { "type": "keyword" },
                "family": { "type": "keyword" }
            }
            "ip" : { "type" : "ip" },
            "mac" : { "type" : "keyword" }
          }
        }
      }
    }
  }
こんな感じの template でいいのかねぇ
Elastic Common Schema こんなこと計画してるらしい

それか無視するか

  # For Beat and LSF compatibility
  if [beat][name] {
    # Remove host metadata
    mutate {
      remove_field => [ "[host]" ]
    }
    mutate {
      add_field => {
        "host" => "%{[beat][name]}"
      }
    }
beat.hostname ではなく beat.name つかえと...

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に送る)-------------------↗︎
Filebeat(redisに送る)-----------------↗︎
最近は Kafka を broker にするのが良さげか?
私は各端末には Java 環境は入れたくないので Filebeat を使ってます。
(私は IoT ごっこと称して遊んでいるのですが) Arduino YUN の 32U4 部で計測したデータを AR9331 部 OpenWrt 上の python beaver を用いて redis に直接送ってます。

Filebeat:

端末(filebeat) ----> 解析サーバ(logstash-shipper)
[端末(filebeat) ----> 解析・蓄積(Elasticsearch Ingest Node)]

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 例 (6.0 仮)

6.0 は type が使えないので log_type という名前のカスタムフィールドに変更する。
logstash 使うので filebeat modules は使わない。
modules 勉強しないといけない。
もともと logstash から入ったので modules は私には不要かも...
######################## Filebeat Configuration ############################

#=========================== Filebeat prospectors =============================

filebeat.inputs:
#filebeat.prospectors:

- type: log
  paths:
    - /var/log/syslog
    - /var/log/mail.log
    - /var/log/auth.log
  fields:
    log_type: syslog
  fields_under_root: true

- type: log
  paths:
    /var/log/apache2/access.log
  fields:
    log_type: apache
  fields_under_root: true

- type: log
  paths:
    /var/log/apache2/other_vhosts_access.log
  fields:
    log_type: apache-other-vhost
  fields_under_root: true

- type: log
  paths:
    /var/log/apache2/error.log
  fields:
    log_type: apache-error
  fields_under_root: true

- type: log
  paths:
    /var/log/varnish/varnishncsa.log
  fields:
    log_type: varnish
  fields_under_root: true

- type: log
  paths:
    /var/log/dpkg.log
  fields:
    log_type: dpkg
  fields_under_root: true

- type: log
  paths:
    /var/log/fail2ban.log
  fields:
    log_type: fail2ban
  fields_under_root: true

#========================= Filebeat global options ============================

filebeat.registry_file: /var/lib/filebeat/registry

#================================ Outputs ======================================

#----------------------------- Logstash output ---------------------------------
output.logstash:
  # The Logstash hosts
  hosts: ["localhost:5044"]

  # Optional SSL. By default is off.
  # List of root certificates for HTTPS server verifications
  ssl.certificate_authorities: ["/etc/logstash/logstash-forwarder.crt"]

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

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

  # Configure SSL verification mode. If `none` is configured, all server hosts
  # and certificates will be accepted. In this mode, SSL based connections are
  # susceptible to man-in-the-middle attacks. Use only for testing. Default is
  # `full`.
  #ssl.verification_mode: full
  ssl.verification_mode: none

#================================ Logging ======================================
# There are three options for the log output: syslog, file, stderr.
# Under Windows systems, the log files are per default sent to the file output,
# under all other system per default to syslog.

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

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

# Send all logging output to syslog. The default is false.
#logging.to_syslog: true
logging.to_syslog: false

# If enabled, filebeat periodically logs its internal metrics that have changed
# in the last period. For each metric that changed, the delta from the value at
# the beginning of the period is logged. Also, the total values for
# all non-zero internal metrics are logged on shutdown. The default is true.
#logging.metrics.enabled: true

# The period after which to log the internal metrics. The default is 30s.
#logging.metrics.period: 30s

# Logging to rotating files files. Set logging.to_files to false to disable logging to
# files.
logging.to_files: true
logging.files:
  # Configure the path where the logs are written. The default is the logs directory
  # under the home path (the binary location).
  #path: /var/log/filebeat
  path: /var/log/filebeat

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

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

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

  # The permissions mask to apply when rotating log files. The default value is 0600.
  # Must be a valid Unix-style file permissions mask expressed in octal notation.
  #permissions: 0600

# Set to true to log messages in json format.
#logging.json: false

メンテナンス

/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=3.1.1 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
公式 pattern の 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/geoip2/geolite2/
http://geolite.maxmind.com/download/geoip/database/GeoLite2-City.mmdb.gz
http://geolite.maxmind.com/download/geoip/database/GeoLite2-Country.mmdb.gz
http://geolite.maxmind.com/download/geoip/database/GeoLite2-ASN.tar.gz
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

geoip 更新処理

wget http://geolite.maxmind.com/download/geoip/database/GeoLite2-City.mmdb.gz
wget http://geolite.maxmind.com/download/geoip/database/GeoLite2-Country.mmdb.gz
wget http://geolite.maxmind.com/download/geoip/database/GeoLite2-ASN.tar.gz
rm *.old
mv GeoLite2-City.mmdb GeoLite2-City.mmdb.old
mv GeoLite2-Country.mmdb GeoLite2-Country.mmdb.old
mv GeoLite2-ASN.mmdb GeoLite2-ASN.mmdb.old
gunzip GeoLite2-City.mmdb.gz
gunzip GeoLite2-Country.mmdb.gz
tar xfz GeoLite2-ASN.tar.gz --strip=1 --wildcards */GeoLite2-ASN.mmdb
rm GeoLite2-ASN.tar.gz

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

Logstash 5.0.0 GA につき、Monitor API を使った munin plugin 作ってみた。

https://github.com/nxhack/munin-plugin-logstash

Elastic Stack 純正のモニタリングパッケージ X-Pack はこれから試す。

X-Pack

Basic ライセンスというのが Free で、ライセンスを1年ごとに更新していけば、ずっと無料でつかえそうだ。

6.3.0 から Basic ライセンスは有効期限が無制限になった。また面倒だったアップテート時の x-pack のインストース作業も不要になった。

自分のテスト環境はシングルノードなので status が YELLOW にならないように、

/usr/share/elasticsearch/plugins/x-pack/x-pack-core/x-pack-core-6.2.4.jar
テンプレート json の index.number_of_replicas を変更する。
curl -XDELETE 'http://127.0.0.1:9200/_template/.monitoring-logstash'
curl -XDELETE 'http://127.0.0.1:9200/_template/.monitoring-alerts'
curl -XDELETE 'http://127.0.0.1:9200/_template/.monitoring-es-2'
curl -XDELETE 'http://127.0.0.1:9200/_template/.monitoring-es'
curl -XDELETE 'http://127.0.0.1:9200/_template/.monitoring-data-2'
curl -XDELETE 'http://127.0.0.1:9200/_template/.monitoring-kibana-2'
curl -XDELETE 'http://127.0.0.1:9200/_template/.monitoring-kibana'

作ってしまった index の index.number_of_replicas を変更する。

curl -XPUT 'http://localhost:9200/.monitoring-es-6-2017.12.05/_settings' -H 'Content-Type: application/json' -d'
{
    "index" : {
        "number_of_replicas" : "0"
    }
}
'

curl -XPUT 'http://localhost:9200/.monitoring-logstash-6-2017.12.05/_settings' -H 'Content-Type: application/json' -d'
{
    "index" : {
        "number_of_replicas" : "0"
    }
}
'

curl -XPUT 'http://localhost:9200/.monitoring-kibana-6-2017.12.05/_settings' -H 'Content-Type: application/json' -d'
{
    "index" : {
        "number_of_replicas" : "0"
    }
}
'

Elastic Stack がアップデートされたら、いちいち明示的に X-Pack をアップデートしなければいけないのは萎える。

6.3.0 から標準パッケージにはいったっぽい。
systemctl stop logstash
systemctl stop kibana
systemctl stop elasticsearch
cd /usr/share/logstash
./bin/logstash-plugin install logstash-output-statsd
./bin/logstash-plugin install logstash-filter-throttle
./bin/logstash-plugin install logstash-filter-sleep
systemctl start elasticsearch
systemctl start kibana
systemctl start logstash


また、elasticsearch を(再)起動する時点で、kibana や logstash が稼働している場合に、monitor を突きにくるので、認証エラーが多発する。 これは無視してよいが気持ち悪い。

Authentication of [kibana] was terminated by realm [reserved] - failed to authenticate user [kibana]
Authentication of [logstash_system] was terminated by realm [reserved] - failed to authenticate user [logstash_system]

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


geoip support for GeoIPLite2-ASN database

4.2.1 でうごくか...

/usr/share/logstash/bin/logstash-plugin update logstash-filter-geoip
Updating logstash-filter-geoip
Updated logstash-filter-geoip 4.1.1 to 4.2.1
	geoip {
          database => "/etc/logstash/geoip/GeoLite2-ASN.mmdb"
          source => "postfix_client_ip"
          target => "postfix_bgp"
        }

いけた!

    "postfix_bgp": {
      "as_org": "Towerstream I, Inc.",
      "ip": "64.17.249.242",
      "asn": 33224
    },

Raspberry Pi

https://beats-nightlies.s3.amazonaws.com/index.html?prefix=jenkins/filebeat/

にある純正スタティックリンク版がさっくり動いた。

filebeat-god はコンパイルした

git clone https://github.com/tsg/go-daemon.git
cd go-daemon
make
mv god filebeat-god

config ファイル等は deb から流用

curl -L -O https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-5.5.1-amd64.deb
dpkg-deb -x filebeat-5.5.1-amd64.deb ./

RLIMIT_MEMLOCK

systemd 配下の場合は /usr/lib/systemd/system/elasticsearch.service

[service]
LimitMEMLOCK=infinity

こっちで対処するのが良いそうだ。

systemctl edit elasticsearch

このコマンドで、

/etc/systemd/system/elasticsearch.service.d/override.conf

ここに、

[service]
LimitMEMLOCK=infinity

sigle node / standalone

discovery.type: single-node

Elastic Stack 6.0.0 upgrade memo

"type" がつかえない

https://www.elastic.co/guide/en/elasticsearch/reference/master/removal-of-types.html

statsd が標準プラグインから消えた。

./bin/logstash-plugin install logstash-output-statsd

kibana の '.kibana' のフォーマット変換が必要

https://www.elastic.co/guide/en/kibana/6.0/migrating-6.0-index.html


"type" が使えなくなったので "log_type" というカスタムフィールドにかえた。その変更をコツコツした。

変換後いろいろ確認して、無駄なものを削除した

curl -XGET 'http://127.0.0.1:9200/.kibana/_search/?size=1000&pretty'
curl -XDELETE 'http://127.0.0.1:9200/.kibana/doc/#{_id}


python beaver も 6.0 には対応できてない。 とりあえず type を送らないようにした。

--- ./beaver/transports/base_transport.py.orig	2017-11-30 10:57:01.546311555 +0900
+++ ./beaver/transports/base_transport.py	2017-11-24 11:40:34.962587490 +0900
@@ -36,21 +36,19 @@
         self._logstash_version = beaver_config.get('logstash_version')
         if self._logstash_version == 0:
             self._fields = {
-                'type': '@type',
                 'tags': '@tags',
                 'message': '@message',
                 'file': '@source_path',
                 'host': '@source_host',
-                'raw_json_fields': ['@message', '@source', '@source_host', '@source_path', '@tags', '@timestamp', '@type'],
+                'raw_json_fields': ['@message', '@source', '@source_host', '@source_path', '@tags', '@timestamp'],
             }
         elif self._logstash_version == 1:
             self._fields = {
-                'type': 'type',
                 'tags': 'tags',
                 'message': 'message',
                 'file': 'file',
                 'host': 'host',
-                'raw_json_fields': ['message', 'host', 'file', 'tags', '@timestamp', 'type'],
+                'raw_json_fields': ['message', 'host', 'file', 'tags', '@timestamp'],
             }
 
         def raw_formatter(data):
@@ -122,7 +120,6 @@
             formatter = self._default_formatter
 
         data = {
-            self._fields.get('type'): kwargs.get('type'),
             self._fields.get('tags'): kwargs.get('tags'),
             '@timestamp': timestamp,
             self._fields.get('host'): self._current_host,

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 を変える。
Monitor API 用のポートも明示的に指定しているほうがよい。 --http.port 9600
  • 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 を起動する。
  • elasticsearch_deprecation.log にこんなのがでたら
ES has detected the [path.data] folder using the cluster name as a folder [/xxx], Elasticsearch 6.0 will not allow the cluster name as a folder within the data path
Breaking changes in 6.0 » Cluster changes
DATA_DIR をクラスタネーム付きのパスまでにしてあげる(ex: /foo -> /foo/cluster_name_bar)
もちろん /foo/cluster_name_bar 直下には nodes ディレクトリのみがある。
  • ingest node
A New Way To Ingest - Part 1
A New Way To Ingest - Part 2
Logstash の filter 機能を Elasticsearch に取り込んだのか...私の場合は不要なので node.ingest: false

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

  • /var/log/kibana/kibana.stderr を確認する。

もし下記のエラーがあれば、

FATAL { Error: EACCES: permission denied, open '/usr/share/kibana/optimize/bundles/graph.entry.js'
これは X-Pack のインストールした場合の権限がうまく処理できてないのが理由。(X-Pack を消しても残る)
cd /usr/share/kibana/optimize/bundles
sudo chmod g+w *

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 でも可能

IPv6 address の抽出

単純な方法があった。

client_ip: *\:*
これだとマッチしないのがあるっぽいな。要調査
client_ip: ["::" TO "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"]
これでも抜けるな
これかな? unable to CIDR match IPv4-mapped IPv6
あちゃ。type ipになってなかった。もうすこしホゲる。
type ip にしてみたが、うまくマッチする方法がみつからない。

どうやら type ip ではこれで良い。このアドレスはインターネットに広報してよいブロックのみ。これ以外は変えないといけない。

client_ip: "2000::/3"

ちなみに logstash だとこんなコードでマッチする。実運用では logstash 側のロジックで新しいフィールドつくった。

結局 type ip ならこれでよさそうだ。

if [client_ip] =~ /:/ {
  # is IPv6, do something
  mutate {
    add_field => { "client_ipv6" => "%{client_ip}" }
  }
}

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

Kibana-5.x.png

kibana4 の黒い画面で

Kibana4-black.png

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

Timelion.png

kibana 4 で kibana 3 風に

Kibana4-apache.png

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

Kibana4-sshd-heatmap.png

迷惑メール

Kibana4-amavis.png


Elasticsearch

構造

curl -XGET 'http://127.0.0.1:9200/{INDEX}/{TYPE:mapping}/{ID:Document}'
curl -XGET 'http://127.0.0.1:9200/{INDEX}/{TYPE:mapping}/{ID:Document}/_source'
curl -XGET 'http://127.0.0.1:9200/{INDEX}/{TYPE:mapping}/_mapping'
curl -XGET 'http://127.0.0.1:9200/{INDEX}/{TYPE:mapping}/_mapping?pretty'
curl -XGET 'http://127.0.0.1:9200/_search?q=tags:_grokparsefailure'
curl -XGET 'http://127.0.0.1:9200/_cluster/health?pretty'
curl -XGET 'http://127.0.0.1:9200/_template?pretty'
curl -XGET 'http://127.0.0.1:9200/kibana-int/_search?q=*:*&pretty'
curl -XGET 'http://127.0.0.1:9200/kibana-int/_search?q=*:*&size=100&pretty'
curl -XGET '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 で大幅に書式変わった。

Disk full で index がロックされた場合

curl -XPUT -H "Content-Type: application/json" http://localhost:9200/_all/_settings -d '{"index.blocks.read_only_allow_delete": null}'
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'

X-Pack 削除したら...

curl -XGET 'http://127.0.0.1:9200/_cluster/health?level=shards&pretty'
curl -XDELETE 'http://127.0.0.1:9200/.security'
curl -XDELETE 'http://127.0.0.1:9200/.triggered_watches'
curl -XDELETE 'http://127.0.0.1:9200/.watches'
curl -XDELETE 'http://127.0.0.1:9200/.monitoring-es-6-YYYY.MM.DD'
curl -XDELETE 'http://127.0.0.1:9200/.monitoring-alerts-6'
curl -XDELETE 'http://127.0.0.1:9200/.watcher-history-6-YYYY.MM.DD'

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]*)

ES 5.x で filterd query が廃止になったので対応した。

https://github.com/nxhack/munin-plugins

Logstash monitor API を使った plugin も作った。

https://github.com/nxhack/munin-plugin-logstash

Munin plugin for elasticsearch も Pull Request がマージされた。

https://github.com/y-ken/munin-plugin-elasticsearch
Merge pull request #14 from nxhack/patch_for_ES_5.0.0