我有什么方法可以获取上下文,以便我可以检索loggerName
并使用LogManager.GetLogger(loggerName)
代替LogManager.GetCurrentClassLogger()
吗?
我注意到container.RegisterConditional()
可以访问上下文。
此外,我想暂时避免像SimpleLogging.NLog这样的解决方案。
最后,我愿意接受这不是正确的方法。顺便说一下,AOP是我已经探索过的一个选项(Is it a good practice to have logger as a singleton?)。
注意:我知道GetCurrentClassLogger()
获取了我使用.NET反射检索的相同信息。
using NLog;
using SimpleInjector;
namespace DependencyInjection
{
class Program
{
private static Container _container;
static void Main(string[] args)
{
Bootstrap();
_container.GetInstance<Greeter>().Greet();
}
private static void Bootstrap()
{
_container = new Container();
_container.Register<ILogger>(() => LogManager.GetCurrentClassLogger(), Lifestyle.Transient);
_container.Register<Greeter>();
_container.Verify();
}
public class Greeter
{
private ILogger _logger;
public Greeter(ILogger logger)
{
_logger = logger;
}
public void Greet()
{
_logger.Log(LogLevel.Info, "Hello world!");
}
}
}
}
答案 0 :(得分:13)
您需要定义一个代理记录器,将消息路由到正确的Nlog Logger。这个代理非常简单:
public class NLogProxy<T> : ILogger
{
private static readonly NLog.ILogger logger =
LogManager.GetLogger(typeof (T).FullName);
void ILogger.Log(string message)
{
logger.Log(LogLevel.Info, message);
}
}
您可以将此注册为
container.RegisterConditional(typeof(ILogger),
context => typeof(NLogProxy<>).MakeGenericType(context.Consumer.ImplementationType),
Lifestyle.Singleton, context => true);
您需要记录的所有地方都必须注入ILogger
。
至于AOP。我不确定你的意见是什么意思
必须维护的包装器(NLog.ILogger合同很大)。
记录为cross cutting concern,使用decorator是应用横切问题的好方法。使用装饰器,无法记录每个(私有)函数调用入口和出口,但为什么要这样?正如您可以阅读here,您可能不需要这样做。在大多数情况下,使用完整的堆栈跟踪记录服务被调用(传递给此服务的数据)和可能的异常的简单事实将是绰绰有余的。
所以考虑一下:
public interface ISomeService
{
void DoSomething(string someParameter);
}
public class SomeServiceDecorator : ISomeService
{
private readonly ISomeService decoratee;
private readonly ILogger logger;
public SomeServiceDecorator(ISomeService decoratee, ILogger logger)
{
this.decoratee = decoratee;
this.logger = logger;
}
public void DoSomething(string someParameter)
{
try
{
this.logger.Log(string.Format("Do something called with {0}", someParameter));
this.decoratee.DoSomething(someParameter);
}
catch (Exception e)
{
this.logger.Log(e.ToString());
throw;
}
}
}
此装饰器将使用传递给服务的信息记录所有函数调用,并记录任何异常。
但是这种方法会将类的数量增加2,所以不是DRY。引起此问题是因为此设计至少是次优的。围绕单个开放式通用抽象使用设计将完全解决此问题。您可以阅读此设计here和here。
在这种情况下,您将拥有一个“LoggingDecorator”
public class LoggingCommandHandlerDecorator<T> : ICommandHandler<T>
{
private readonly ICommandHandler<T> decoratee;
private readonly ILogger logger;
public LoggingCommandHandlerDecorator(ICommandHandler<T> decoratee, ILogger logger)
{
this.decoratee = decoratee;
this.logger = logger;
}
public void Handle(T command)
{
// serialize command to json and log
this.logger.Log(serializedcommandData);
this.decoratee.Handle(command);
}
}
这个装饰器会记录你的所有命令。
这是我对AOP的看法......