4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Logstashでの.jsonファイル取り込み方法

Last updated at Posted at 2021-08-17

.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への取り込み〇

hoge.json
[{"name":"toda","age":24},{"name":"shimoda","age":28},{"name":"kasuya","age":34}]

取り込みやすい形。

hoge.conf
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への取り込み×

hoge.json
[
    {
        "name":"toda",
        "age":24
    },
    {
        "name":"shimoda",
        "age":28
    },
    {
        "name":"kasuya",
        "age":34
    }
]
hoge.conf
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への取り込み〇

hoge.json
{"name":"toda","age":"24"}
hoge.conf
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だと、

hoge.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}
hoge.conf
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の場合

hoge.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への取り込み×

hoge.json
{
    "name":"toda",
    "age":24
},
{
    "name":"shimoda",
    "age":28
},
{
    "name":"kasuya",
    "age":34
}

hoge.json
{
    "name":"toda",
    "age":24
}
hoge.conf
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"
    }
}

hoge.conf
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なしのものにする。
一つのファイルに配列として足す形式か、

hoge.json
[{"name":"toda","age":24},{"name":"shimoda","age":28},{"name":"kasuya","age":34}]

データごとにファイルを分ける以下の形式にするか、にしようと思う。

hoge1.json
{"name":"toda","age":"24"}
hoge2.json
{"name":"shimoda","age":"28"}
hoge3.json
{"name":"kasuya","age":"34"}

## メモ
.confでcodec=>"json_lines"で改行ありも取り込めるっぽいけど、
何回か試して出力が不安定(どういう形式の.jsonが正なのかよくわからなかった)ので、
json_linesの使用は諦めた。

4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?