2

NLog を使用し、イベントを SQL サーバーに記録しています。ログに記録されるフィールドの 1 つはログ レベルです。これは文字列、'Info'、'Warn' などとして記録されます。ログ イベントをGUI。

カスタム レイアウト レンダラーを作成せずに、データベースに挿入するために列挙型を整数に変換することは可能ですか?

レベルを文字列としてデータベースに記録する構成行は次のとおりです。

<parameter name="@Level" layout="${level}"/>

理想的には、次のような整数への変換があるかもしれません。

<parameter name="@LevelId" layout="${level:format=tointeger}"/>

format=tostringコンバーターがあるのと同じように。

4

3 に答える 3

3

別のオプションは、次のように挿入ステートメントで文字列を整数に変換することです。

<target name="database" xsi:type="Database" connectionStringName="MyConnectionStringName" useTransactions="true">
  <commandText>
    <![CDATA[
    INSERT INTO [dbo].LogEvent
      (Time,
       LogLevel,
       Title,
       Message,
       ExceptionDetails)
    VALUES
      (@Time,
       CASE @Level
       WHEN 'Trace' THEN 0
       WHEN 'Debug' THEN 1
       WHEN 'Info' THEN 2
       WHEN 'Warn' THEN 3
       WHEN 'Error' THEN 4
       WHEN 'Fatal' THEN 5
       ELSE NULL
       END,
       @Title,
       @Message,
       @ExceptionDetails)
    ]]>
  </commandText>
  <parameter name="@Time" layout="${date:format=yyyy-MM-dd HH\:mm\:ss.fff}" />
  <parameter name="@Level" layout="${level}" />
  <parameter name="@Title" layout="${ndc}" />
  <parameter name="@Message" layout="${message}" />
  <parameter name="@ExceptionDetails" layout="${exception:format=tostring}" />
</target>
于 2014-06-20T00:01:34.290 に答える
1

このレイアウト レンダラーを試してください。とてもシンプルです)

public class NlogLevelToIntLayoutRenderer : LayoutRenderer
{
    protected override void Append(StringBuilder builder, LogEventInfo logEvent)
    {
        builder.Append(logEvent.Level.Ordinal);
    }
}
于 2015-02-19T13:13:39.903 に答える
1

これは、まさにこの目的のために作成したカスタム LayoutRenderer です。NLog 1.0 に対して書いたので、LayoutRenderer の NLog 2.0 規則に完全には準拠していない可能性があります (たとえば、GetEstimatedBufferSize は使用されなくなったと思います)。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using NLog;
using NLog.LayoutRenderers;

namespace NLog.Extensions
{
  [LayoutRenderer("LogLevelOrdinal")]
  class LogLevelOrdinalLayoutRenderer : LayoutRenderer
  {
    IDictionary<LogLevel, int> ordinals;

    public override void  Initialize()
    {
      base.Initialize();

      ordinals = GetLogLevels()
                  .OrderBy(level => level)
                  .Select((level, index) => new { Level = level, Ordinal = index })
                  .ToDictionary( x => x.Level, x => x.Ordinal);
    }

    protected override void Append(StringBuilder builder, LogEventInfo logEvent)
    {
      int level = 0;

      if (!ordinals.TryGetValue(logEvent.Level, out level)) level = 99;

      builder.Append(level);
    }

    protected override int GetEstimatedBufferSize(LogEventInfo logEvent)
    {
      return 1;
    }

    //
    // LogLevel is a static class with a static member for each of the different log levels.
    // The LogLevel ordinal is not exposed publically (i.e. an ordinal indicating the relative
    // "importance" of a LogLevel value).
    // The implementation of LogLevel.GetHashCode actually does return the ordinal, but it doesn't
    // seem right to rely on that implementation detail.
    // In the end, this LayoutRenderer is really just to allow for producing a numeric value to represent
    // a particular log level value's "position" relative to the other lob levels.  As such, 
    // We can just get all of the known log level values, order them (they are sortable), and assign our
    // own ordinal based on the position of the log level value in the resulting sorted list.
    //
    // This helper function exposes the known log level values as IEnumerable<LogLevel> so that we can
    // easily use LINQ to build a dictionary to map LogLevel to ordinal.
    //
    internal IEnumerable<LogLevel> GetLogLevels()
    {
      yield return LogLevel.Trace;
      yield return LogLevel.Debug;
      yield return LogLevel.Info;
      yield return LogLevel.Warn;
      yield return LogLevel.Error;
      yield return LogLevel.Fatal;
    }

  }
}
于 2012-07-09T18:24:39.773 に答える