使用NLog与MEF的最佳方式是什么? [英] What is the best way of using NLog with MEF?

查看:181
本文介绍了使用NLog与MEF的最佳方式是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想知道使用NLog与Managed Extensibility Framework(MEF)的最佳方式是什么?



我有一个应用程序,支持使用MEF架构的插件(导入和导出等)
我想为我的应用程序添加日志功能。
作为日志记录组件,我想使用NLog。



你会推荐什么?
1.为NLog创建一个包装器,即配置NLog的其他插件,并导出其他插件导入
的void Log(字符串级别,字符串消息)等函数。每个插件都应该有它自己的实例NLog配置和使用。 (他们都会写入同一个文件)

解决方案

这是一个有趣的方法,但是,似乎遭受所注入的所有记录器(或注入的一个单体)将是相同的实例(或将具有相同的名称,名称作为NLogLoggingService类的名称)的缺点,这意味着您不能非常轻松地控制粒度的日志记录(即在一个类别中将日志记录转换为信息级别,在另一个类中记录警告)。另外,如果您选择使用呼叫站点格式化令牌,您将始终收到呼叫的呼叫站点NLog记录器而不是您的应用程序代码中的通话网站。



以下是链接的记录器的缩写版本:

  [Export(Services.Logging.LoggingService,typeof(ILoggingService))] 
class NLogLoggingService:ILoggingService
{
Logger log; public NLogLoggingService
{
log = LogManager.GetCurrentClassLogger();
}

public void调试(对象消息)
{
log.Debug(message);
}
public void DebugWithFormat(string format,params object [] args)
{
if(args.Length == 0)
{
log的.debug(格式);
}
else
{
调试(string.Format(format,args));
}
}
public bool IsDebugEnabled
{
get
{
return log.IsDebugEnabled;
}
}
}

在构造函数 LogManager.GetCurrentClassLogger()用于获取NLog记录器。 GetCurrentClassLogger将根据当前类型返回一个名为named的NLog记录器,在这种情况下,它是NLogLoggingService。因此,要在app.config文件中配置NLog,您将根据记录器命名为SoapBox.Core.NLogLoggingService进行配置。通常,在直接使用NLog(或log4net)的代码中,每个类都会获得自己的唯一命名的记录器,如下所示:

 命名空间MyNamespace 
{
public class MyClass1
{
private static readonly Logger logger LogManager.GetCurrentClassLogger();

public void DoSomeWork()
{
logger.Info(从MyClass1.DoSomeWork内记录);
}
}

public class MyClass2
{
private static readonly Logger logger LogManager.GetCurrentClassLogger();

public void DoSomeWork()
{
logger.Info(从MyClass2.DoSomeWork里面记录);
}
}
}

现在MyClass1和MyClass2可以单独控制。您可以为每个类配置不同的级别,将它们发送到不同的目标,或者完全关闭一个或两个。或者,由于Log4net和NLog中的Logger层次结构的概念,您可以通过为名称空间(在本例中为MyNamespace)或任何祖先命名空间配置logger来同时控制两个日志记录。如果没有为完全限定类型名称配置记录器,则记录框架通过考虑名称以点划分的字符串的形式向上移动,并删除最后一个块,并检查该记录器是否已配置。所以在这种情况下,我们正在为MyNamespace.MyClass1和MyNamespace.MyClass2请求记录器。我可以配置app.config文件,让MyNamespace记录在info,并写入文件目标(app4net-talk中的appender)。如果我这样做,那么我通过完全限定名称请求的两个记录器都将继承MyNamespace配置。



通过MEF注入NLog的建议方法,有一个记录器实例,所以您不能配置每个类以不同的日志记录。另外,正如我前面提到的,如果您选择记录调用站点信息,那么您将始终为该方法获取SoapBox.Core.NLogLoggingService和Debug(或DebugWithFormat,Info或InfoWithFormat等)。



这似乎是从log4net和NLog成功注入记录器的一个问题。几个月前我可以看到有关这个问题的问题



