Tanzu Kubernetes Grid ExtensionsのFluent Bitにyttを使ってLua Filterでscriptを設定するメモ

TKG ExtensionsのFluent Bitをyttでカスタマイズする例です。

ここではLua Filterを使ってLua Scriptによるrecordの加工を行います。 ログメッセージ中の@n@\nに変換する処理を書きます。

以下ではTKG Extensionは1.2を使用しています。マニフェストはこちらからダウンロードできます。 tkg-extensionsディレクトリに展開してある前提です。

次のディレクトリ及びファイルを作成します。

tkg-extensions/overlays/logging/fluent-bit/filter-transform.yaml

#@ load("@ytt:overlay", "overlay")
#@overlay/match by=overlay.subset({"kind":"ConfigMap", "metadata": {"name": "fluent-bit-config"}})
---
data:
  #@overlay/replace via=lambda a, b: a + b
  filter-record.conf: |

    [FILTER]
        Name    lua
        Match   *
        script  /fluent-bit/scripts/transform.lua
        call    cb_transform
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: fluent-bit-scripts
  namespace: tanzu-system-logging
  labels:
    k8s-app: fluent-bit
data:
  transform.lua: |
    function cb_transform(tag, timestamp, record)
       if record['message'] ~= nil then
         record['message'] = record['message']:gsub('@n@', '\n')
       end
       return 2, timestamp, record
    end
#@overlay/match by=overlay.subset({"kind":"DaemonSet", "metadata": {"name": "fluent-bit"}})
---
spec:
  template:
    spec:
      containers:
      #@overlay/match by="name"
      - name: fluent-bit
        volumeMounts:
        #@overlay/match by="name", missing_ok=True
        - name: fluent-bit-scripts
          mountPath: /fluent-bit/scripts/
      volumes:
      #@overlay/match by="name", missing_ok=True
      - name: fluent-bit-scripts
        configMap:
          name: fluent-bit-scripts

やっていることは

  • fluent-bit-config ConfigMapのfilter-record.confにLua用の[Filter]の設定を追記
  • Lua Scriptを含むfluent-bit-scripts Config Mapを追加
  • fluent-bit DaemonSetにfluent-bit-scripts ConfigMapをマウント

です。

yttで結合するの例は以下の通りです。

ytt \
  -f tkg-extensions/common \
  -f tkg-extensions/logging/fluent-bit \
  -f tkg-extensions/overlays/logging/fluent-bit/filter-transform.yaml \
  -v tkg.instance_name=my-instance \
  -v tkg.cluster_name=my-cluster \
  -v fluent_bit.output_plugin=elasticsearch \
  -v fluent_bit.elasticsearch.host=elasticsearch.elasticsearch-kibana.svc.cluster.local \
  -v fluent_bit.elasticsearch.port=9200

これをkubectlkappでデプロイすれば良いです。

今回の例は、アプリのログが複数行に跨がる場合に、Fluent Bitが各行をそれぞれ別レコードとしてElasticsearchなどに送信し、検索しづらくなるのを防ぐため、 アプリ側で\n@n@に置換し、複数行のログを1行にまとめ、Fluent Bit側で送信する前に再度@n@\nに戻す処理を行いたくて実装しました。

Spring BootでSLF4Jを使う場合は次の環境変数を設定することでログの\n@n@に置換できます。

        - name: LOGGING_EXCEPTIONCONVERSIONWORD
          value: "\t%replace(%replace(%xEx){'\n','@n@'}){'\t','    '}%nopex"
        - name: LOGGING_PATTERN_CONSOLE
          value: "%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${logging.pattern.level:%5p}) %clr(${PID: }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %replace(%m){'\n','@n@'}${logging.exception-conversion-word:%wEx}%n"

例えば次のようにElasticsearch上で複数行ログを見ることができます。

image

尚、複数行対応はFluent BitのMultiline Configurationを設定した方がスマートだと思います。 また、既存のログフォーマット自体を変えて良いならecs-loggingを使って構造化ログを送った方が良いでしょう。

追記

Elasticsearchの表示改行させるだけなら次のように\n\rするだけで良かったです。

        - name: LOGGING_EXCEPTIONCONVERSIONWORD
          value: "\t%replace(%replace(%xEx){'\n','\r'}){'\t','    '}%nopex"
        - name: LOGGING_PATTERN_CONSOLE
          value: "%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${logging.pattern.level:%5p}) %clr(${PID: }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %replace(%m){'\n','\r'}${logging.exception-conversion-word:%wEx}%n"

わざわざLuaで@n@\nに置換する必要はありませんでした。他の用途でLuaスクリプトを使いたいことがあると思うので、この記事は残しておきます。