.NET6.0のコンテナイメージでログの出力形式を変更したい場合は環境変数で上書きする。

# はじめに
普段 Serilog でログを出力しているので、ログの出力設定もSerilogの設定に依存しているため今まで気づきませんでしたが、.NET 6.0 のコンテナイメージの場合デフォルトのログの出力形式は取り回しのしやすさから JSON になっているようです。
[Breaking Change: Default console logger format set to JSON](https://github.com/dotnet/dotnet-docker/issues/3274)
この記事ではログの出力方法を標準の JSON 形式から別の形式に変更する方法について説明します。
# 標準で出力されるログ
ASP.NET Coreのプロジェクトを.NET 6.0で作り、Dockerで実行すると次のようなログが出力されます。

```json
{"EventId":60,"LogLevel":"Warning","Category":"Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository","Message":"Storing keys in a directory \u0027/root/.aspnet/DataProtection-Keys\u0027 that may not be persisted outside of the container. Protected data will be unavailable when container is destroyed.","State":{"Message":"Storing keys in a directory \u0027/root/.aspnet/DataProtection-Keys\u0027 that may not be persisted outside of the container. Protected data will be unavailable when container is destroyed.","path":"/root/.aspnet/DataProtection-Keys","{OriginalFormat}":"Storing keys in a directory \u0027{path}\u0027 that may not be persisted outside of the container. Protected data will be unavailable when container is destroyed."}}
{"EventId":14,"LogLevel":"Information","Category":"Microsoft.Hosting.Lifetime","Message":"Now listening on: https://[::]:443","State":{"Message":"Now listening on: https://[::]:443","address":"https://[::]:443","{OriginalFormat}":"Now listening on: {address}"}}
{"EventId":14,"LogLevel":"Information","Category":"Microsoft.Hosting.Lifetime","Message":"Now listening on: http://[::]:80","State":{"Message":"Now listening on: http://[::]:80","address":"http://[::]:80","{OriginalFormat}":"Now listening on: {address}"}}
{"EventId":0,"LogLevel":"Information","Category":"Microsoft.Hosting.Lifetime","Message":"Application started. Press Ctrl\u002BC to shut down.","State":{"Message":"Application started. Press Ctrl\u002BC to shut down.","{OriginalFormat}":"Application started. Press Ctrl\u002BC to shut down."}}
{"EventId":0,"LogLevel":"Information","Category":"Microsoft.Hosting.Lifetime","Message":"Hosting environment: Development","State":{"Message":"Hosting environment: Development","envName":"Development","{OriginalFormat}":"Hosting environment: {envName}"}}
{"EventId":0,"LogLevel":"Information","Category":"Microsoft.Hosting.Lifetime","Message":"Content root path: /app/","State":{"Message":"Content root path: /app/","contentRoot":"/app/","{OriginalFormat}":"Content root path: {contentRoot}"}}
```

# ログ形式の変更
実行時は何を設定するのでもなく JSON 形式で出てくれるのはうれしいのですが、Visual Studio でデバックするときなどは人が読みやすい形式で出力される方が望ましいです。

通常のアプリケーションの場合、次のようにすると appsettings.json で出力形式を変更できますが、Docker で動作するアプリケーションの場合は ASP.NET Core の標準の Dockerfile の設定で `Logging__Console__FormatterName` は `json` で上書きされるためこの設定は無視されます。

ログ形式の変更については下記のドキュメントを参照してください。

https://docs.microsoft.com/ja-jp/dotnet/core/extensions/console-log-formatter#set-formatter-with-configuration

```json:appsettings.json(標準の出力)
{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    },
    "Console": {
      "FormatterName": "simple"
    }
  },
  "AllowedHosts": "*"
}
```

通常のアプリの場合、上記の設定をすると次のようにシンプルなログが出力されます。

```
info: Microsoft.Hosting.Lifetime[14]
      Now listening on: https://localhost:7215
info: Microsoft.Hosting.Lifetime[14]
      Now listening on: http://localhost:5215
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development
```

今まで通り `simple` で出力したい場合は、Dockerfile でさらに上書きするか、コンテナ実行時に環境変数で上書きする必要があります。

```Dockerfile:Dockerfileでログ設定を上書きする例
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
ENV Logging__Console__FormatterName=simple
WORKDIR /app
EXPOSE 80
EXPOSE 443

FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
# ...略...
```

Dockerfile に設定してしまうと、運用環境でも `json` ではなく `simple` でログが出力されてしまいます。docker-compose が利用できるのであれば実行時の環境変数に設定して開発時のみ `simple` で出力したほうが良いでしょう。さらにいえば、docker-compose.yml よりも、docker-compose.override.yml で設定したほうがより望ましいでしょう。

```yaml:docker-compose.override.ymlでログ設定を上書きする例
version: '3.4'

services:
  webapplication25:
    environment:
      - ASPNETCORE_ENVIRONMENT=Development
      - ASPNETCORE_URLS=https://+:443;http://+:80
      - Logging__Console__FormatterName=simple
    ports:
      - "80"
      - "443"
    volumes:
      - ${APPDATA}/Microsoft/UserSecrets:/root/.microsoft/usersecrets:ro
      - ${APPDATA}/ASP.NET/Https:/root/.aspnet/https:ro     
```

# おわりに

.NET 6.0 になってコンテナサイズのさらなる縮小など、よりコンテナ環境に最適化された修正が行われています。
詳しくは下記のページを参照してください。

https://github.com/dotnet/dotnet-docker/issues/2382

https://github.com/dotnet/dotnet-docker/issues/3276