2

我正在使用 NLog 并将事件记录到 SQL 服务器。记录的字段之一是日志级别,它记录为字符串、“信息”、“警告”等。我还想将级别记录为整数值,以便在查看日志事件时提供更好的排序图形用户界面。

是否可以在不编写自定义布局渲染器的情况下将枚举转换为整数以插入数据库?

将级别作为字符串记录到数据库中的配置行是

<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

这是我为此目的编写的自定义 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 回答
1

试试这个布局渲染器。这很简单)

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