最终我能够弄清楚一些依赖注入框架如何成功地注入特定于正在创建的类的log4net和NLog记录器(即如果DI框架正在实例化MyClass依赖于ILogger接口,然后MyClass将获得一个本质上相当于MyClass通过LogManager.GetCurrentClassLogger api请求记录器本身的事情的记录器。 DI / IoC框架中的解析器通常被赋予当前上下文(包含当前正在创建的对象的其他信息)。有了这种类型,就可以使一个日志框架特定的解析器接收到该类型并将其传递给日志框架,以创建适合该类型的记录器。



为了充分利用NLog(和log4net的)功能,您最好能够告诉MEF您的类依赖于ILogger,而且还将ILogger的实例注入你的班级应该取决于你的班级的类型。



我不知道用MEF来实现这一点是多么容易。或者,您可以将NLog的静态LogManager包装在ILogManager中并注入。这将偏离正常的注入ILogger范例。



总结:如果您以这种方式通过MEF注入NLog,您将能够使用NLog登录,但是你只会有一个命名记录器(SoapBox.Core.NLogLoggingService)。这意味着您无法以任何程度的粒度控制 - 无论是级别/开/关或输出(NLog Target / log4net Appender)



我不对于通过MEF注入NLog,并保持原始NLog给您的粒度/灵活性,对于要做的工作有一个很好的答案。



我可以说,我们已决定使用 Common.Logging for .NET 来抽象日志框架,但我们决定不注入日志记录。相反,我们只需使用静态LogManager(由Common.Logging提供)来发出记录器。


I am wondering what is the best way to use NLog with Managed Extensibility Framework (MEF)?

I have an application that support plugins using MEF architecture (Import and Exports etc) I want to add logging capability to my application. As a logging component I want to use NLog.

What would you recommend? 1. Create a wrapper for NLog, i.e. additional plugin that configures NLog and exports functions like void Log(string level, string message) that other plugins importing 2. Every plugin should have it is own instance of NLog configured and used. (They all would write to the same file actually).

解决方案

This is an interesting approach, however, it seems to suffer from the drawback that all loggers that are injected (or the one singleton that is injected) will be the same instance (or will have the same name, the name being the name of the NLogLoggingService class. That means that you cannot very easily control the granularity of logging (i.e. turn logging to "Info" level in one class and "Warn" in another class). Also, if you opt to use the call site formatting tokens, you will always get the call site of the call the the NLog logger rather than the call site in your application code.

Here is an abbreviated version of the logger that was linked:

  [Export(Services.Logging.LoggingService, typeof(ILoggingService))] 
  class NLogLoggingService : ILoggingService 
  { 
    Logger log; public NLogLoggingService() 
    { 
      log = LogManager.GetCurrentClassLogger(); 
    } 

    public void Debug(object message) 
    {
      log.Debug(message); 
    }
    public void DebugWithFormat(string format, params object[] args) 
    { 
      if (args.Length == 0) 
      { 
        log.Debug(format); 
      } 
      else
      { 
        Debug(string.Format(format, args)); 
      }
    } 
    public bool IsDebugEnabled 
    { 
      get 
      { 
        return log.IsDebugEnabled; 
      } 
    } 
  }

In the constructor LogManager.GetCurrentClassLogger() is used to get the NLog logger. GetCurrentClassLogger will return a NLog logger that is "named" based on the "current" type, which, in this case, is NLogLoggingService. So, to configure NLog in the app.config file, you will configure based on the that the logger is named "SoapBox.Core.NLogLoggingService". Commonly, in code that uses NLog (or log4net) directly, each class gets its own uniquely named logger like this:

namespace MyNamespace
{
  public class MyClass1
  {
    private static readonly Logger logger LogManager.GetCurrentClassLogger();

    public void DoSomeWork()
    {
      logger.Info("Logging from inside MyClass1.DoSomeWork");
    }
  }

  public class MyClass2
  {
    private static readonly Logger logger LogManager.GetCurrentClassLogger();

    public void DoSomeWork()
    {
      logger.Info("Logging from inside MyClass2.DoSomeWork");
    }
  }
}

Now the logging for MyClass1 and MyClass2 is individually controllable. You can configure different levels for each class, send them to different targets, or turn one or both off altogether. Alternatively, due to the concept of logger hierarchies in both log4net and NLog, you could control the logging in both class simultaneously by configuring a "logger" for the namespace (MyNamespace in this case), or any "ancestor" namespace. If there is not a logger configured for the fully qualified typename, then the logging framework essentially moves up the hierarchy by considering the name a dot delimited string and removing the last chunk and checking to see if that logger is configured. So, in this case, we are requesting loggers for MyNamespace.MyClass1 and MyNamespace.MyClass2. I could configure the app.config file to have MyNamespace log at the "info" and write to a file target (appender in log4net-speak). If I did that, then both loggers that I requested via their fully qualified names would inherit the MyNamespace configuration.

With the suggested way of injecting NLog via MEF, you will only have one logger instance, so you cannot configure each class to log differently. Also, as I mentioned earlier, if you opt to log call site information, you will always get "SoapBox.Core.NLogLoggingService" for the class and "Debug" (or DebugWithFormat, or Info, or InfoWithFormat, etc) for the method.

This seems to be an issue with successfully injecting loggers from log4net and NLog. You can see the question that I asked about this very issue a couple of months ago.

Ultimately I was able to figure out how some dependency injection frameworks can successfully inject log4net and NLog loggers that are specific to the class being created (i.e. if the DI framework is instantiating MyClass, which in turn depends on an ILogger interface, then MyClass will get a logger that is essentially equivalent to what would have happened if MyClass requested the logger itself via the LogManager.GetCurrentClassLogger api). Generally "resolvers" in DI/IoC frameworks are given the current context (containing, among other information, the type of the object currently being created). With that type available, it becomes a simple matter of having a logging framework-specific resolver receive that type and pass it along to the logging framework to create a logger appropriate for that type.

In order to get the most out of NLog's (and log4net's) capabilities you would really like to be able to tell MEF that your class is dependendent on "ILogger", but also that the instance of "ILogger" that gets injected into your class should depend on the Type of your class.

I don't know how easy it will be to achieve that with MEF. Alternatively, you could wrap NLog's static LogManager in a ILogManager and inject that. That would deviate from the normal "inject ILogger" paradigm.

To summarize: If you inject NLog via MEF this way, you will indeed be able to log with NLog, but you will only ever have one named logger (SoapBox.Core.NLogLoggingService). This means that you will not be able control with any degree of granularity - either for levels/on/off or for output (NLog Target/log4net Appender)

I don't have a good answer for what to do as far as injecting NLog via MEF AND keeping the granularity/flexibility that "raw" NLog gives you.

I can say that we have decided to use Common.Logging for .NET to abstract the logging framework but we decided NOT to inject logging. Instead, we will just use a static LogManager (as provided by Common.Logging) to hand out loggers.

这篇关于使用NLog与MEF的最佳方式是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