2013-03-12 112 views
10

我的解决方案多个项目C#解决方案2012目前包含两个项目:设置在Visual Studio中使用NLOG在Visual Studio

  • DLL
  • WPF应用程序(这需要DLL的方法)

DLL和WPF应用程序都使用NLog进行日志记录。目前每个项目都包含NLog DLL本身。

这是我不明白:

  1. 似乎没有必要对我来说,包括每个项目的相同NLog DLL。然而
  2. 的DLL应在其他可重复使用的解决方案,即以某种方式NLog DLL必须包含在DLL项目。

什么是设置Visual Studio解决方案和/或项目的适当方式?

+1

让它像现在这样,我会说。每个想要使用它的程序集只有一个DLL副本。如果使用该DLL的可执行程序集引用(说)两个其他类库程序集也使用该DLL,那么您将*只*得到可执行程序集的输出文件夹中的一个DLL。 – 2013-03-12 08:45:06

回答

9

以及你需要在你使用它,你一定需要它部署的可执行文件(在你的情况WPF应用程序)的二进制文件,以便它可以被发现并在运行时使用的所有项目的DLL。

我在我的所有项目中倾向于做的事情是在日志引擎周围创建一个包装,这样我就不需要引用和依赖特定的第三方日志API,如Log4Net或NLog,所以我使用我的包装日志记录类无处不在,然后我只在包装类的项目和可执行项目中引用了日志组件,才能将程序集部署到bin文件夹。

希望这有助于;-)

1

你最好抽象使用日志记录机制。我在this blog post中描述过这个问题,它是关于log4net的,但是无论你使用什么框架都是一样的原理。在任何情况下,您都需要在使用它的每个项目中使用日志程序集,但通过抽象它可以很容易地将其替换为其他东西(例如测试时)。日志记录是基础设施,因此您可以将接口和具体实现放入基础架构项目中,并从您想要记录的项目中引用该接口和具体实现。

+0

这很好,我同意,但如果DI无法实施,该怎么办?我想在整个解决方案中将多个项目中的日志记录分开并引用。 – JoshYates1980 2016-02-19 17:09:01

7

如果您的DLL只是您计划在各种项目之间共享的核心库,那么可以明智地将NLog引用和包装代码添加到该库中,然后确保任何使用者应用程序(例如您的WPF项目)有一个与之关联的NLog.config文件。

由于您使用的是VS2012,我假设您也很可能使用.NET 4.5,它可以让您利用新的调用者信息属性。我已经为基本的NLog包装器编写了下面的代码,并相信它具有效率(不使用StackTrace)和可用性的完美平衡。

using System; 
using System.Runtime.CompilerServices; 
using NLog; 

namespace ProjectName.Core.Utilities 
{ 
    /// <summary> 
    /// Generic NLog wrapper. 
    /// </summary> 
    public static class Logger 
    { 
     /// <summary> 
     /// Gets or sets the enabled status of the logger. 
     /// </summary> 
     public static bool Enabled 
     { 
      get { return LogManager.IsLoggingEnabled(); } 
      set 
      { 
       if (value) 
       {      
        while (!Enabled) LogManager.EnableLogging(); 
       } 
       else 
       { 
        while (Enabled) LogManager.DisableLogging(); 
       } 
      } 
     } 

     /// <summary> 
     /// Writes the diagnostic message at the Trace level. 
     /// </summary> 
     /// <param name="message"></param> 
     /// <param name="exception"></param> 
     /// <param name="callerPath"></param> 
     /// <param name="callerMember"></param> 
     /// <param name="callerLine"></param> 
     public static void Trace(string message, Exception exception = null, 
      [CallerFilePath] string callerPath = "", 
      [CallerMemberName] string callerMember = "", 
      [CallerLineNumber] int callerLine = 0) 
     { 
      Log(LogLevel.Trace, message, exception, callerPath, callerMember, callerLine); 
     } 

     /// <summary> 
     /// Writes the diagnostic message at the Debug level. 
     /// </summary> 
     /// <param name="message"></param> 
     /// <param name="exception"></param> 
     /// <param name="callerPath"></param> 
     /// <param name="callerMember"></param> 
     /// <param name="callerLine"></param> 
     public static void Debug(string message, Exception exception = null, 
      [CallerFilePathAttribute] string callerPath = "", 
      [CallerMemberName] string callerMember = "", 
      [CallerLineNumber] int callerLine = 0) 
     { 
      Log(LogLevel.Debug, message, exception, callerPath, callerMember, callerLine); 
     } 

