NLog自定义日志级别

本文关键字:日志 自定义 NLog | 更新日期: 2023-09-27 18:02:22

我有一个数据库,我试图写我的消息,并希望使用${level}布局,但我需要将其转换为int值,以参考我自己的表,存储日志级别。是否有可能在配置中将级别转换为我的enum ?还有其他想法吗?

NLog自定义日志级别

我没有检查过这个,但我怀疑你应该能够为NLog编写自己的布局渲染器(插件)来做你想做的事情。NLog是非常可插拔的:)

一个布局渲染器的快速示例(未测试…):

[LayoutRenderer("intLevel", UsingLogEventInfo = true)]
public class IntLevel : LayoutRenderer
{
    protected override int GetEstimatedBufferSize(LogEventInfo logEvent)
    {
        return 1;
    }
    protected override void Append(StringBuilder builder, LogEventInfo logEvent)
    {
        switch(logEvent.Level.LowercaseName)
        {
            case "trace":
                builder.Append(0);
                break;
            case "debug":
                builder.Append(1);
                break;
            case "info":
                builder.Append(2);
                break;
            case "warn":
                builder.Append(3);
                break;
            case "error":
                builder.Append(4);
                break;
            case "fatal":
                builder.Append(5);
                break;
            default:
                builder.Append(-1);
                break;
        }
    }
}

试试这个解决方案:

[LayoutRenderer("levelInt")]
public class NlogLevelToIntLayoutRenderer : LayoutRenderer
{
    protected override void Append(StringBuilder builder, LogEventInfo logEvent)
    {
        builder.Append(logEvent.Level.Ordinal);
    }
}

这是一个经过测试的布局渲染器,它将日志级别记录为整数。我获得日志级别的方式可能有点过火,但我正在经历一个linq阶段;-)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NLog;
using NLog.LayoutRenderers;
namespace MyNLogExtensions.NLog
{
  [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;
    }
  }
}