5

新しいレベルを追加できるように、カスタム log4net logger/logmanager を実装しようとしています。また、ターゲット テーブルのスキーマ (AdoNetAppender と SQL Server 2008 を使用しています) にいくつかのオプション フィールドを持たせたいと考えています。たとえば、追加しているレベルは使用状況を追跡するために使用され、フィールドの 1 つは Duration である必要があります (何かにかかった時間を示すため)。ただし、他のレベル (INFO、DEBUG、FATAL など) には、期間の値はありません。したがって、すべてのフィールドに値が含まれているわけではないテーブルに挿入できるようにする必要があります。できれば、無関係なフィールドに null 値を渡すために標準レベルのログ記録をすべて再実装する必要はありません。理想的には、log4net は、特定のロギング イベントで見つからないプロパティ値に対して自動的に NULL を渡します。

カスタム ロガーのコードは次のとおりです。

public void Usage(TimeSpan? duration, DateTime? startTime, DateTime? endTime, string message)
    {
        if (IsUsageEnabled)
        {
            LoggingEvent loggingEvent = new LoggingEvent(GetType(), Logger.Repository, Logger.Name, _currentUsageLevel,
                message, null);
            if (startTime.HasValue)
            {
                loggingEvent.Properties["StartTime"] = startTime.Value;
            }
            else
            {
                loggingEvent.Properties["StartTime"] = DBNull.Value;
            }

            if (endTime.HasValue)
            {
                loggingEvent.Properties["EndTime"] = endTime.Value;
            }
            else
            {
                loggingEvent.Properties["EndTime"] = DBNull.Value;
            }

            if (duration.HasValue)
            {
                loggingEvent.Properties["Duration"] = duration.Value.TotalMilliseconds;
            }
            else
            {
                loggingEvent.Properties["Duration"] = DBNull.Value;
            }

            Logger.Log(loggingEvent);
        }
    }

( DBNull.Value への割り当ては、値が渡されなかったときに log4net が null を渡すのに役立つことを期待して追加されましたが、削除できることを願っています)。

アペンダーの構成は次のとおりです。

<appender name="SQLAppender" type="log4net.Appender.AdoNetAppender">
  <bufferSize value="1" />
  <connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
  <connectionString value="my connection string (which actually gets replaced at runtime with a connection string retrieved from a config database)" />
  <commandText value="INSERT INTO MyTable ([Date],[Thread],[Level],[Logger],[Message],[Exception], [Login], [StartTime], [EndTime], [Duration]) VALUES (@log_date, @thread, @log_level, @logger, @message, @exception, @login, @start_time, @end_time, @duration)" />
  <parameter>
    <parameterName value="@log_date" />
    <dbType value="DateTime" />
    <layout type="log4net.Layout.RawTimeStampLayout" />
  </parameter>
  <parameter>
    <parameterName value="@thread" />
    <dbType value="String" />
    <size value="255" />
    <layout type="log4net.Layout.PatternLayout">
      <conversionPattern value="%thread" />
    </layout>
  </parameter>
  <parameter>
    <parameterName value="@log_level" />
    <dbType value="String" />
    <size value="50" />
    <layout type="log4net.Layout.PatternLayout">
      <conversionPattern value="%level" />
    </layout>
  </parameter>
  <parameter>
    <parameterName value="@logger" />
    <dbType value="String" />
    <size value="255" />
    <layout type="log4net.Layout.PatternLayout">
      <conversionPattern value="%logger" />
    </layout>
  </parameter>
  <parameter>
    <parameterName value="@message" />
    <dbType value="String" />
    <size value="4000" />
    <layout type="log4net.Layout.PatternLayout">
      <conversionPattern value="%message" />
    </layout>
  </parameter>
  <parameter>
    <parameterName value="@exception" />
    <dbType value="String" />
    <size value="4000" />
    <layout type="log4net.Layout.ExceptionLayout" />
  </parameter>
  <parameter>
    <parameterName value="@login" />
    <dbType value="String" />
    <size value="255" />
    <layout type="log4net.Layout.PatternLayout">
      <conversionPattern value="%property{CurrentLogin}" />
    </layout>
  </parameter>
  <parameter>
    <parameterName value="@start_time" />
    <dbType value="DateTime" />
    <layout type="log4net.Layout.PatternLayout"
      value="%property{StartTime}" />
  </parameter>
  <parameter>
    <parameterName value="@end_time" />
    <dbType value="DateTime" />
    <layout type="log4net.Layout.PatternLayout">
      <conversionPattern value="%property{EndTime}" />
    </layout>
  </parameter><parameter>
    <parameterName value="@duration" />
    <dbType value="Double" />
    <layout type="log4net.Layout.PatternLayout">
      <conversionPattern value="%property{Duration}" />
    </layout>
  </parameter>
</appender>

カスタム レベルで何かをログに記録しようとすると、期間、開始時間、終了時間を渡した場合にのみ機能します。デフォルトレベルを含む他のものについては、出力ウィンドウに手がかりがなく、サイレントに失敗するようです(ただし、デフォルトレベルでログを記録すると、StringをDateTimeまたはDoubleに変換できないという例外がスローされます)。

これがこのように静かに失敗する理由を誰もが理解できる理由はありますか?

4

1 に答える 1

7

いくつかのlog4netソースをトレースした後、私は最終的にそれを理解しました。問題は、カスタム パラメーターのレンダリングに PatternLayout を使用していたことです。このレイアウトはnullstringに強制されるため、テーブル内の null 許容フィールド"(null)"などに挿入しようとすると問題が発生します。datetime解決策は簡単です。PatternLayout レイアウトを使用する代わりに、log4net.Layout.RawPropertyLayout を使用します。これにより、null プロパティが として渡されますnull。これが必要です。

于 2010-07-13T16:39:24.207 に答える