我已将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);
答案 0 :(得分:26)
%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>
这不符合您的目标吗?
答案 1 :(得分: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");
...
public static void Info(string message)
{
if (defaultLogger.IsEnabledFor(infoLevel))
{
defaultLogger.Log(typeof(Logger), infoLevel, message, null);
}
}
答案 2 :(得分:7)
只需声明您的日志变量......
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
然后你可以正常使用它。
答案 3 :(得分: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; }
}
}
}
答案 4 :(得分:3)
我只想使用像%stacktrace{2}
这样的转换模式。
输出示例:
MyNamespace.ClassName.Method&gt; Common.Log.Warning
其中MyNamespace.ClassName.Method
是一个调用我的包装器的方法,而Common.Log.Warning
是包装类的一个方法。
可以找到转换模式here。
答案 5 :(得分:1)
C#4.5如何使用callerinfo - http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.callermembernameattribute.aspx
答案 6 :(得分:0)
我能想到的唯一一件事(因为我目前不使用log4net)是请求堆栈跟踪(新的StackTrace),然后返回一个框架以获取所需的信息。但是,我不确定这对运行时性能的影响。
答案 7 :(得分: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>
答案 8 :(得分:0)
单击here了解如何在.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" };
}
然后调用相关的控制器操作(使用上述示例,使用HTTP GET调用/Values/Get
),您将收到与以下内容匹配的输出:
2019-06-05 19:58:45,103 [9] INFO- [Log4NetLogging_Project.Controllers.ValuesController.Get:23]-这是信息记录
答案 9 :(得分:0)
我为此(.Net framework 4.5+)实现了以下解决方案:log4net包装器方法(例如Info,Warn,Error)可以利用CallerMemberName和CallerFilePath来从以下位置获取代码的类和方法名:日志正在被调用。然后,您可以将它们聚合到一个自定义的log4net属性中。
随意使用您的log4net自己的包装器实现,这里唯一重要的事情是: Info和Error方法的签名以及GetLogger方法的实现。
调用Logger.Info或Logger.Error方法时,永远不要指定“ memberName”和“ sourceFilePath” args,它们由.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方法。