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-per-class 스타일을 사용하면 여전히이 작업을 수행하지만 호출 당 한 번이 아니라 클래스 당 한 번 수행 할 수 있으며 심각한 성능 문제를 제거 할 수 있습니다.
NLog에서 "파일 당 로거"사용의 장점 : 네임 스페이스 및 클래스 이름별로 로그를 관리 / 필터링 할 수 있습니다. 예:
<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}
레이아웃에서 사용 합니다.
개발 관점에서 매번 로거 객체를 만들 필요가없는 것이 가장 쉽습니다. 반면에 그렇지 않고 리플렉션을 사용하여 동적으로 생성하면 성능이 저하됩니다. 이를 해결하려면 로거를 동적으로 비동기식으로 생성하는 다음 코드를 사용할 수 있습니다.
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);
}
}
}
두 가지 이유가 즉시 떠 오릅니다.
아마도 캡슐화를 중단하지 않고 클래스에만 표시되는 메서드를 로깅 할 수 있기를 원하기 때문에 로깅 기능을 중단하지 않고 다른 애플리케이션에서 클래스를 쉽게 사용할 수 있습니다.
NLOG를 사용하는 경우 구성에서 호출 사이트를 지정할 수 있습니다. 그러면 로깅 문이있는 클래스 이름과 메서드가 기록됩니다.
<property name="CallSite" value="${callsite}" />
그런 다음 로거 이름 또는 어셈블리 이름에 상수를 사용할 수 있습니다.
면책 조항 : NLOG가이 정보를 수집하는 방법을 모르겠습니다. 제 추측은 반영 일 것이므로 성능을 고려해야 할 수도 있습니다. NLOG v4.4 이상을 사용하지 않는 경우 Async 메서드에 몇 가지 문제가 있습니다.