如何在包装Log4net时记录MethodName?

Cla*_*sen 27 .net logging log4net

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

loggingEvent.LocationInformation.MethodName
loggingEvent.LocationInformation.ClassName
Run Code Online (Sandbox Code Playgroud)

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

如何使用forwardingappender和静态包装类来记录该信息

Logger.Debug("Logging to Debug");
Logger.Info("Logging to Info");
Logger.Warn("Logging to Warn");
Logger.Error(ex);
Logger.Fatal(ex);
Run Code Online (Sandbox Code Playgroud)

Mag*_*son 27

怎么样%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>
Run Code Online (Sandbox Code Playgroud)

那不是你做的事吗?

  • 注意主题中的"包装时".在问题作者的例子中(当包装ILog时)%M将等同于"Debug","I​​nfo"等,这是没用的. (10认同)

Cla*_*sen 24

好吧,错误是在我的附近,但为了完整性,包括我所知的最佳答案:

你需要的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");
Run Code Online (Sandbox Code Playgroud)

...

    public static void Info(string message)
    {
        if (defaultLogger.IsEnabledFor(infoLevel))
        {
            defaultLogger.Log(typeof(Logger), infoLevel, message, null);
        }
    }
Run Code Online (Sandbox Code Playgroud)

  • 我不敢相信这些信息很难找到。谢谢! (2认同)

nig*_*der 7

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

输出示例:

MyNamespace.ClassName.Method > Common.Log.Warning

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

可以在此处找到转换模式。


小智 6

只需声明你的日志变量......

private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
Run Code Online (Sandbox Code Playgroud)

然后你可以正常使用它.

  • 没工作,但我希望这很容易! (10认同)

小智 5

我为此实现了以下解决方案(.Net Framework 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后您可以在 .config 文件中使用如下日志转换模式:

<conversionPattern value="[%level][%date][Thd%thread: %property{Source}][Message: %message]%newline" />
Run Code Online (Sandbox Code Playgroud)

这将导致日志看起来像这样:

[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 方法。