根据 NLog 文档:
大多数应用程序将使用每个类一个记录器,其中记录器的名称与类的名称相同。
这与 log4net 的操作方式相同。为什么这是一个好的实践?
使用log4net时,每个类使用一个记录器可以轻松地捕获日志消息的来源(即写入日志的类)。如果您没有为每个类使用一个记录器,而是为整个应用程序使用一个记录器,则需要使用更多反射技巧来知道日志消息来自何处。
以下是对比:
using System.Reflection;
private static readonly ILog _logger =
LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
public void SomeMethod()
{
_logger.DebugFormat("File not found: {0}", _filename);
}
Logger.DebugFormat("File not found: {0}", _filename); // Logger determines caller
-- or --
Logger.DebugFormat(this, "File not found: {0}", _filename); // Pass in the caller
使用第二个示例,Logger需要构建堆栈跟踪才能看到谁在调用它,或者您的代码必须始终传入调用方。使用每个类一个Logger的风格,您仍然可以这样做,但是您可以每个类只做一次而不是每次调用都要做,并消除严重的性能问题。
<logger name="A.NameSpace.MyClass" minlevel="Debug" writeTo="ImportantLogs" />
<logger name="A.NameSpace.MyOtherClass" minlevel="Trace" writeTo="ImportantLogs" />
<logger name="StupidLibrary.*" minlevel="Error" writeTo="StupidLibraryLogs" />
<!-- Hide other messages from StupidLibrary -->
<logger name="StupidLibrary.*" final="true" />
<!-- Log all but hidden messages -->
<logger name="*" writeTo="AllLogs" />
NLogger有一个非常有用的代码片段可以完成此操作。 nlogger
代码片段将创建以下代码:
private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
只需少量按键,您就可以为每个类创建一个日志记录器。它将使用命名空间和类名作为日志记录器的名称。要为您的类记录器设置不同的名称,您可以使用以下代码:
private static NLog.Logger logger = NLog.LogManager.GetLogger("MyLib.MyName");
正如@JeremyWiebe所说,你不必使用技巧来获取试图记录消息的类的名称:可以通过在布局中使用${logger}
轻松地将记录器的名称(通常是类的名称)记录到文件(或其他目标)中。
NLog 在性能方面也有优势。大多数用户都会使用
Logger logger = LogManager.GetCurrentClassLogger()
在大多数情况下,类的名称为记录器提供了一个很好的名称。扫描日志文件时,您可以看到日志消息并将其直接与代码行关联起来。
一个不太适合使用这种方法的好例子是Hibernate的SQL日志。有一个名为“Hibernate.SQL”或类似名称的共享记录器,许多不同的类将原始SQL写入单个记录器类别。
从开发角度来看,如果您不必每次创建日志记录器对象,则最容易。另一方面,如果您使用反射动态创建它,将会降低性能。为了解决这个问题,您可以使用以下代码异步动态创建日志记录器:
using NLog;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WinForms
{
class log
{
public static async void Log(int severity, string message)
{
await Task.Run(() => LogIt(severity, message));
}
private static void LogIt(int severity, string message)
{
StackTrace st = new StackTrace();
StackFrame x = st.GetFrame(2); //the third one goes back to the original caller
Type t = x.GetMethod().DeclaringType;
Logger theLogger = LogManager.GetLogger(t.FullName);
//https://github.com/NLog/NLog/wiki/Log-levels
string[] levels = { "Off", "Trace", "Debug", "Info", "Warn", "Error", "Fatal" };
int level = Math.Min(levels.Length, severity);
theLogger.Log(LogLevel.FromOrdinal(level), message);
}
}
}
我立刻想到了两个原因:
可能是因为您希望能够记录仅对类可见的方法,而不会破坏封装性,这也使得在另一个应用程序中使用该类变得更加容易,而不会破坏日志记录功能。
通过命名空间或类轻松配置附加器。
<property name="CallSite" value="${callsite}" />