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/