明日から使える ASP.NET Core ロギング術!
by
neno
Link
Embed
Share
Beginning
This slide
Copy link URL
Copy link URL
Copy iframe embed code
Copy iframe embed code
Copy javascript embed code
Copy javascript embed code
Share
Tweet
Share
Tweet
Slide 1
Slide 1 text
明日から使える ASP.NET Core ロギング術! .NET ラボ 2023/07/22 何縫ねの。
Slide 2
Slide 2 text
自己紹介 1 • 所属: NTTコミュニケーションズ イノベーションセンター • 趣味: C#, OSS, ドール, 一眼(α7 IV) • 執心領域 • C# ⇔ TypeScript • SignalR 何縫ねの。 nenoNaninu nenoMake ブログ https://blog.neno.dev その他 https://neno.dev
Slide 3
Slide 3 text
OSS 紹介 2 属性を付与するだけ Tapper • C# の型定義から TypeScript の型定義を生成する .NET Tool/ library • JSON / MessagePack 対応! https://github.com/nenoNaninu/Tapper
Slide 4
Slide 4 text
OSS 紹介 3 • C# の SignalR Client を強く型付けするための Source Generator TypedSignalR.Client Before After (using TypedSignalR.Client) こんな SignalR の Hub と Receiver の interface が あったとして… 脱文字列! 全てが強く型付け! https://github.com/nenoNaninu/TypedSignalR.Client
Slide 5
Slide 5 text
4 • TypeScript の SignalR Client を強く型付けするための .NET Tool / library TypedSignalR.Client.TypeScript Before After (using TypedSignalR.Client.TypeScript) 脱文字列! 全てが強く型付け! TypeScript 用の型を C# から自動生成 MessagePack Hub Protocol 対応! https://github.com/nenoNaninu/TypedSignalR.Client.TypeScript 属性を付与するだけ! OSS 紹介
Slide 6
Slide 6 text
5 • SignalR 使ったアプリを快適に開発するための GUI を自動生成する library • 2 step で利用可能! • http pipeline に middleware の追加 • Hub と Receiver を定義してる interface に属性を付与 • JWT 認証 サポート • パラメータのユーザ定義型サポート • JSON で入力! SignalR 版 SwaggerUI TypedSignalR.Client.DevTools https://github.com/nenoNaninu/TypedSignalR.Client.DevTools OSS 紹介
Slide 7
Slide 7 text
ConsoleFormatter 6
Slide 8
Slide 8 text
ConsoleFormatter 7 • Microsoft.Extensions.Logging には以下のようなクラスが存在する。 • SimpleConsoleFormatter • JsonConsoleFormatter • SystemdConsoleFormatter コンソールにログを出力際のフォーマットは複数ある。
Slide 9
Slide 9 text
ConsoleFormatter 8 • Microsoft.Extensions.Logging には以下のようなクラスが存在する。 • SimpleConsoleFormatter • JsonConsoleFormatter • SystemdConsoleFormatter コンソールにログを出力際のフォーマットは複数ある。 internal なクラス 以下のように拡張メソッドで設定
Slide 10
Slide 10 text
ConsoleFormatter 9 • Microsoft.Extensions.Logging には以下のようなクラスが存在する。 • SimpleConsoleFormatter • JsonConsoleFormatter • SystemdConsoleFormatter コンソールにログを出力際のフォーマットは複数ある。 internal なクラス 以下のように拡張メソッドで設定
Slide 11
Slide 11 text
ConsoleFormatter 10 • Microsoft.Extensions.Logging には以下のようなクラスが存在する。 • SimpleConsoleFormatter • JsonConsoleFormatter • SystemdConsoleFormatter コンソールにログを出力際のフォーマットは複数ある。 internal なクラス 以下のように拡張メソッドで設定 このセッション中での 例は全て SimpleConsole
Slide 12
Slide 12 text
ConsoleFormatter 11 • Microsoft.Extensions.Logging には以下のようなクラスが存在する。 • SimpleConsoleFormatter • JsonConsoleFormatter • SystemdConsoleFormatter コンソールにログを出力際のフォーマットは複数ある。 スライドで JsonConsole の ログ見せられても 見辛いだけなので internal なクラス 以下のように拡張メソッドで設定 このセッション中での 例は全て SimpleConsole
Slide 13
Slide 13 text
HttpLogging 12
Slide 14
Slide 14 text
HttpLogging 13 • AddHttpLogging • 何をログに出力するかの設定を行う。 • 特定のヘッダやクエリを出力したりも可能 • UseHttpLogging • ログを出力するためのミドルウェアを request pipeline に追加 HTTP のリクエスト/リスポンスに関するログを出力したい。
Slide 15
Slide 15 text
HttpLogging 14 • AddHttpLogging • 何をログに出力するかの設定を行う。 • 特定のヘッダやクエリを出力したりも可能 • UseHttpLogging • ログを出力するためのミドルウェアを request pipeline に追加 HTTP のリクエスト/リスポンスに関するログを出力したい。 HttpLoggingFields (enum) を ビット演算でくっつけていく
Slide 16
Slide 16 text
HttpLogging 15 • AddHttpLogging • 何をログに出力するかの設定を行う。 • 特定のヘッダやクエリを出力したりも可能 • UseHttpLogging • ログを出力するためのミドルウェアを request pipeline に追加 HTTP のリクエスト/リスポンスに関するログを出力したい。 HttpLoggingFields (enum) を ビット演算でくっつけていく
Slide 17
Slide 17 text
HttpLogging 16 • AddHttpLogging • 何をログに出力するかの設定を行う。 • 特定のヘッダやクエリを出力したりも可能 • UseHttpLogging • ログを出力するためのミドルウェアを request pipeline に追加 HTTP のリクエスト/リスポンスに関するログを出力したい。 HttpLoggingFields (enum) を ビット演算でくっつけていく 出し過ぎには注意 パフォーマンス & GDPR
Slide 18
Slide 18 text
HttpLogging 17 • ログレベルの設定も必要 • appsettings.json 等で Microsoft.AspNetCore.HttpLogging の ログレベルを Information にしておく HTTP のリクエスト/リスポンスに関するログを出力したい。
Slide 19
Slide 19 text
HttpLogging 18 • なかなか良さそう。 • 本当に? HttpLoggingMiddleware によって出力されるログ
Slide 20
Slide 20 text
HttpLogging 19 • 同じエンドポイントを同時に叩くと… HttpLoggingMiddleware によって出力されるログ
Slide 21
Slide 21 text
HttpLogging 20 • 同じエンドポイントを同時に叩くと… HttpLoggingMiddleware によって出力されるログ リクエストが 来たのは分かる。 レスポンスを 返したのも分かる。
Slide 22
Slide 22 text
HttpLogging 21 • 同じエンドポイントを同時に叩くと… HttpLoggingMiddleware によって出力されるログ どのリクエストに どのリスポンスを 返したのかは分からない…! リクエストが 来たのは分かる。 レスポンスを 返したのも分かる。
Slide 23
Slide 23 text
HttpLogging 22 • 同じエンドポイントを同時に叩くと… HttpLoggingMiddleware によって出力されるログ どのリクエストに どのリスポンスを 返したのかは分からない…! リクエストが 来たのは分かる。 レスポンスを 返したのも分かる。 当然このままでは ビジネスロジックのログも リクエストとは無関係…!
Slide 24
Slide 24 text
ConsoleFormatterOptions .IncludeScopes 23
Slide 25
Slide 25 text
ConsoleFormatterOptions.IncludeScopes 24 設定はいたって簡単
Slide 26
Slide 26 text
ConsoleFormatterOptions.IncludeScopes 25 設定はいたって簡単
Slide 27
Slide 27 text
ConsoleFormatterOptions.IncludeScopes 26 • SpanId , TraceId, ParentId がログに含まれるようになる。 • これが嬉しい。 • 他にも RequestPath とか ConnectionId とかいろいろ。 IncludeScopes を true に設定した場合のログ
Slide 28
Slide 28 text
ConsoleFormatterOptions.IncludeScopes 27 • SpanId , TraceId, ParentId がログに含まれるようになる。 • これが嬉しい。 • 他にも RequestPath とか ConnectionId とかいろいろ。 IncludeScopes を true に設定した場合のログ
Slide 29
Slide 29 text
ConsoleFormatterOptions.IncludeScopes 28 リクエスト毎のログを追えるようになる…!
Slide 30
Slide 30 text
ConsoleFormatterOptions.IncludeScopes 29 リクエスト毎のログを追えるようになる…!
Slide 31
Slide 31 text
ConsoleFormatterOptions.IncludeScopes 30 リクエスト毎のログを追えるようになる…!
Slide 32
Slide 32 text
ConsoleFormatterOptions.IncludeScopes 31 • 「ログにスコープを含める」かどうかのオプション。 SpanId とか TraceId をログに出すためのオプションではない
Slide 33
Slide 33 text
ConsoleFormatterOptions.IncludeScopes 32 • 「ログにスコープを含める」かどうかのオプション。 SpanId とか TraceId をログに出すためのオプションではない 適当にログのスコープを 切ってあげると..
Slide 34
Slide 34 text
ConsoleFormatterOptions.IncludeScopes 33 • 「ログにスコープを含める」かどうかのオプション。 SpanId とか TraceId をログに出すためのオプションではない
Slide 35
Slide 35 text
ConsoleFormatterOptions.IncludeScopes 34 • 「ログにスコープを含める」かどうかのオプション。 SpanId とか TraceId をログに出すためのオプションではない
Slide 36
Slide 36 text
ConsoleFormatterOptions.IncludeScopes 35 • 「ログにスコープを含める」かどうかのオプション。 SpanId とか TraceId をログに出すためのオプションではない MyScope!!
Slide 37
Slide 37 text
W3C Trace Context 36
Slide 38
Slide 38 text
W3C Trace Context 37 Span 1 Span 3 Span 5 Span 2 Span 4 Service A Service B Service C Trace HTTP 分散トレースのための仕組み。 • ASP.NET Core 的には分散システムじゃなくても有益。
Slide 39
Slide 39 text
W3C Trace Context 38 Span 1 Span 3 Span 5 Span 2 Span 4 Service A Service B Service C Trace HTTP 分散トレースのための仕組み。 • ASP.NET Core 的には分散システムじゃなくても有益。 W3C Trace Context のより詳細は以下のブログで。 【C#】ASP.NET Core と W3C Trace Context とお手軽ロギング。 https://blog.neno.dev/entry/2023/07/04/181843
Slide 40
Slide 40 text
ExceptionHandler 39
Slide 41
Slide 41 text
ExceptionHandler 40 • Development • DeveloperExceptionPageMiddleware が自動で追加される • 例外が起きたとき HTTP の Response に stack trace が含まれたりするのは このミドルウェアがそういう仕事をしている • Staging / Production • 未処理の例外をハンドリングするためのミドルウェアは自動で追加されない • その結果どうなるかというと… ENVIRONMENT 次第で未処理の例外のハンドリングが変わる
Slide 42
Slide 42 text
ExceptionHandler 41 既定の構成 + ENVIRONMENT= Production で例外が発生した場合
Slide 43
Slide 43 text
ExceptionHandler 42 既定の構成 + ENVIRONMENT= Production で例外が発生した場合 例外が Kestrel にまで 突き抜けてしまっている..
Slide 44
Slide 44 text
ExceptionHandler 43 既定の構成 + ENVIRONMENT= Production で例外が発生した場合 例外が Kestrel にまで 突き抜けてしまっている.. HttpLogging の Response に 関するログも残らない…!
Slide 45
Slide 45 text
ExceptionHandler 44 • AddProblemDetails • RFC 7807 “Problem Details for HTTP APIs” に準拠したレスポンスを作成する ためのサービスの追加 • UseExceptionHandler • 未処理の例外をハンドリングするためのミドルウェアを追加 • UseHttpLogging() の下に。 UseExceptionHandler で未処理の例外をハンドリング
Slide 46
Slide 46 text
ExceptionHandler 45 UseExceptionHandler を利用した場合のログ
Slide 47
Slide 47 text
ExceptionHandler 46 UseExceptionHandler を利用した場合のログ 例外が Kestrel にまで 突き抜けてない
Slide 48
Slide 48 text
ExceptionHandler 47 UseExceptionHandler を利用した場合のログ 例外が Kestrel にまで 突き抜けてない HttpLogging の Response に 関するログがしっかり残る…!
Slide 49
Slide 49 text
ExceptionHandler 48 • RFC 7807 “Problem Details for HTTP APIs” に準拠したレスポンスを 返すようになる。 • traceId が含まれるようになるのが嬉しい。かもしれない。 例外発生時のレスポンス
Slide 50
Slide 50 text
DbDataSource 49
Slide 51
Slide 51 text
DbDataSource 50 • Npgsql / MySqlConnector は対応済み。 • https://github.com/npgsql/npgsql • https://github.com/mysql-net/MySqlConnector .NET 7 で追加された ADO.NET の新しい API https://github.com/dotnet/runtime/issues/64812
Slide 52
Slide 52 text
DbDataSource 51 • Npgsql / MySqlConnector は対応済み。 • https://github.com/npgsql/npgsql • https://github.com/mysql-net/MySqlConnector .NET 7 で追加された ADO.NET の新しい API https://github.com/dotnet/runtime/issues/64812 提案者は Npgsql の中の人 (MS の中の人でもある)
Slide 53
Slide 53 text
DbDataSource 52 • Npgsql の場合、NpgsqlDataSourceBuilder で DbDataSource を作成する • UseLoggerFactory() で loggerFactory を渡す。 • これだけで Command が叩かれた際によしなにログを出してくれるように DbDataSource はロギングの観点でも嬉しい
Slide 54
Slide 54 text
DbDataSource 53 • Npgsql の場合、NpgsqlDataSourceBuilder で DbDataSource を作成する • UseLoggerFactory() で loggerFactory を渡す。 • これだけで Command が叩かれた際によしなにログを出してくれるように 少なくとも Npgsql では DbDataSource はロギングの観点でも嬉しい
Slide 55
Slide 55 text
DbDataSource 54 • Npgsql の場合、NpgsqlDataSourceBuilder で DbDataSource を作成する • UseLoggerFactory() で loggerFactory を渡す。 • これだけで Command が叩かれた際によしなにログを出してくれるように 少なくとも Npgsql では DbDataSource の提案者が Npgsql の中の人なだけに 各実装でも Npgsql の 実装に寄せてくると 思われる DbDataSource はロギングの観点でも嬉しい
Slide 56
Slide 56 text
DbDataSource 55 実際に出力されるログ。
Slide 57
Slide 57 text
DbDataSource 56 実際に出力されるログ。
Slide 58
Slide 58 text
DbDataSource 57 実際に出力されるログ。 SpanId / TraceId がちゃんとログに 含まれているため、どのリクエストで どのクエリが発行されたのか一目瞭然
Slide 59
Slide 59 text
DbDataSource 58 実際に出力されるログ。 SpanId / TraceId がちゃんとログに 含まれているため、どのリクエストで どのクエリが発行されたのか一目瞭然 親切に duration (ms) も よしなに表示してくれる
Slide 60
Slide 60 text
HttpClientFactory 59
Slide 61
Slide 61 text
HttpClientFactory 60 • ASP.NET Core では HttpClient は直接 new してキャッシュせず、 HttpClientFactory を使うのがそもそものベストプラクティス [1] HttpClientFactory はロギングの観点でも嬉しい [1] https://learn.microsoft.com/en-us/dotnet/architecture/microservices/implement-resilient-applications/use-httpclientfactory-to-implement-resilient-http-requests [2] https://github.com/nenoNaninu/TraceContextExample
Slide 62
Slide 62 text
HttpClientFactory 61 実際に出力されるログ。 https://github.com/nenoNaninu/TraceContextExample
Slide 63
Slide 63 text
HttpClientFactory 62 実際に出力されるログ。 https://github.com/nenoNaninu/TraceContextExample
Slide 64
Slide 64 text
HttpClientFactory 63 実際に出力されるログ。 https://github.com/nenoNaninu/TraceContextExample リクエストとレスポンスの 双方をログに出力
Slide 65
Slide 65 text
HttpClientFactory 64 実際に出力されるログ。 親切にレスポンスが 返ってくるまでの時間も よしなに表示してくれる https://github.com/nenoNaninu/TraceContextExample リクエストとレスポンスの 双方をログに出力
Slide 66
Slide 66 text
まとめ 65 • AddHttpLogging / UseHttpLogging • Inbound HTTP request / response がログとして出力される • LoggingFields は RequestProperties | ResponseStatusCode がオススメ。 • ログレベルの設定を忘れずに。 • ConsoleFormatterOptions.IncludeScopes • ログのスコープが出力に含まれるようになる。 • SpanId / TraceId / ParentId が表示されて嬉しい。 • W3C Trace Context • 詳細はこちら : https://blog.neno.dev/entry/2023/07/04/181843 • AddProblemDetails / UseExceptionHandler • 未処理の例外をハンドリング / RFC 7807 • DbDataSource • Npgsql ではすべての Command がログとして出力される • HttpClientFactory • Outbound HTTP request / response がログとして出力される
Slide 67
Slide 67 text
References 66 • https://github.com/dotnet/runtime/tree/v7.0.8 • https://github.com/dotnet/aspnetcore/tree/v7.0.8 • https://github.com/dotnet/runtime/issues/64812 • https://learn.microsoft.com/en-us/aspnet/core/fundamentals/http-logging/?view=aspnetcore-7.0 • https://learn.microsoft.com/en-us/aspnet/core/fundamentals/logging/?view=aspnetcore-7.0 • https://learn.microsoft.com/en-us/aspnet/core/fundamentals/error-handling?view=aspnetcore-7.0 • https://learn.microsoft.com/en-us/dotnet/architecture/microservices/implement-resilient-applications/use- httpclientfactory-to-implement-resilient-http-requests • https://learn.microsoft.com/en-us/dotnet/core/diagnostics/distributed-tracing-concepts • https://www.w3.org/TR/trace-context/