.jsonファイルの書式ごとに、Logstash経由でのElasticsearchへの取り込み結果をまとめてみた。
動作環境
OS:Ubuntu Server 20.04.2 LTS
Elasticseach:7.13
Logstash:7.13
logstashの起動
.jsonファイルの取り込みを試すときは、
systemctl でやるよりも、binを直接叩いて実行した方がやりやすい。
systemctlだと、ログを都度journalctlで見る必要があり、面倒。
.binだと、叩いた直後からログがコンソールに出てくれる。
ログを見ないと、
「設定ファイルをちゃんと読み込んでない」のか、
「設定ファイルの内容が不適切で、取り込み対象のファイルを無視している」のかわかりにくい。
感覚的に詰まったときは大体後者。
binで実行する場合
sudo /usr/share/logstash/bin/logstash -f /etc/logstash/conf.d/hoge.conf
systemctlで実行する場合
systemctl start logstash.service
# logの確認
journalctl -u logstash.service -xe -n 100
.jsonの書式別 取り込み結果
■ .json(配列 + 改行 \n なし) ... Elasticseacrchへの取り込み〇
[{"name":"toda","age":24},{"name":"shimoda","age":28},{"name":"kasuya","age":34}]
取り込みやすい形。
input {
file {
path =>[/data/hoge.json],
sincedb_path => "/dev/null"
start_position => "beginning"
codec => "json"
}
}
#filter {
#
#}
output {
elasticsearch {
hosts => ["http://X.X.X.X:9200"]
index => "hogeIndex"
}
}
出力(Elasticsearchでの見え方)
~ ドキュメント1 (DBでいうレコード) ~
・・・
"name":"toda",
"age":24,
・・・
~ ドキュメント2 (DBでいうレコード) ~
・・・
"name":"shimoda",
"age":28,
・・・
~ ドキュメント3 (DBでいうレコード) ~
・・・
"name":"kasuya",
"age":34,
・・・
期待値
####■ .json(配列 + 改行 \n あり) ... Elasticseacrchへの取り込み×
[
{
"name":"toda",
"age":24
},
{
"name":"shimoda",
"age":28
},
{
"name":"kasuya",
"age":34
}
]
input {
file {
path =>[/data/hoge.json],
sincedb_path => "/dev/null"
start_position => "beginning"
codec => "json"
}
}
#filter {
#
#}
output {
elasticsearch {
hosts => ["http://X.X.X.X:9200"]
index => "hogeIndex"
}
}
.json(改行 \n なし)の場合と同じ
出力
例)"message" : "}",
"message" : """ "name":"toda",""",
\nがあるため、取り込めない。
一行ずつのレコードができる。
それぞれのレコードのmessageに、一行ごとのこまごまになった値が入る。
取り込もうと思えばできるけど、単純なオプション設定ではできないため、
細かくパースする設定が必要そう。
.jsonファイルを取り込む前にjqコマンドなどで一行の.jsonにした方が楽そう。
jq --compact-output
■ .json(配列ではない + 改行 \n なし) ... Elasticseacrchへの取り込み〇
{"name":"toda","age":"24"}
input {
file {
path =>[/data/hoge.json],
sincedb_path => "/dev/null"
start_position => "beginning"
codec => "json"
}
}
filter {
}
output {
elasticsearch {
hosts => ["http://X.X.X.X:9200"]
index => "hogeIndex"
}
}
出力
{
"took" : 0,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "hogeIndex",
"_type" : "_doc",
"_id" : "Xa9xP3sBW11KQnuE-Tml",
"_score" : 1.0,
"_source" : {
"host" : "HOGEHOGEHOGEHOGE",
"age" : "24",
"@timestamp" : "2021-08-17T12:17:19.067Z",
"@version" : "1",
"path" : "/data/hoge.json",
"name" : "toda"
}
}
]
}
}
期待値通りに取り込んでいる。
別の.confだと、
input {
file {
path =>[/data/hoge.json],
sincedb_path => "/dev/null"
start_position => "beginning"
}
}
filter {
json {
source => "message"
}
}
output {
elasticsearch {
hosts => ["http://X.X.X.X:9200"]
index => "hogeIndex"
}
}
出力
{
"took" : 0,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "hogeIndex",
"_type" : "_doc",
"_id" : "XK9uP3sBW11KQnuEGznB",
"_score" : 1.0,
"_source" : {
"host" : "HOGEHOGEHOGEHOGE",
"@version" : "1",
"path" : "/data/hoge.json",
"name" : "tanaka",
"message" : """{"name":"tanaka","age":"23"}""",
"age" : "23",
"@timestamp" : "2021-08-17T12:13:05.646Z"
}
}
...
]
}
}
この方法の場合は、
nameとageがそれぞれ別のフィールドとして取り込めているが、
messageフィールドに取り込みデータがそのまま入り、データが重複している。
.confのfilterでmessageフィールドをremoveする必要がある。
ただし、以下の形式はいまいち
{"name":"toda","age":24},{"name":"shimoda","age":28},{"name":"kasuya","age":34}
input {
file {
path =>[/data/hoge.json],
sincedb_path => "/dev/null"
start_position => "beginning"
codec => "json"
}
}
filter {
}
output {
elasticsearch {
hosts => ["http://X.X.X.X:9200"]
index => "hogeIndex"
}
}
出力
{
"took" : 0,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "hogeIndex",
"_type" : "_doc",
"_id" : "Xa9xP3sBW11KQnuE-Tml",
"_score" : 1.0,
"_source" : {
"host" : "HOGEHOGEHOGEHOGE",
"age" : "24",
"@timestamp" : "2021-08-17T12:17:19.067Z",
"@version" : "1",
"path" : "/data/hoge.json",
"name" : "toda"
}
}
]
}
}
{"name":"toda","age":24},{"name":"shimoda","age":28},{"name":"kasuya","age":34} のうち、
最初の{"name":"toda","age":24}しか取り込まれなかった。
別の.confの場合
input {
file {
path =>[/data/hoge.json],
sincedb_path => "/dev/null"
start_position => "beginning"
}
}
filter {
json {
source => "message"
}
}
output {
elasticsearch {
hosts => ["http://X.X.X.X:9200"]
index => "hogeIndex"
}
}
出力
...
"message" : """{"name":"toda","age":24},{"name":"shimoda","age":28},{"name":"kasuya","age":34}""",
...
一つのmessageフィールドにすべて含まれていた。
ドキュメント(DBでいうレコード)は一つのみ。
nameフィールドも、ageフィールドも作成されなかった。
つまりダメ。
####■ .json(配列ではない + 改行 \n あり) ... Elasticseacrchへの取り込み×
{
"name":"toda",
"age":24
},
{
"name":"shimoda",
"age":28
},
{
"name":"kasuya",
"age":34
}
や
{
"name":"toda",
"age":24
}
input {
file {
path =>[/data/hoge.json],
sincedb_path => "/dev/null"
start_position => "beginning"
codec => "json"
}
}
#filter {
#
#}
output {
elasticsearch {
hosts => ["http://X.X.X.X:9200"]
index => "hogeIndex"
}
}
や
input {
file {
path =>[/data/hogehoge.json],
sincedb_path => "/dev/null"
start_position => "beginning"
codec => "json"
}
}
filter {
}
output {
elasticsearch {
hosts => ["http://X.X.X.X:9200"]
index => "hogeIndex"
}
}
出力
...
"message" : """ "name":"toda",""",
...
messageフィールドのみ。ダメ。
## 結論
とりあえず取り込む.jsonファイルは改行\nなしのものにする。
一つのファイルに配列として足す形式か、
[{"name":"toda","age":24},{"name":"shimoda","age":28},{"name":"kasuya","age":34}]
データごとにファイルを分ける以下の形式にするか、にしようと思う。
{"name":"toda","age":"24"}
{"name":"shimoda","age":"28"}
{"name":"kasuya","age":"34"}
## メモ
.confでcodec=>"json_lines"で改行ありも取り込めるっぽいけど、
何回か試して出力が不安定(どういう形式の.jsonが正なのかよくわからなかった)ので、
json_linesの使用は諦めた。