New Relic Infrastructure Agentはログ転送の機能を持っているため、シンプルにファイルをtailして更新した行をNew Relic Logsに送ったり、syslogやEvent Logを転送したりすることは数行の設定で可能です。このログ転送機能はFluent Bitを利用しているため、Fluent Bitの設定ファイルそのものを指定することで、Fluent Bitの機能を活用することができます。例えば1つのエントリが複数行にわたるようなログを転送したり、ログをパースし構造化した上で属性を追加したり、Luaスクリプトによりログを加工したりすることもできます。この記事では、fluentbitの機能を活用したログ転送のサンプルを紹介したいと思います。

対象となるログのエントリは以下のような複数行に渡るログです。スタックトレースを含んだ例外などを扱う場合を想定しています。それぞれのログのエントリは日時を含むメッセージで始まっていますが、複数のフォーマットが混在しています。もちろん、ログの出力フォーマットを変更した方がシンプルに解決できますが、すぐに変更できない場合にfluentbitの機能を活用して解決するケースを考えています。

2021-02-15 10:13:10 致命的なエラーが発生しました

RuntimeException at NewRelicLab.ExampleApp.Main

  [Thread-1] at XXX.YYY.ZZZ



15-Feb-2021 10:13:15.123 INFO 情報

起動完了

まず必要な設定ファイルを紹介します。まずはInfrastructure Agentのログ転送設定用のフォルダ(Linuxの場合 /etc/newrelic-infra/logging.d/、Windowsの場合 C:\Program Files\New Relic\newrelic-infra\logging.d\)に以下の設定ファイルを配置します。設定ファイル名およびnameキーの値は任意で、Windowsの場合は記載のパスをWindowsのものに置き換えてください。

logs:

  - name: external-fluentbit-config-and-parsers-file

    fluentbit:

      config_file: /etc/newrelic-infra/logging.d/fluentbit.conf

      parsers_file: /etc/newrelic-infra/logging.d/parsers.conf
そしてここで指定している2つのconfファイルが、Fluent Bitの設定ファイル形式のものです。参照するLuaスクリプトとあわせてGistに公開しています。

設定ファイルを保存後、Infrastructure Agentを再起動し、ログを追記するとNew Relic Logsに転送されクエリできるようになります。

次に、設定ファイルの説明もかねてFluent Bitがどのようにログをパースし解析するかを説明します。

  1. [INPUT]セクションでtail対象となる読み込むファイルを指定しています。
    1. Parser_Firstline は[PARSER]セクションのfirst_log_firstlineを参照します。
    2. Tagで指定しているfirst_logはあとで利用するため、名前を変える場合は注意が必要です。
  2. [PARSER]セクションのfirst_log_firstlineが実行されます。
    1. 複数行のログの場合、このフェーズでは各行はまだ分離されています。2行目以降は定義された最後の名前つきキャプチャグループに自動的に追加されるため、 このパーサー内でtimeやmessageといった追加の属性を抽出させることもできますが、厳密に最初の行を識別するためだけのものにすることをお勧めします。
    2. この例では、複数行にわたるログの最初の行を判定するために、正規表現はパイプ(|)で区切られた2つのタイムスタンプフォーマットにマッチさせています。ログのフォーマットによっては日時ではなく別の正規表現が適切かもしれません。
    3. ログメッセージのすべてをマッチさせるため、[\s\S]*?を使い、ログキャプチャグループ(?<log>...).に格納しています。行頭と行末を一致させるために^と$を使うことをお勧めします。
  3. parserという名前の[FILTER]セクションが実行されます。
    1. [INPUT]セクションでfirst_logとタグづけされたものを見つけます。1つのフィルタで複数のタグにマッチされることもできますが複雑になります。
    2. 次にログの属性を読み込みます。属性がないログに対してはなにもしません。
    3. [PARSER]で指定されたfirst_log_1もしくはfirst_log_2が見つかるまでログに対してパーサーを実行します。
      1. パーサーfirst_log_1もしくはfirst_log_2のどちらかに一致したらパース処理が実行されます。
      2. キャプチャグループtimeを含む複数のキャプチャグループにわけれます。
      3. Time_Keyで指定されたキャプチャグループ(ここではtime)を読み込み、Time_Keyに従い、Time_OffsetだけUTCとずれた日時をUnix時間に変換します。
      4. Time_Offsetはログメッセージの日時にタイムゾーンの指定がないものの、特定のタイムゾーンの時間を表しているときに使えます。ログメッセージにタイムゾーンの指定がある場合はTime_Formatで%zが利用できます。
  4. luaという名前の[FILTER]セクションが実行されます。
    1. [INPUT]セクションでfirst_logとタグづけされたものを見つけます。
    2. scriptで指定されたLuaスクリプトファイルのcallで指定された関数を実行します。このLuaスクリプトはFluent Bitのサンプルとして提供されているもので、[INPUT]セクションで指定されたタグをログのtag属性として追加します。逆に言うと、[INPUT]タグで指定したタグは、デフォルトではログに追加されず、Fluent Bit内部でのみ利用されます。
    3. 時刻の秒が小数の場合(Time_Formatで%Lを利用します)、time_as_tableを指定します。指定しない場合小数部分の精度が落ち、ずれた時刻のログとして保存されることがあります。この設定はFluent Bit 1.6.0で導入されたため、Infrastructure Agent 1.13.2以降を利用する必要があります。
  5. record_modifierという名前の[FILTER] セクションが実行されます
    1. Match *は、すべての[INPUT]ファイルに対して実行されることを意味します。
    2. ホスト名のような共通の属性を、ソースの形式に関係なく、すべてのレコードに追加します。
  6. file [OUTPUT]が実行されます
    1. 運用環境ではおすすめできませんが、設定のデバッグ目的などに利用できます。デバッグ目的では、[SERVICE]タグのログ出力も利用してください。
  7. ログレコードをNew Relicに送信します。New Relic Logsへの送信はInfrastructure Agentにより自動的に設定されているため、追加の設定は不要です。

 

このように、New Relic Infrastructure Agentのログ転送ではFluent Bitの機能を活用できます。Fluent Bitのすべての機能はドキュメントを参照してください。Infrastructure Agentと利用することで配布や再起動をまとめて管理することができます。