LogstashでGrokを使う方法を学ぼう!

こんにちわ! Suです!

最近、開発現場でLogstashのfilterを設定する機会があって、初めてGrokを触ったので、調べたGrokについて簡単にまとめました。

この記事がお役に立てれば幸いです!

Grokって何?

Grokは複雑なテキストデータのパターンマッチングを行うための強力なツールであり、ログの解析やデータ抽出など、さまざまな用途で活用されてるようです。

なんのこっちゃ分からん!w という方に向けてざっくり説明すると

こんな感じのテキスト(これはApacheというソフトのログです)を

127.0.0.1 - frank [10/Oct/2000:13:55:36 -0700] "GET /apache_pb.gif HTTP/1.0" 200 2326

こんな感じに構造化するためのツールです。これをElasticSearchに保存して、Kibanaで検索したりします。

{
  "client_ip": "127.0.0.1",
  "ident": "-",
  "user": "frank",
  "timestamp": "10/Oct/2000:13:55:36 -0700",
  "request": "GET /apache_pb.gif HTTP/1.0",
  "httpversion": "1.0",
  "response": "200",
  "bytes": "2326"
}

Grok使わなくても正規表現使えばいいじゃない

おっしゃる通りですが、今まで正規表現で頑張っていた解析を、簡単な表現で構造化できるのはすごいことだと思います。

試しに先ほどのこのログを正規表現で表現すると以下になります。

(?<client_ip>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) - (?<ident>\S+) (?<user>\S+) \[(?<timestamp>[^\]]+)\] "(?<request>[^"]+)" (?<response>\d{3}) (?<bytes>\d+)

どうでしょう?難しいですよね?

正規表現マスターであれば苦労はないかもしれませんが、それでも「1つ間違えれば正しく動作しない」ことになります。

Grokは複雑なフォーマットを簡単に表現できる素晴らしいツールだとわかります。

Grokのフォーマットってどこ見ればいいの?

ツールによってどのGrokパターンを持っているか分からないので、LogstashのGrokパターンだけおいておきます。

https://github.com/logstash-plugins/logstash-patterns-core/blob/main/patterns/legacy/grok-patterns

LogstashでGrokを使うフィルターの内容教えて

サンプルを以下に書きます。Logstashのフィルターは、「input」、「filter」、「output」と3つの構造に分かれています。

詳細は割愛しますが

  • inputは、データがどこから入ってくるかを指定する(標準入力ならstdin、Kafkaのならkafkaという設定になる)
  • filterは、今回まとめているgrokを使ったフィルターで構造化したり、不要なデータを除外したりなど行う
  • outputは、filterの結果をどのように出力するかを指定する(標準出力ならstdout、ElasticSearchに出力もできます)

という感じです。

#sample.conf
input {
  stdin {}
}

filter {
  grok {
    match => { "message" => "%{COMMONAPACHELOG}" }
  }
}

output {
  stdout { codec => rubydebug }
}

この”%{COMMONAPACHELOG}”の部分がGrokのパターンです。

他のパターンを使いたい場合は、この部分を変えましょう。

LogstashでGrokを使うフィルターを実際に試したい

Logstashが既に入っているサーバで実行する場合

Logstashが既に入っているサーバで実行する場合は、以下のコマンドでフィルターのテストを行いましょう。

cat sample.log | sudo /usr/share/logstash/bin/logstash -f sample.conf
  • sample.logは、フィルターを通して構造化したいログファイルのサンプルを入れます
  • sample.confは、先ほど説明したinput, filter, outputを定義したファイルを使います

Logstashが既に入っているサーバがない場合(ローカルで実行)

Logstashが入っていない場合は、Dockerを使ってローカルでLogstashサーバを用意して試しましょう。

まずは、DockerのLogstashイメージをダウンロード。バージョンはお好きなバージョンを入れてください(今回は8.6.0を使ってます)

docker pull docker.elastic.co/logstash/logstash:8.6.0

次に、ダウンロードしたDockerのイメージIDを確認します

$ docker images
REPOSITORY                            TAG       IMAGE ID       CREATED         SIZE
docker.elastic.co/logstash/logstash   8.6.0     d5c34d1abe55   14 months ago   747MB

Dockerを起動しつつ、Dockerに入ります

docker run -it --rm docker.elastic.co/logstash/logstash:8.6.0 /bin/bash

vi コマンドで、ログのサンプルファイルを作成します

vi sample.log

vi コマンドがDocker内にない場合は、ローカルでsample.logファイルを作り、ローカルからDockerにコピーしましょう

# docker psコマンドでimage IDを確認します
$ docker ps
CONTAINER ID   IMAGE                                       COMMAND                   CREATED         STATUS         PORTS            NAMES
0abcfeea57a3   docker.elastic.co/logstash/logstash:8.6.0   "/usr/local/bin/dock…"   8 minutes ago   Up 8 minutes   5044/tcp, 9600/tcp   compassionate_goodall

# docker cpコマンドで docker内にsample.logをコピーします
docker cp sample.log 0abcfeea57a3:/usr/share/logstash/sample.log

vi コマンドで、フィルターのサンプルファイルを作成します

vi sample.conf

viコマンドがDocker内にない場合は、sample.logと同様にローカルでsample.confファイルを作り、ローカルからDockerにコピーしましょう

catコマンドで、sample.logの内容を標準出力し、logstashコマンドに渡します。使うフィルターファイルを指定しつつ実行することで、Logstashのフィルターを試すことができます。

cat sample.log | /usr/share/logstash/bin/logstash -f sample.conf

こんな感じの結果が出ます。

{
     "timestamp" => "10/Oct/2000:13:55:36 -0700",
           "url" => {
        "original" => "/apache_pb.gif"
    },
       "message" => "127.0.0.1 - frank [10/Oct/2000:13:55:36 -0700] \"GET /apache_pb.gif HTTP/1.0\" 200 2326",
    "@timestamp" => 2024-03-29T03:44:07.097214358Z,
         "event" => {
        "original" => "127.0.0.1 - frank [10/Oct/2000:13:55:36 -0700] \"GET /apache_pb.gif HTTP/1.0\" 200 2326"
    },
          "http" => {
         "request" => {
            "method" => "GET"
        },
         "version" => "1.0",
        "response" => {
                   "body" => {
                "bytes" => 2326
            },
            "status_code" => 200
        }
    },
          "user" => {
        "name" => "frank"
    },
          "host" => {
        "hostname" => "d92b7409dc20"
    },
      "@version" => "1",
        "source" => {
        "address" => "127.0.0.1"
    }
}

うまくいかない場合は、以下の様にLogstashを起動した状態で、直接sample.logの内容をコピペしてもOKです。(stdinでLogstashが待機してくれているので、コピペでも受け付けてくれます)

/usr/share/logstash/bin/logstash -f sample.conf

環境つくるの面倒だなぁ、Grokフィルタ試せるサイトないの?

英語ですが、Grok Constructorというサービスがあります。こちらでは、入力とGrokフィルターを書くことで、どのような構造化がされるか試すことができます。

https://grokconstructor.appspot.com/do/match

最後に

いかがでしたでしょうか?

Grokの設定は最初は分かりづらいかもしれません。しかし、小さなサンプルから始めることで色んなパターンを試したりするとっかかりになると思います。

ELKスタックなどLogstashを触る機会が増えている昨今、Grokを学び、よりよいエンジニアライフを過ごしましょう!

では、またお会いしましょう!

最新情報をチェックしよう!