2012-07-06 172 views
2

我正在使用NLog和记录事件到SQL服务器。其中一个记录的字段是日志级别,它被记录为一个字符串,'Info','Warn'等。我也想将这个级别记录为一个整数值,以便在查看日志事件时提供更好的排序一个GUI。Nlog枚举整数

是否有可能将枚举转换为整数以插入数据库而无需编写自定义布局渲染器?

配置行记录的电平到一个数据库作为字符串是

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

在理想情况下可能存在于整数转换,等等;

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

非常喜欢有一个format=tostring转换器。

+0

这几天简单地使用EF连接到数据库和运行查询,我不知道你为什么使用传统的日志记录方式。 – 2012-07-06 08:45:32

+1

因为这是我推出赛义德的方式。 – 2012-07-06 11:21:37

+0

我也使用log4net为正常日志(文件,事件查看器,控制台 ),但在数据库日志的情况下,我发现使用EF更容易,在特殊情况下不需要重新添加处理程序的代码,并且没有限制它,通常数据库日志是至关重要的,他们需要一些额外的信息。 – 2012-07-06 11:27:24

回答

1

这是我为此编写的自定义LayoutRenderer。我写的反对NLOG 1.0,所以它可能不是完全坚持NLOG 2.0约定LayoutRenderer(例如,我认为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; 
    } 

    } 
} 
+0

最后,我在持有日志记录的表上插入并更新触发器。根据日志级别字符串,它会更新LevelOrdinal整数字段。将逻辑掩埋在触发器中并不理想,但可能的日志级别足够静态以使其可接受。 – 2012-07-11 10:38:00

3

另一种选择是将字符串转换为在一个Integer插入语句如下:

<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> 
+0

最好的选择,你不能/不想部署额外的程序集 – fra 2015-01-27 08:01:17

1

试试这个布局渲染器。这是非常简单的)

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