web-dev-qa-db-ja.com

Serilogでの例外の構造化

次の例に示すように、Serilogにはオブジェクトを分解する便利な方法があります。

logger.Debug(exception, "This is an {Exception} text", exception);
logger.Debug(exception, "This is an {@Exception} structure", exception);

1行目では、ロガーは例外をプレーンテキストとして(ToString()を呼び出して)ログに記録します。2行目では、ロガーが例外プロパティを個別のフィールドとして書き込みます。しかし、このオーバーロードはどうですか?

logger.Debug(exception, "This is an exception", exception);

これは最初の引数として例外を取り、常に文字列として書き込まれます。私が可能にしたいのは、構造化された方法で例外のロギングを有効にすることです。これを達成するためにSerilogを構成することは可能ですか?

更新。この質問は例外のロギングの別の側面につながると思います:レンダリングされたテキストメッセージ(そのため、プレーンテキストのロガーは、例外の詳細の膨大な山で満たされていません。

25
Vagif Abilov

これについて議論するフォーラムスレッド があり、そこではいくつかの解決策が提示されています。 Thomas Bolonは、あなたが見つけることができる「例外的な破壊」拡張機能を作成しました Gist

この場合、次の構文のみを使用します。

logger.Debug(exception, "This is an exception");

例外をフォーマット文字列に追加する必要はありません。

例外がテキストシンクに出力されるようにするには、{Exception}は出力テンプレートに含まれています。標準のビルトインのものはすでにこれを持っています、例えば:

outputTemplate: "{Timestamp} [{Level}] {Message}{NewLine}{Exception}";
19

Serilog.Exceptions を見てください。Exception.ToString()に出力されない例外の詳細とカスタムプロパティが記録されます。

このライブラリには、最も一般的な例外タイプの追加プロパティを処理するカスタムコードがあり、例外が内部でSerilog.Exceptionsによってサポートされていない場合にのみ、リフレクションを使用して追加情報を取得します。

NuGetパッケージを追加してから、次のようにエンリッチャーを追加します。

_using Serilog;
using Serilog.Exceptions;

ILogger logger = new LoggerConfiguration()
    .Enrich.WithExceptionDetails()
    .WriteTo.Sink(new RollingFileSink(
        @"C:\logs",
        new JsonFormatter(renderMessage: true))
    .CreateLogger();
_

JSONログには、詳細な例外情報とカスタム例外プロパティが追加されます。 EntityFrameworkからDbEntityValidationExceptionをログに記録するとどうなるかを次に示します(この例外は、.ToString()に含まれていない深くネストされたカスタムプロパティがあることで有名です)。

_try
{
    ...
}
catch (DbEntityValidationException exception)
{
    logger.Error(exception, "Hello World");
}
_

上記のコードは、次のログを記録します。

_{
  "Timestamp": "2015-12-07T12:26:24.0557671+00:00",
  "Level": "Error",
  "MessageTemplate": "Hello World",
  "RenderedMessage": "Hello World",
  "Exception": "System.Data.Entity.Validation.DbEntityValidationException: Message",
  "Properties": {
    "ExceptionDetail": {
      "EntityValidationErrors": [
        {
          "Entry": null,
          "ValidationErrors": [
            {
              "PropertyName": "PropertyName",
              "ErrorMessage": "PropertyName is Required.",
              "Type": "System.Data.Entity.Validation.DbValidationError"
            }
          ],
          "IsValid": false,
          "Type": "System.Data.Entity.Validation.DbEntityValidationResult"
        }
      ],
      "Message": "Validation failed for one or more entities. See 'EntityValidationErrors' property for more details.",
      "Data": {},
      "InnerException": null,
      "TargetSite": null,
      "StackTrace": null,
      "HelpLink": null,
      "Source": null,
      "HResult": -2146232032,
      "Type": "System.Data.Entity.Validation.DbEntityValidationException"
    },
    "Source": "418169ff-e65f-456e-8b0d-42a0973c3577"
  }
}
_

Serilog.Exceptions は.NET標準をサポートし、リフレクションなしで多くの一般的な例外タイプをサポートしますが、さらに追加したいので、気軽に貢献してください。

ヒント-人間が読めるスタックトレース

Ben.Demystifier NuGetパッケージを使用して、人間が読める例外のスタックトレースを取得できます。Serilogを使用している場合は、 serilog-enrichers-demystify NuGetパッケージを使用できます。

33

これは完全に回避する必要があります。 ElasticSearchとSerilogはどちらも、任意のオブジェクトをシリアル化することを念頭に置いて設計されていません。形状が競合するオブジェクトをログに記録すると、ElasticSearchでマッピングの例外が発生します。 NuGetでElasticSearchシンクを使用している場合、マッピングの競合を引き起こすものはすべて失われます。また、Serilogは循環関係を処理しないため、深度リミッターのセルフログエラーが発生します。辞書に分解してこれをSerilogに渡すことでこれに対処しようとするプロジェクトがありますが、それでも厄介なログとマッピングの例外が発生します。

セリログ: https://nblumhardt.com/2016/02/serilog-tip-dont-serialize-arbitrary-objects/

例外で役立つと思われるものに基づいて、例外プロパティのロギングについて具体的に説明するのが最善です。

2
Daniel Leach