     /// <summary> 
     /// Writes the diagnostic message at the Info level. 
     /// </summary> 
     /// <param name="message"></param> 
     /// <param name="exception"></param> 
     /// <param name="callerPath"></param> 
     /// <param name="callerMember"></param> 
     /// <param name="callerLine"></param> 
     public static void Info(string message, Exception exception = null, 
      [CallerFilePathAttribute] string callerPath = "", 
      [CallerMemberName] string callerMember = "", 
      [CallerLineNumber] int callerLine = 0) 
     { 
      Log(LogLevel.Info, message, exception, callerPath, callerMember, callerLine); 
     } 

     /// <summary> 
     /// Writes the diagnostic message at the Warn level. 
     /// </summary> 
     /// <param name="message"></param> 
     /// <param name="exception"></param> 
     /// <param name="callerPath"></param> 
     /// <param name="callerMember"></param> 
     /// <param name="callerLine"></param> 
     public static void Warn(string message, Exception exception = null, 
      [CallerFilePathAttribute] string callerPath = "", 
      [CallerMemberName] string callerMember = "", 
      [CallerLineNumber] int callerLine = 0) 
     { 
      Log(LogLevel.Warn, message, exception, callerPath, callerMember, callerLine); 
     } 

     /// <summary> 
     /// Writes the diagnostic message at the Error level. 
     /// </summary> 
     /// <param name="message"></param> 
     /// <param name="exception"></param> 
     /// <param name="callerPath"></param> 
     /// <param name="callerMember"></param> 
     /// <param name="callerLine"></param> 
     public static void Error(string message, Exception exception = null, 
      [CallerFilePathAttribute] string callerPath = "", 
      [CallerMemberName] string callerMember = "", 
      [CallerLineNumber] int callerLine = 0) 
     { 
      Log(LogLevel.Error, message, exception, callerPath, callerMember, callerLine); 
     } 

     /// <summary> 
     /// Writes the diagnostic message at the Fatal level. 
     /// </summary> 
     /// <param name="message"></param> 
     /// <param name="exception"></param> 
     /// <param name="callerPath"></param> 
     /// <param name="callerMember"></param> 
     /// <param name="callerLine"></param> 
     public static void Fatal(string message, Exception exception = null, 
      [CallerFilePathAttribute] string callerPath = "", 
      [CallerMemberName] string callerMember = "", 
      [CallerLineNumber] int callerLine = 0) 
     {    
      Log(LogLevel.Fatal, message, exception, callerPath, callerMember, callerLine); 
     } 

     /// <summary> 
     /// Writes the specified diagnostic message. 
     /// </summary> 
     /// <param name="level"></param> 
     /// <param name="message"></param> 
     /// <param name="exception"></param> 
     /// <param name="callerPath"></param> 
     /// <param name="callerMember"></param> 
     /// <param name="callerLine"></param> 
     private static void Log(LogLevel level, string message, Exception exception = null, string callerPath = "", string callerMember = "", int callerLine = 0) 
     { 
      // get the source-file-specific logger 
      var logger = LogManager.GetLogger(callerPath); 

      // quit processing any further if not enabled for the requested logging level 
      if (!logger.IsEnabled(level)) return; 

      // log the event with caller information bound to it 
      var logEvent = new LogEventInfo(level, callerPath, message) {Exception = exception}; 
      logEvent.Properties.Add("callerpath", callerPath); 
      logEvent.Properties.Add("callermember", callerMember); 
      logEvent.Properties.Add("callerline", callerLine); 
      logger.Log(logEvent); 
     } 
    } 
} 

然后尝试将其放入NLog.config中的其中一个目标的布局字段以获取详细的来电者信息。

${event-context:item=callerpath}:${event-context:item=callermember}(${event-context:item=callerline}) 
+0

如果您添加对“Microsoft BCL构建组件”的引用(通过NuGet),也可以以.net 4.0为目标 – Xilmiki 2014-07-16 07:57:18

+0

为什么Enabled的setter使用while循环来检查Enabled的当前状态?如果值为true,并且LogManager.DisableLogging()否则只需调用LogManager.EnableLogging()就足够了吗? – 2015-05-06 15:36:04

+1

刚刚发现有一个日志启用计数器,并且启用和禁用分别增加或减少该计数器。我发现命名有点混乱,希望别人从中学到东西。 – 2015-05-06 15:37:14