34

我已经将 Log4net 包装在一个静态包装器中并想要记录

loggingEvent.LocationInformation.MethodName
loggingEvent.LocationInformation.ClassName

然而,我得到的只是我的包装器的名称。

如何使用 forwardingappender 和静态包装类(如

Logger.Debug("Logging to Debug");
Logger.Info("Logging to Info");
Logger.Warn("Logging to Warn");
Logger.Error(ex);
Logger.Fatal(ex);
4

10 回答 10

30

%M%C变量呢 ?http://logging.apache.org/log4net/log4net-1.2.11/release/sdk/log4net.Layout.PatternLayout.html

用法,例如:

<layout type="log4net.Layout.PatternLayout">
  <conversionPattern value="%date [%thread] %-5level %logger [%M %C] - %message%newline" />
</layout>

这不是你所追求的吗?

于 2010-08-15T19:19:34.630 回答
29

好吧,错误出现在我的附加程序中,但为了完整起见,我尽我所知包括答案:

您需要的 Facade 应该包装 ILogger 而不是 ILog

 public static class Logger
 {
    private readonly static Type ThisDeclaringType = typeof(Logger);
    private static readonly ILogger defaultLogger;

    static Logger()
    {
      defaultLogger =
        LoggerManager.GetLogger(Assembly.GetCallingAssembly(),"MyDefaultLoggger");

...

    public static void Info(string message)
    {
        if (defaultLogger.IsEnabledFor(infoLevel))
        {
            defaultLogger.Log(typeof(Logger), infoLevel, message, null);
        }
    }
于 2008-10-01T14:28:50.223 回答
7

我会简单地使用类似的东西%stacktrace{2}作为转换模式。

输出示例:

MyNamespace.ClassName.Method > Common.Log.Warning

whereMyNamespace.ClassName.Method是调用我的包装器Common.Log.Warning的方法,并且是包装器类的方法。

转换模式可以在这里找到。

于 2015-05-05T20:39:21.170 回答
5

只需像这样声明您的日志变量...

private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

然后就可以正常使用了。

于 2008-10-01T14:30:32.343 回答
4

这篇文章帮助我弄清楚了如何编写自己的包装器,因此作为回报,我认为您可能会喜欢我的完整类来包装记录器,这似乎工作得很好,实际上只需要直接使用 ILog 的一半多一点时间!

所需要的只是在配置文件中设置日志记录的适当 xml 和

[assembly: log4net.Config.XmlConfigurator(Watch = true)] 

在您的 AssemblyInfo.cs 中,它应该很容易工作。

注意事项:我使用 Log4NetDash 的设置非常简单,因此被欺骗并将一些信息放在错误的字段中(例如,域字段中的堆栈跟踪),这仍然对我有用,因为我不在乎信息在哪里显示,但如果您在空闲时间正确设置内容,则可能需要解决此问题!

using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Reflection;
using System.Threading;
using log4net;
using log4net.Core;

namespace Utility
{
    public class Logger
    {
        static Logger()
        {
            LogManager.GetLogger(typeof(Logger));
        }

        public static void Debug(string message, params object[] parameters)
        {
            Log(message, Level.Debug, null, parameters);
        }

        public static void Info(string message, params object[] parameters)
        {
            Log(message, Level.Info, null, parameters);
        }

        public static void Warn(string message, params object[] parameters)
        {
            Log(message, Level.Warn, null, parameters);
        }

        public static void Error(string message, params object[] parameters)
        {
            Error(message, null, parameters);
        }

        public static void Error(Exception exception)
        {
            if (exception==null)
                return;
            Error(exception.Message, exception);
        }

        public static void Error(string message, Exception exception, params object[] parameters)
        {
            string exceptionStack = "";

            if (exception != null)
            {
                exceptionStack = exception.GetType().Name + " : " + exception.Message + Environment.NewLine;
                Exception loopException = exception;
                while (loopException.InnerException != null)
                {
                    loopException = loopException.InnerException;
                    exceptionStack += loopException.GetType().Name + " : " + loopException.Message + Environment.NewLine;
                }
            }

            Log(message, Level.Error, exceptionStack, parameters);
        }



        private static void Log(string message, Level logLevel, string exceptionMessage, params object[] parameters)
        {
            BackgroundWorker worker = new BackgroundWorker();
            worker.DoWork += LogEvent;
            worker.RunWorkerAsync(new LogMessageSpec
                                      {
                                          ExceptionMessage = exceptionMessage,
                                          LogLevel = logLevel,
                                          Message = message,
                                          Parameters = parameters,
                                          Stack = new StackTrace(),
                                          LogTime = DateTime.Now
                                      });
        }

        private static void LogEvent(object sender, DoWorkEventArgs e)
        {
            try
            {
                LogMessageSpec messageSpec = (LogMessageSpec) e.Argument;

                StackFrame frame = messageSpec.Stack.GetFrame(2);
                MethodBase method = frame.GetMethod();
                Type reflectedType = method.ReflectedType;

                ILogger log = LoggerManager.GetLogger(reflectedType.Assembly, reflectedType);
                Level currenLoggingLevel = ((log4net.Repository.Hierarchy.Logger) log).Parent.Level;

                if (messageSpec.LogLevel<currenLoggingLevel)
                    return;

                messageSpec.Message = string.Format(messageSpec.Message, messageSpec.Parameters);
                string stackTrace = "";
                StackFrame[] frames = messageSpec.Stack.GetFrames();
                if (frames != null)
                {
                    foreach (StackFrame tempFrame in frames)
                    {

                        MethodBase tempMethod = tempFrame.GetMethod();
                        stackTrace += tempMethod.Name + Environment.NewLine;
                    }
                }
                string userName = Thread.CurrentPrincipal.Identity.Name;
                LoggingEventData evdat = new LoggingEventData
                                             {
                                                 Domain = stackTrace,
                                                 Identity = userName,
                                                 Level = messageSpec.LogLevel,
                                                 LocationInfo = new LocationInfo(reflectedType.FullName,
                                                                                 method.Name,
                                                                                 frame.GetFileName(),
                                                                                 frame.GetFileLineNumber().ToString()),
                                                 LoggerName = reflectedType.Name,
                                                 Message = messageSpec.Message,
                                                 TimeStamp = messageSpec.LogTime,
                                                 UserName = userName,
                                                 ExceptionString = messageSpec.ExceptionMessage
                                             };
                log.Log(new LoggingEvent(evdat));
            }
            catch (Exception)
            {}//don't throw exceptions on background thread especially about logging!
        }

        private class LogMessageSpec
        {
            public StackTrace Stack { get; set; }
            public string Message { get; set; }
            public Level LogLevel { get; set; }
            public string ExceptionMessage { get; set; }
            public object[] Parameters { get; set; }
            public DateTime LogTime { get; set; }
        }
    }
}
于 2010-01-08T12:31:19.823 回答
2

C#4.5 功能调用者信息怎么样 - http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.callermembernameattribute.aspx

于 2014-06-11T06:49:32.263 回答
2

我为此实现了以下解决方案(.Net 框架 4.5+):log4net 包装器方法(例如 Info、Warn、Error)可以使用 CallerMemberName 和 CallerFilePath 来获取日志所在的代码的类和方法名称叫。然后,您可以将这些聚合到自定义 log4net 属性中。

随意使用您的 log4net 自己的包装器实现,这里唯一重要的是:Info 和 Error 方法的签名,以及 GetLogger 方法的实现。

在调用 Logger.Info 或 Logger.Error 方法时,不应指定“memberName”和“sourceFilePath”参数,它们由 .Net 自动填充。

public static class Logger
{
    private class LogSingletonWrapper
    {
        public ILog Log { get; set; }
        public LogSingletonWrapper()
        {
            Log = LogManager.GetLogger(GetType());
        }
    }

    private static readonly Lazy<LogSingletonWrapper> _logger = new Lazy<LogSingletonWrapper>();

    public static void Info(string message, [CallerMemberName] string memberName = "", [CallerFilePath] string sourceFilePath = "") 
        => GetLogger(memberName, sourceFilePath).Info(message);
    
    public static void Error(string message,Exception ex, [CallerMemberName] string memberName = "", [CallerFilePath] string sourceFilePath = "") 
        => GetLogger(memberName, sourceFilePath).Error(message, ex);

    private static ILog GetLogger(string memberName, string sourceFilePath)
    {
        var classname = sourceFilePath.Split('\\').Last().Split('.').First();
        log4net.ThreadContext.Properties["Source"] = $"{classname}.{memberName.Replace(".", "")}";
        return _logger.Value.Log;
    }
}

然后你可以在你的 .config 文件中使用这样的日志转换模式:

<conversionPattern value="[%level][%date][Thd%thread: %property{Source}][Message: %message]%newline" />

这将导致日志如下所示:

[INFO][2019-07-03 16:42:00,936][Thd1: Application.Start][消息:应用程序正在启动...]

[错误][2019-07-03 16:42:44,145][Thd6: DataProcessor.ProcessDataBatch][消息:试图除以零。]

上述示例中调用了以下方法:Application 类的 Start 方法和 DataProcessor 类的 ProcessDataBatch 方法。

于 2019-07-03T16:40:44.957 回答
0

我唯一能想到的(因为我目前不使用 log4net)是请求堆栈跟踪(新 StackTrace),然后返回一个框架以获取您需要的信息。但是,我不确定这对运行时性能的影响。

于 2008-10-01T11:58:01.617 回答
0

我只会写更多克劳斯正确答案的代码

在包装类中

public static class Logger
{
   private static readonly ILogger DefaultLogger;

   static Logger()
   {
      defaultLogger = LoggerManager.GetLogger(Assembly.GetCallingAssembly(), "MyDefaultLoggger"); // MyDefaultLoggger is the name of Logger
   }

  public static void LogError(object message)
  {
      Level errorLevel = Level.Error;
      if (DefaultLogger.IsEnabledFor(errorLevel))
      {
          DefaultLogger.Log(typeof(Logger), errorLevel, message, null);
      }
  }

  public static void LogError(object message, Exception exception)
  {
      Level errorLevel = Level.Error;
      if (DefaultLogger.IsEnabledFor(errorLevel))
      {
          DefaultLogger.Log(typeof(Logger), errorLevel, message, exception);
      }
  }

其余方法以此类推。

在 web.config 或 app.config log4net.Layout.PatternLayout中 ,您可以使用一些转换模式,例如:

%location %method %line

<layout type="log4net.Layout.PatternLayout">
    <conversionPattern value="%date{dd/MM/yyyy hh:mm:ss.fff tt} [%thread] %level %logger [%location %method %line] [%C %M] - %newline%message%newline%exception"/>
  </layout>
于 2015-11-16T22:18:53.567 回答
0

单击此处了解如何在 .NET Core 2.2 中实现 log4net

以下步骤取自上述链接,并分解了如何将 log4net 添加到 .NET Core 2.2 项目中。

首先,在 Package-Manager 控制台中运行以下命令:

Install-Package Log4Net_Logging -Version 1.0.0

然后添加带有以下信息的 log4net.config(请编辑它以匹配您的设置):

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
  </configSections>
  <log4net>
    <appender name="FileAppender" type="log4net.Appender.FileAppender">
      <file value="logfile.log" />
      <appendToFile value="true" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%d [%t] %-5p - %m%n" />
      </layout>
    </appender>
    <root>
      <!--LogLevel: OFF, FATAL, ERROR, WARN, INFO, DEBUG, ALL -->
      <level value="ALL" />
      <appender-ref ref="FileAppender" />
    </root>
  </log4net>
</configuration>

然后,将以下代码添加到控制器中(这是一个示例,请在将其添加到控制器之前对其进行编辑):

public ValuesController()
{
    LogFourNet.SetUp(Assembly.GetEntryAssembly(), "log4net.config");
}
// GET api/values
[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
    LogFourNet.Info(this, "This is Info logging");
    LogFourNet.Debug(this, "This is Debug logging");
    LogFourNet.Error(this, "This is Error logging");    
    return new string[] { "value1", "value2" };
}

然后调用相关的控制器操作(使用上面的示例,/Values/Get使用 HTTP GET 调用),您将收到与以下内容匹配的输出:

2019-06-05 19:58:45,103 [9] INFO-[Log4NetLogging_Project.Controllers.ValuesController.Get:23] - 这是信息记录

于 2019-06-05T15:29:51.657 回答