【问题标题】:Nlog Callsite is wrong when wrapper is used使用 wrapper 时 Nlog Callsite 错误
【发布时间】:2011-07-05 04:51:19
【问题描述】:

我正在使用 NLog 进行日志记录,我使用包装器来调用日志方法,我的问题是:如果我尝试打印有关调用站点 (${callsite}) 的信息,它会打印包装器方法而不是原始方法这导致记录器进行记录。

有什么方法可以获取调用包装器方法的原始方法吗?

【问题讨论】:

标签: c# logging nlog


【解决方案1】:

查看我对这个问题的回答:

Problem matching specific NLog logger name

我已经从这里的答案中复制了示例代码(用于缩写的 NLog 包装器)以节省一些麻烦:

  class NLogLogger : ILogger
  {
    private NLog.Logger logger;

    //The Type that is passed in is ultimately the type of the current object that
    //Ninject is creating.  In the case of my example, it is Class1 and Class1 is
    //dependent on ILogger.
    public NLogLogger(Type t)
    {
      logger = NLog.LogManager.GetLogger(t.FullName);
    }

    //Trace, Warn, Error, Fatal eliminated for brevity

    public bool IsInfoEnabled
    {
      get { return logger.IsInfoEnabled; }
    }

    public bool IsDebugEnabled
    {
      get { return logger.IsDebugEnabled; }
    }

    public void Info(string format, params object [] args)
    {
      if (logger.IsInfoEnabled)
      {
        Write(LogLevel.Info, format, args);
      }
    }

    public void Debug(string format, params object [] args)
    {
      if (logger.IsDebugEnabled)
      {
        Write(LogLevel.Debug, format, args);
      }
    }

    private void Write(LogLevel level, string format, params object [] args)
    {
      LogEventInfo le = new LogEventInfo(level, logger.Name, null, format, args);
      logger.Log(typeof(NLogLogger), le);
    }
  }

请注意,这个答案是在 NInject 的上下文中给出的。即使您不使用 NInject,同样的原则也适用于包装 NLog。关键是向 NLog 传达你的包装器的类型。

这是关于如何正确编写 NLog 包装器的示例(即维护呼叫站点信息)。关键在于 Write 方法。注意它是如何使用 NLog 的 Log 方法的。另请注意,这是将包装类的类型作为第一个参数传递。 NLog 使用类型信息向上导航调用堆栈。一旦它看到一个 DeclaringType 是传入类型(即包装器的类型)的方法,它就知道堆栈中的下一帧是调用方法。

另请参阅此链接(指向 NLog 的源存储库)以获取另外两个“扩展”Logger 示例。一种是包装,一种是继承:

https://github.com/jkowalski/NLog/tree/master/examples/ExtendingLoggers

我不是 100% 确定,但我认为你不能像这样简单地包装 NLog 并将 Info、Debug、Warn 等方法委托给 NLog:

class MyNLogWrapper
{
  private readonly Logger logger = LogManager.GetCurrentClassLogger();

  public void Info(string msg)
  {
    logger.Info(msg);
  }
}

您需要一种方法来告诉 NLog 包装器的类型,我认为您只能通过 Logger.Log 方法(重载)调用 NLog 来做到这一点。

如果这还不够有用,请发布您的包装以获得更多帮助。

【讨论】:

  • 当将扩展方法所在的类作为传递给Log的类型传递时,这似乎也适用于扩展方法。
【解决方案2】:

您也可以将其添加到您的 NLogLogger 类中,并在 Write 方法的第一行中调用它。

    protected void GetCurrentClassLogger()
    {
        //This should take you back to the previous frame and context of the Log call
        StackTrace trace = new StackTrace();

        if (trace.FrameCount > 1)
        {
            logger = LogManager.GetLogger(trace.GetFrame(1).GetMethod().ReflectedType.FullName);
        }
        else //This would go back to the stated problem
        {
            logger = LogManager.GetCurrentClassLogger();
        }
    }


    private void Write(LogLevel level, string format, params object[] args)
    {
        //added code
        GetCurrentClassLogger();

        LogEventInfo le = new LogEventInfo(level, logger.Name, null, format, args);
        logger.Log(typeof(NLogLogger), le);
    }

