包装 NLog 时如何保留调用点信息
我有一个包装 NLog 的类(称为 NLogger)。我的日志保存到我的数据库中。 我遇到的问题是如何显示日志记录发生的位置。 我有这个
<parameter name="@Logger" layout="${callsite}"/>
,但这只是显示 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);
}
I have a class that wraps NLog (called NLogger). My logs are saved to my database.
The thing I'm having a problem with is how do I show where the logging occured.
I have this
<parameter name="@Logger" layout="${callsite}"/>
but this just shows Core.Logging.Loggers.NLogLogger.Log which is my NlogWrapper not the class which calls my wrapper.
This is my wrapper method
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);
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
问题是你的包装纸没有正确包装。下面是如何正确包装 NLog 的示例,直接取自 NLog 源树:
关键是将记录器包装器的类型传递给对 Log 的调用。当 NLog 尝试找到调用点时,它会在堆栈中向上查找,直到第一个调用方法的声明类型不是传递给 Log 调用的类型。这将是实际调用包装器的代码。
在你的情况下,你的记录器看起来像这样:
The problem is that your wrapper is not wrapping correctly. Here is an example of how to wrap NLog correctly, taken directly from the source tree of NLog:
The key is passing the type of your logger wrapper to the call to Log. When NLog tries to find the callsite, it goes up the stack until the first calling method whose declaring type is NOT the type passed to the Log call. This will be the code that is actually calling your wrapper.
In your case, your logger would look something like this:
要跳过几帧并深入了解包装器调用者上下文,请在 App.config 中设置,或在程序中设置著名的修饰符:
示例:
请参阅此页面了解
${callsite:skipFrames=Integer}
以及
${callsite- 的此页面 linenumber:skipFrames=Integer}
我建议您在包装器中使用此格式:
此设置的输出如下:
To skip few frames and dive into wrapper callers context, set up in the App.config, or in program the famous modifier:
Examples:
See this page for
${callsite:skipFrames=Integer}
and this page for
${callsite-linenumber:skipFrames=Integer}
I recommend you to use this format in your wrapper:
The output from this setting will be as follows:
来源:http://slf.codeplex.com/discussions/210075
我使用了上面发布的代码只需提取调用方法名称并将其作为“消息”参数的一部分传递给布局。这让我可以将调用日志包装器的原始方法名称写入日志文件(而不是日志包装器的类名)。
Source : http://slf.codeplex.com/discussions/210075
I used the posted code above to simply extract the calling method name and pass that as part of the "message" parameter to the layout. This lets me have the original method name where the log wrapper was called be written to the log file (rather than the log wrapper's class name).
我已经和这个问题作斗争有一段时间了。
真正重要的是日志文件中的调用站点(FullyQualified Namespace)。
首先,我尝试从 Stacktrace 中获取正确的记录器:
但遗憾的是,MEF 的 Stacktrace 非常长,我无法清楚地识别 ILogger 请求者的正确调用者。
因此,我没有通过构造函数注入注入 ILogger 接口,而是创建了一个 ILogFactory 接口,它可以通过构造函数注入注入,然后调用工厂上的 Create 方法
并实现它:
使用 ILogger:
和实现:
使用它...只需注入 ILogFactory 并在 Mefed 导入构造函数中调用 Create 方法:
希望这有帮助
I have been fighting with this problem a while now.
Really improtant was the Callsite (FullyQualified Namespace) within the logfiles.
First, i tryed to get the right logger out of the Stacktrace:
But sadly, the Stacktrace with MEF is very long and i cannot clearly identify the correct caller for the Requester of the ILogger.
So, instead of injecting the ILogger Interface via Constructor Injection, i have created a ILogFactory Interface, that can get injected via Constructor Injection and call then the Create Method on the Factory
And implemented it:
With the ILogger:
and Implementation of:
To use it... just inject the ILogFactory and calle the Create Method in a Mefed Importing Constructor:
hope this helps
如今,修复调用点的更简单方法是使用 LogManager.AddHiddenAssembly(Assembly)
例如,
这将修复调用点,无需进行手动堆栈遍历等。
Nowadays a more simple approach to fix the callsite, is to use
LogManager.AddHiddenAssembly(Assembly)
e.g.
This will fix the callsite and no need to do manual stack walking etc.
或者,您可以避免设置 NLog 的本机解决方案,并检索文件 |方法|包装器代码中的行信息:
然后您只需调用静态方法并在消息之前添加调用点:
Alternatively, you can avoid native solution from NLog set up, and retrieve the file | method | line info in your wrappers code:
Then you just call your static methods and add callsite before message:
伙计们
经过几天的努力和搜索,最后,我只使用一个简单的类构建了 Nlog Wrapper,它可以保留 ${callsite} 并在创建 Nlog Wrapper 实例时获取正确的记录器名称。我将把代码如下,并附上简单的注释。如您所见,我使用 Stacktrace 来获取正确的记录器名称。使用 write 和 writewithex 注册 logevnet,以便保留调用点。
Guys
After several days hard work and search.Finally, I just use one simple class built the Nlog Wrapper which can retain the ${callsite} and get the correct logger name when created the instance of Nlog Wrapper. I will put the code as followed with simple comment. As you can see I use Stacktrace to get the right logger name. Use write and writewithex to register the logevnet so that can retain callsite.
有一个简单的方法可以实现这一点。只需将这些属性添加到日志包装器方法签名中:
并将它们传递给包装的 NLog 方法。
请参阅 https://learn.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.callerfilepathattribute?view=netframework-4.7.2 有关 System.Runtime.CompilerServices 属性的详细信息在.NET中。
There is an easy way to achieve this. Just add these attributes to your log wrapper method signatures:
and pass these to the wrapped NLog methods.
See https://learn.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.callerfilepathattribute?view=netframework-4.7.2 for more info on System.Runtime.CompilerServices attibutes in .NET.