ちょっとした内容をアクセスログから見たいなと思った時に
試した事があったので、それについて書こうと思います
検証したきっかけ
リリース直後や機能のアップデート後、はたまたアクセスが急増した時などに
アクセスログを見ることがよくあると思います。
ただ、上記要件以外でもカジュアルに
あれ、この地域からのアクセスが意外に多い等、
コーヒー飲みながら、サービス展開に思いを馳せたりしたいな、と思ったのがきっかけです。
今回はKibanaのvisualizeを使ってログを見ていきたいと思います。
やる事
- Kibanaでどのあたりの地域からアクセスがあるのかを見たい
- Elasticsearchを使う
- ログファイルだけあれば解析できるように、embulkでElasticsearchで投入する
- どこでも気軽に試せるようにdockerコンテナで処理する
- 今回のエントリー用にログデータはダミーデータを利用する
- Elasticsearchに入れるデータはIPと位置情報のみ
今回の構成
- access_kibana
- docker
- elasticsearch
- config
schema.json
Dockerfile
- embulk
- config
embulk_config.yml
Dockerfile
- kibana
Dockerfile
docker-compose.yml
- log
Gemfile
sample_log.rb
dockerコンテナで環境を用意する
Dockerfileの準備
- elasticsearch
FROM elasticsearch:5.6.5
# x-pack
RUN elasticsearch-plugin install --batch x-pack
# kuromoji
RUN elasticsearch-plugin install analysis-kuromoji
- kibana
FROM kibana:5.6.5
# x-pack
RUN kibana-plugin install x-pack
- embulk
こちらはDockerhubに上がっているものを利用します。
embulk Dockerfile
docker-compose
docker-composeを準備してまとめて管理します
version: '2'
services:
elasticsearch:
build: elasticsearch
volumes:
- es-data:/usr/share/elasticsearch/data
- ./elasticsearch/config:/usr/share/elasticsearch/config
ports:
- 9200:9200
expose:
- 9300
ulimits:
nofile:
soft: 65536
hard: 65536
network_mode: "bridge"
kibana:
build: kibana
links:
- elasticsearch:elasticsearch
ports:
- 5601:5601
network_mode: "bridge"
embulk:
build: embulk
links:
- elasticsearch:elasticsearch
volumes:
- ./embulk/config:/opt/config
- ../log:/opt/log
network_mode: "bridge"
volumes:
es-data:
driver: local
networks:
default:
external:
name: bridge
dockerコンテナを起動
cd docker
docker-compose up -d
アクセスログを作る apache-loggen
今回は apache-loggen を使ってダミーのアクセスログを作ります
gem install apache-loggen --no-ri --no-rdoc -V
apache-loggen --rate=10 --limit=10 > opt/log
ログに位置情報を追加する
IPから位置情報を推測するようにします
- gem
# Gemfileに追加
gem 'maxminddb'
- gem install
bundle install --path vdendor/bundle
-
位置情報の取得
位置情報にはMaxMindのオープンソースデータを利用します
GeoLite2-City をダウンロードする -
ruby
IPと位置情報を紐付けデータを再出力します
require 'MaxMindDB'
db = MaxMindDB.new('GeoLite2-City.mmdb')
readFile = "log/orig.log"
outFile = "log/geoip.log"
outIp = []
begin
File.open(readFile){|file|
file.each_line{|access|
access.match(/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/){|md|
ip = md[0]
ret = db.lookup(ip)
str = "#{ip},¥"#{ret.location.latitude},#{ret.location.longitude}¥""
outIp << str
}
}
}
# 例外は小さい単位で捕捉する
rescue SystemCallError => e
puts %Q(class=[#{e.class}] message=[#{e.message}])
rescue IOError => e
puts %Q(class=[#{e.class}] message=[#{e.message}])
end
f = File.open(outFile, "w")
outIp.each { |s| f.puts(s) }
Elasticsearchの初期化
何もtemplateを指定しないと、geo_pointを認識してくれないので
明示的に型を定義します。
今回は、ipと位置情報のみを登録するようにします。
docker-composeのvolumeで指定した [./elasticsearch/config]配下に
設定ファイルを準備する
/* schema.json */
{
"mappings": {
"geo_ips": {
"properties": {
"ip": {
"type": "string",
"index" : "not_analyzed"
},
"location": {
"type": "geo_point"
}
}
}
}
}
}
- 作ったtemplateを元に indexの作成
curl -XPUT localhost:9200/geo_ips --data-binary @schema.json
embulk_configの作成
CSV情報をElasticsearchに取り込むように設定ファイルを作成します。
- embulk_config.yml
in:
type: file
path_prefix: /opt/log/geoip
parser:
charset: UTF-8
newline: CRLF
type: csv
delimiter: ','
quote: '"'
escape: ''
header_line: true
columns:
- {name: "ip", type: string}
- {name: "location", type: string}
out:
type: elasticsearch
mode: insert
nodes:
- {host: elasticsearch, port: 9200}
index: geo_ips
index_type: geo_ips
Elasticsearch実行
dockerコンテナ上で実行します
embulk run embulk_config.yml
Kibanaで確認
localhost:5601/
まとめ
fuluentdやLogstashを導入する場合はindexのtemplateだけしっかりしておけば、
そのまま表示できると思います。
ただサーバーになかなか入れらなかったり、アクセスログだけからの調査や確認をする場合は
割と便利だなと思いました。
もう少しtemplateを実用化してレガシーシステムのログも集約していければと思います。