【讨论】:

    【解决方案3】:

    伙计们 经过几天的努力和搜索。最后,我只使用一个简单的类构建了 Nlog Wrapper,它可以保留 ${callsite} 并在创建 Nlog Wrapper 实例时获取正确的记录器名称。我将把代码放在后面加上简单的注释。如您所见,我使用 Stacktrace 来获取正确的记录器名称。使用 write 和 writewithex 注册 logevnet 以便保留调用站点。如果您有任何问题,请告诉我。

     public  class NlogWrapper 
        {  
            private  readonly NLog.Logger _logger; //NLog logger
    
        /// <summary>
        /// This is the construtor, which get the correct logger name when instance created  
        /// </summary>
    
        public NlogWrapper()
            {
            StackTrace trace = new StackTrace();
    
            if (trace.FrameCount > 1)
            {
                _logger = LogManager.GetLogger(trace.GetFrame(1).GetMethod().ReflectedType.FullName);
            }
            else //This would go back to the stated problem
            {
                _logger = LogManager.GetCurrentClassLogger();
            }
        }
        /// <summary>
        /// These two method are used to retain the ${callsite} for all the Nlog method  
        /// </summary>
        /// <param name="level">LogLevel.</param>
        ///  <param name="format">Passed message.</param>
        ///  <param name="ex">Exception.</param>
        private void Write(LogLevel level, string format, params object[] args)
        {
            LogEventInfo le = new LogEventInfo(level, _logger.Name, null, format, args);
            _logger.Log(typeof(NlogWrapper), le);
        }
        private void WriteWithEx(LogLevel level, string format,Exception ex, params object[] args)
        {
            LogEventInfo le = new LogEventInfo(level, _logger.Name, null, format, args);
            le.Exception = ex;
            _logger.Log(typeof(NlogWrapper), le);
        }
    
    
        #region  Methods
        /// <summary>
        /// This method writes the Debug information to trace file
        /// </summary>
        /// <param name="message">The message.</param>
        public  void Debug(String message)
            {
                if (!_logger.IsDebugEnabled) return;
    
            Write(LogLevel.Debug, message);
        }  
    
        public  void Debug(string message, Exception exception, params object[] args)
        {
            if (!_logger.IsFatalEnabled) return;
            WriteWithEx(LogLevel.Debug, message, exception);
        }
    
        /// <summary>
        /// This method writes the Information to trace file
        /// </summary>
        /// <param name="message">The message.</param>
        public  void Info(String message)
            {
                if (!_logger.IsInfoEnabled) return;
            Write(LogLevel.Info, message);
        }
    
        public  void Info(string message, Exception exception, params object[] args) 
        {
            if (!_logger.IsFatalEnabled) return;
            WriteWithEx(LogLevel.Info, message, exception);
        }
        /// <summary>
        /// This method writes the Warning information to trace file
        /// </summary>
        /// <param name="message">The message.</param>
        public  void Warn(String message)
            {
                if (!_logger.IsWarnEnabled) return;
              Write(LogLevel.Warn, message); 
            }
    
        public  void Warn(string message, Exception exception, params object[] args)
        {
            if (!_logger.IsFatalEnabled) return;
            WriteWithEx(LogLevel.Warn, message, exception);
        }
    
        /// <summary>
        /// This method writes the Error Information to trace file
        /// </summary>
        /// <param name="error">The error.</param>
        /// <param name="exception">The exception.</param>
        //   public static void Error( string message)
        //  {
        //    if (!_logger.IsErrorEnabled) return;
        //  _logger.Error(message);
        //}
    
        public  void Error(String message) 
        {
            if (!_logger.IsWarnEnabled) return;
            //_logger.Warn(message);
            Write(LogLevel.Error, message);
        }
        public void Error(string message, Exception exception, params object[] args)
        {
            if (!_logger.IsFatalEnabled) return;
            WriteWithEx(LogLevel.Error, message, exception);
        }  
    
    
        /// <summary>
        /// This method writes the Fatal exception information to trace target
        /// </summary>
        /// <param name="message">The message.</param>
        public void Fatal(String message)
            {
                if (!_logger.IsFatalEnabled) return;
             Write(LogLevel.Fatal, message);
        }
    
        public void Fatal(string message, Exception exception, params object[] args)
        {
            if (!_logger.IsFatalEnabled) return;
            WriteWithEx(LogLevel.Fatal, message, exception);
        }
    
        /// <summary>
        /// This method writes the trace information to trace target
        /// </summary>
        /// <param name="message">The message.</param>
        /// 
        public  void Trace(string message, Exception exception, params object[] args)  
        {
            if (!_logger.IsFatalEnabled) return;
            WriteWithEx(LogLevel.Trace, message, exception);
        }
        public  void Trace(String message)
            {
                if (!_logger.IsTraceEnabled) return;
                Write(LogLevel.Trace, message);
        }
    
            #endregion
    
        }
    

    【讨论】:

    • 当你在你的项目中使用它时。只需这样做: NlogWrapper mylog= new NlogWrapper( ); mylog.Error("这是关于:", ex).然后包装类将处理记录器名称和调用站点信息。当您使用 ${logger} ${callsite}。您将获得正确的信息,而不是 logwrapper 类调用站点的信息
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多