로거 래퍼 모범 사례
내 응용 프로그램에서 nlogger를 사용하고 싶습니다. 나중에 로깅 시스템을 변경해야 할 수도 있습니다. 그래서 저는 로깅 파사드를 사용하고 싶습니다.
기존 예제를 작성하는 방법에 대한 권장 사항을 알고 있습니까? 또는이 분야의 모범 사례에 대한 링크를 제공하십시오.
저는 Common.Logging 과 같은 로깅 파사드를 사용 했지만 (내 자신의 CuttingEdge.Logging 라이브러리 를 숨기는 경우에도 ) 요즘에는 Dependency Injection 패턴을 사용 하며이를 통해 두 종속성 을 모두 준수하는 내 자신의 (간단한) 추상화 뒤에 로거를 숨길 수 있습니다. 반전 원리 와 인터페이스 분리 원리(ISP) 멤버가 하나 있고 인터페이스가 내 애플리케이션에 의해 정의되기 때문입니다. 외부 라이브러리가 아닙니다. 애플리케이션의 핵심 부분이 외부 라이브러리의 존재에 대한 지식을 최소화하는 것이 좋습니다. 로깅 라이브러리를 교체 할 의도가없는 경우에도 마찬가지입니다. 외부 라이브러리에 대한 강한 종속성은 코드를 테스트하기 어렵게 만들고 애플리케이션을 위해 특별히 설계되지 않은 API로 애플리케이션을 복잡하게 만듭니다.
이것은 내 응용 프로그램에서 종종 추상화가 보이는 것입니다.
public interface ILogger
{
void Log(LogEntry entry);
}
public enum LoggingEventType { Debug, Information, Warning, Error, Fatal };
// Immutable DTO that contains the log information.
public class LogEntry
{
public readonly LoggingEventType Severity;
public readonly string Message;
public readonly Exception Exception;
public LogEntry(LoggingEventType severity, string message, Exception exception = null)
{
if (message == null) throw new ArgumentNullException("message");
if (message == string.Empty) throw new ArgumentException("empty", "message");
this.Severity = severity;
this.Message = message;
this.Exception = exception;
}
}
선택적으로이 추상화는 몇 가지 간단한 확장 방법으로 확장 될 수 있습니다 (인터페이스가 좁아지고 ISP를 계속 준수하도록 허용). 이렇게하면이 인터페이스의 소비자를위한 코드가 훨씬 간단 해집니다.
public static class LoggerExtensions
{
public static void Log(this ILogger logger, string message) {
logger.Log(new LogEntry(LoggingEventType.Information, message));
}
public static void Log(this ILogger logger, Exception exception) {
logger.Log(new LogEntry(LoggingEventType.Error, exception.Message, exception));
}
// More methods here.
}
인터페이스는 단지 하나의 방법을 포함하기 때문에, 당신은 쉽게 만들 수 있습니다 ILogger
구현하는 log4net에 프록시 , Serilog에 , Microsoft.Extensions.Logging , NLog 또는 다른 로깅 라이브러리를하고이 클래스에 주입하기 위해 DI 컨테이너를 구성 ILogger
에서 자신의 건설자.
Do note that having static extension methods on top of an interface with a single method is quite different from having an interface with many members. The extension methods are just helper methods that create a LogEntry
message and pass it through the only method on the ILogger
interface. The extension methods become part of the consumer's code; not part of the abstraction. Not only does this allow the extension methods to evolve without the need to change the abstraction, the extension methods and the LogEntry
constructor are always executed when the logger abstraction is used, even when that logger is stubbed/mocked. This gives more certainty about the correctness of calls to the logger when running in a test suite. The one-membered interface makes testing much easier as well; Having an abstraction with many members makes it hard to create implementations (such as mocks, adapters and decorators).
When you do this, there is hardly ever any need for some static abstraction that logging facades (or any other library) might offer.
I used the small interface wrapper + adapter from https://github.com/uhaciogullari/NLog.Interface that is also available via NuGet:
PM> Install-Package NLog.Interface
Generally I prefer to create an interface like
public interface ILogger
{
void LogInformation(string msg);
void LogError(string error);
}
and in the runtime i inject a concrete class that is implemented from this interface.
A great solution to this problem has emerged in the form of the LibLog project.
LibLog is a logging abstraction with built-in support for major loggers including Serilog, NLog, Log4net and Enterprise logger. It is installed via the NuGet package manager into a target library as a source (.cs) file instead of a .dll reference. That approach allows the logging abstraction to be included without forcing the library to take on an external dependency. It also allows a library author to include logging without forcing the consuming application to explicitly provide a logger to the library. LibLog uses reflection to figure out what concrete logger is in use and hook up to it up without any explicit wiring code in the library project(s).
So, LibLog is a great solution for logging within library projects. Just reference and configure a concrete logger (Serilog for the win) in your main application or service and add LibLog to your libraries!
Instead of writing your own facade, you could either use Castle Logging Services or Simple Logging Façade.
Both include adapters for NLog and Log4net.
As of now, the best bet is to use the Microsoft.Extensions.Logging package (as pointed out by Julian). Most logging framework can be used with this.
Defining your own interface, as explained in Steven's answer is OK for simple cases, but it misses a few things that I consider important:
- Structured logging and de-structuring objects (the @ notation in Serilog and NLog)
- Delayed string construction/formatting: as it takes a string, it has to evaluate/format everything when called, even if in the end the event will not be logged because it's below the threshold (performance cost, see previous point)
- Conditional checks like
IsEnabled(LogLevel)
which you might want, for performances reasons once again
You can probably implement all this in your own abstraction, but at that point you'll be reinventing the wheel.
Since 2015 you could also use .NET Core Logging if you're building .NET core applications.
The package for NLog to hook into is:
- NLog.Web.AspNetCore for ASP.NET Core users
- NLog.Extensions.Logging for .NET Core users, e.g. console projects
참고URL : https://stackoverflow.com/questions/5646820/logger-wrapper-best-practice
'developer tip' 카테고리의 다른 글
정적 클래스 내에서 사전 선언 (0) | 2020.09.13 |
---|---|
Div 오버레이를 전체 페이지 (뷰포트뿐만 아니라)로 만드시겠습니까? (0) | 2020.09.13 |
컴퓨터가 죽은 후 Git 저장소가 손상됨 (0) | 2020.09.13 |
Visual Studio Community Edition 2015 및 2017에서 누락 된 CodeLens 참조 수 (0) | 2020.09.13 |
C에서 16 진수 문자 인쇄 (0) | 2020.09.13 |