如何在包装NLog时保留呼叫站点信息

Dav*_*vid 31 c# logging nlog

我有一个包装NLog的类(称为NLogger).我的日志保存到我的数据库中.我遇到问题的是如何显示日志记录发生的位置.我有这个

<parameter name="@Logger" layout="${callsite}"/>  
Run Code Online (Sandbox Code Playgroud)

但这只是显示Core.Logging.Loggers.NLogLogger.Log这是我的NlogWrapper而不是调用我的包装器的类.

这是我的包装方法

        public void Log(LogType messageType, Type context, string message, Exception exception)
        {
            NLog.Logger logger = NLog.LogManager.GetLogger(context.Name);
            LogLevel logLevel = LogLevel.Info; // Default level to info

            switch (messageType)
            {
                case LogType.Debug:
                    logLevel = LogLevel.Debug;
                    break;
                case LogType.Info:
                    logLevel = LogLevel.Info;
                    break;
                case LogType.Warning:
                    logLevel = LogLevel.Warn;
                    break;
                case LogType.Error:
                    logLevel = LogLevel.Error;
                    break;
                case LogType.Fatal:
                    logLevel = LogLevel.Fatal;
                    break;
                default:
                    throw new ArgumentException("Log message type is not supported");                    
            }

            logger.Log(logLevel, message, exception);
        }
Run Code Online (Sandbox Code Playgroud)

wag*_*ghe 41

问题是你的包装器没有正确包装.下面是一个如何正确包装NLog的示例,直接从NLog源代码树中获取:

using System;
using System.Text;
using NLog;

namespace LoggerWrapper
{    
  /// <summary>    
  /// Provides methods to write messages with event IDs - useful for the Event Log target.    
  /// Wraps a Logger instance.    
  /// </summary>    
  class MyLogger    
  {        
    private Logger _logger;        

    public MyLogger(string name)        
    {            
      _logger = LogManager.GetLogger(name);        
    }        

    public void WriteMessage(string eventID, string message)           
    {            
      ///            
      /// create log event from the passed message            
      ///             
      LogEventInfo logEvent = new LogEventInfo(LogLevel.Info, _logger.Name, message);


      //
      // set event-specific context parameter            
      // this context parameter can be retrieved using ${event-context:EventID}            
      //            
      logEvent.Context["EventID"] = eventID;            
      //             
      // Call the Log() method. It is important to pass typeof(MyLogger) as the            
      // first parameter. If you don't, ${callsite} and other callstack-related             
      // layout renderers will not work properly.            
      //            
      _logger.Log(typeof(MyLogger), logEvent);        
    }    
  }
}
Run Code Online (Sandbox Code Playgroud)

关键是将记录器包装器的类型传递给对Log的调用.当NLog试图找到呼叫站点时,它会上升到堆栈,直到第一个调用方法的声明类型不是传递给Log调用的类型.这将是实际调用您的包装器的代码.

在您的情况下,您的记录器看起来像这样:

    public void Log(LogType messageType, Type context, string message, Exception exception)
    {
        NLog.Logger logger = NLog.LogManager.GetLogger(context.Name);
        LogLevel logLevel = LogLevel.Info; // Default level to info

        switch (messageType)
        {
            case LogType.Debug:
                logLevel = LogLevel.Debug;
                break;
            case LogType.Info:
                logLevel = LogLevel.Info;
                break;
            case LogType.Warning:
                logLevel = LogLevel.Warn;
                break;
            case LogType.Error:
                logLevel = LogLevel.Error;
                break;
            case LogType.Fatal:
                logLevel = LogLevel.Fatal;
                break;
            default:
                throw new ArgumentException("Log message type is not supported");                    
        }

        //
        // Build LogEvent here...
        //
        LogEventInfo logEvent = new LogEventInfo(logLevel, context.Name, message);
        logEvent.Exception = exception;

        //
        // Pass the type of your wrapper class here...
        //
        logger.Log(typeof(YourWrapperClass), logEvent);
    }
Run Code Online (Sandbox Code Playgroud)


Sol*_*Out 9

要跳过几帧并深入了解包装调用者上下文,请在App.config中设置,或者在程序中设置着名的修饰符:

skipFrames = 1

例如:请参见本页面${callsite:skipFrames=Integer}此页面${callsite-linenumber:skipFrames=Integer}

我建议你在包装器中使用这种格式:

${callsite:fileName=true:includeSourcePath=false:skipFrames=1}
Run Code Online (Sandbox Code Playgroud)

此设置的输出如下:

... {LicenseServer.LSCore.MainThreadFunction(LSCore.cs:220)} ...

  • 优胜者鸡肉晚餐,这对我来说非常有效。 (3认同)