Docker版のシステムログをコンテナの外に出す

# Docker版のシステムログをコンテナの外に出す

本記事は [OSSのノーコード・ローコード開発ツール「プリザンター」のアドベントカレンダー](https://qiita.com/advent-calendar/2024/pleasanter) の13日目の記事です。

## はじめに

2024年12月10日リリースのプリザンター ver.1.4.11.0 にはシステムログをテキスト形式で出力する機能が追加されました。

[プリザンターの直近のバージョンアップ情報 \| Pleasanter](https://pleasanter.org/ja/manual/release-notes-core)

もちろんDocker版のプリザンターでもこの機能を使うことができます。  
今回はこの機能を使ってシステムログをコンテナの外に出してみます。

システムログの出力はデフォルトではデータベースだけですので、テキスト形式でも出力するようにパラメータを変更する必要があります。  
Docker版の場合はパラメータを変更するためには工夫が必要ですが、以下の手順で設定を行うことができます。  
本エントリはこちらの手順に設定を追加していきますので、先に動く状態にしておいてください。

[Dockerイメージを使用しパラメータを既定値から変更して起動する \| Pleasanter](https://pleasanter.org/ja/manual/change-parameters-at-docker-image)

## 今回のエントリでやること

- システムログをテキスト形式で出力する設定を行う
- コンテナのLoggerをfluentdにしてログをコンテナの外に出力する設定を行う
- コンテナの外にfluentdを立ててログを受け取る設定を行う

## 注意点

本エントリではfluentdをWSL2上で起動し、プリザンターはWindows上で起動しています。

また、今回の設定例では先にfluentdを起動しておく必要があります。

## 設定手順

さっそくシステムログをテキスト形式で出力する設定を行います。

こちらのマニュアルを参考に設定を行います。

[システムログをテキスト出力できるようにする \| Pleasanter](https://pleasanter.org/ja/manual/syslogs-text-output)

最終的なファイルの配置と設定対象を以下のようにします。

```text
.
|-- appsettings.json     # 追加
|-- compose.yaml         # 修正
|-- .env                 # 修正
|
+-- app_data_parameters
|   +-- SysLogs.json     # 追加
|
+-- CodeDefiner
|   +-- Dockerfile
|
+---Pleasanter
    +-- Dockerfile       # 修正
```

1. パラメータのSysLog.jsonをapp_data_parametersフォルダに追加します。
1. SysLog.jsonをマニュアルに従い編集します。
1. PleasanterディレクトリのDockerfileにCOPY命令を追加します。  
    (以下抜粋)

    ```Dockerfile
    COPY appsettings.json .
    ENTRYPOINT [ "dotnet", "Implem.Pleasanter.dll" ]
    ```

1. appsettings.jsonを次のように作成してcompose.yamlと同じディレクトリに配置します。

    ```json
    {
        "type": null,
        "Logging": {
            "LogLevel": {
                "Default": "Information",
                "Microsoft": "Warning",
                "Microsoft.Hosting.Lifetime": "Information"
            }
        },
        "NLog": {
            "throwConfigExceptions": true,
            "targets": {
                "logconsole": {
                    "type": "AsyncWrapper",
                    "target": {
                        "type": "Console",
                        "detectConsoleAvailable": true,
                        "writeBuffer": true,
                        "layout": {
                            "type": "JsonLayout",
                            "Attributes": [
                                {
                                    "name": "timestamp",
                                    "layout": "${date:format=O}"
                                },
                                {
                                    "name": "level",
                                    "layout": "${level:upperCase=true}"
                                },
                                {
                                    "name": "message",
                                    "layout": "${message}"
                                },
                                {
                                    "name": "syslog",
                                    "encode": false,
                                    "layout": {
                                        "type": "JsonLayout",
                                        "includeEventProperties": "true"
                                    }
                                },
                                {
                                    "name": "exception",
                                    "encode": false,
                                    "layout": {
                                        "type": "jsonLayout",
                                        "Attributes": [
                                            {
                                                "name": "type",
                                                "layout": "${exception:format=type}"
                                            },
                                            {
                                                "name": "message",
                                                "layout": "${exception:format=message}"
                                            },
                                            {
                                                "name": "stacktrace",
                                                "layout": "${exception:format=tostring}"
                                            }
                                        ]
                                    }
                                }
                            ]
                        }
                    }
                }
            },
            "rules": [
                {
                    "logger": "syslogs",
                    "minLevel": "Info",
                    "writeTo": "logconsole"
                }
            ]
        }
    }
    ```

1. compose.yamlのpleasanterサービスにloggingを追加します。  
   (以下抜粋)

    ```yaml
    services:
      pleasanter:
        ports:
          - '8881:8080'
        logging:
          driver: "fluentd"
          options:
            fluentd-address: localhost:24224
            fluentd-async-connect: "true"
            tag: "app.logs"
    ```

1. 環境変数用の .env のPLEASANTER_VERを1.4.11.0に変更します。

## fluentdの設定

ログの受け取り用のfluentdの設定を行います。

コンテナの外側にfluentdを起動してログを受け取るため、WSL2側に以下のような配置にします。

```text
.
|-- fluentd
|   +-- conf
|   |   +-- fluent.conf
```

fluent.confを以下のように作成します。

```conf
<source>
  @type forward
  port 24224
  bind 0.0.0.0
</source>

<match app.**>
  @type stdout
</match>
```

## 起動する

先にWSL2上でfluentdを起動しておきます。

今回はfluentdもDockerで動かします。以下のようにします。

```shell
docker run -p 24224:24224 -p 24224:24224/udp -v $(pwd)/fluentd/conf:/fluentd/etc --name=fluentd fluentd:v1.16-1
```

次にWindows側でプリザンターを起動します。  
お試しなので、初回起動時としてデータベースの初期化を行います。

```shell
docker compose build --pull
docker compose run --rm codedefiner _rds /l "ja" /z "Asia/Tokyo"
docker compose up -d pleasanter
```

プリザンターが起動したら、fluentdのコンソールにログが出力されることを確認します。

## 補足

- 本エントリはコンテナ外にシステムログをテキスト形式で出力できることの確認を目的としたものです。本番運用を想定したものではありませんのでご注意下さい
- 受け取り側のfluentdが起動していない場合にコンテナの起動に失敗する場合があります

## まとめ

Docker版のプリザンターでシステムログをテキスト形式で出力する設定を行い、fluentdでログを受け取る設定を行いました。

今回はfluentdを使ってログを受け取りましたが、他の方法でもログを受け取ることができます。詳しくはNLogのドキュメントやDockerのマニュアルを参照してください。