从 Outlook 加载项调用时,NLog 不写入日志文件

NLog does not write to log file when called from Outlook Add-in

我有一个用于 Outlook 的 C# 加载项 (Add-In Express),我试图从中存储一些日志数据,但即使对记录器的调用没有失败,也没有创建日志文件。我在 Win 10 环境中使用 VS 2013。

我的NLog.Config文件(保存在文件夹OutlookAddin\bin\Debug,与OutlookAddIn.dll.config相同的位置)如下:

<?xml version="1.0" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<targets>
    <target name="file" xsi:type="File"
        layout="${longdate} ${logger} ${message}" 
        fileName="${specialfolder:ApplicationData}\FindAlike\NewMails.txt"
        keepFileOpen="false"
        encoding="iso-8859-2" />
</targets>

<rules>
    <logger name="*"  writeTo="file" />
</rules>

加载项中的代码是声明:

public AddinModule()
    {
        Application.EnableVisualStyles();
        InitializeComponent();
        // Please add any initialization code to the AddinInitialize event handler
    }

    private ADXOutlookAppEvents adxOutlookEvents;
    private DateTime LastReceivedDate = DateTime.Now;
    private Timer mailCheckTimer;
    public static RegistryKey SoftwareKey = Registry.CurrentUser.OpenSubKey("Software", true);
    public static RegistryKey AppNameKey = SoftwareKey.CreateSubKey("FindAlike");
    public static Logger logger = LogManager.GetCurrentClassLogger();

测试日志文件写入的例程是:

public static void TestNLog()
    {
        try
        {
            NLog.LogManager.ThrowExceptions = true;

            logger.Info("test1");
            logger.Warn("test2");
            logger.Error("test3");

            var fileTarget1 = (FileTarget)NLog.LogManager.Configuration.FindTargetByName("file");
            var logEventInfo = new LogEventInfo { TimeStamp = DateTime.Now };
            string fileName = fileTarget1.FileName.Render(logEventInfo);
            if (!System.IO.File.Exists(fileName))
                throw new Exception("Log file does not exist.");
        }
        catch (Exception Ex)
        {
            MessageBox.Show(Ex.Message);
        }
    }

调用TestNLog时,虽然目标文件正确,但出现日志文件不存在的Message,说明配置文件读取成功

当包含在可执行文件中时,相同的代码按预期工作。

另一个 Whosebug 问题 (How to use NLog for a DLL) 建议 NLog.config 需要放在与调用插件的可执行文件相同的目录中。这解决了问题。然而,这使得分发非常困难,因为 Outlook 可执行文件的位置会根据 Outlook 版本而有所不同,并且需要管理员权限才能将文件复制到其中。也许另一个记录器不需要这个。

感谢@Julian 的建议,以下代码以编程方式指定了 NLog 配置,并且 运行 从外接程序成功:

    using NLog;
    using NLog.Config;
    using NLog.Targets;
    using System.Xml;
...

public static Logger logger = LogManager.GetCurrentClassLogger();

....   
    public static void ConfigNLog()
            {

            string xml = @"
            <nlog xmlns=""http://www.nlog-project.org/schemas/NLog.xsd""
                xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"">
                <targets>
                    <target name=""file"" xsi:type=""File""
                            layout=""${longdate} ${logger} ${message}"" 
                            fileName=""${specialfolder:ApplicationData}\FindAlike\NewMails.txt""
                            keepFileOpen=""false""
                            encoding=""iso-8859-2"" />
                </targets>
                <rules>
                    <logger name=""*""  writeTo=""file"" />
                </rules>
            </nlog>";

            StringReader sr = new StringReader(xml);
            XmlReader xr = XmlReader.Create(sr);
            XmlLoggingConfiguration config = new XmlLoggingConfiguration(xr, null);
            NLog.LogManager.Configuration = config;
        }

除了@SimonKarvis 的回答,nlog.config 的位置可能很困难。这与单元测试相同。

我会推荐:

  1. 从 C# 创建配置,例如

     var target = new FileTarget
     {
           FileName = logfile,
           ReplaceFileContentsOnEachWrite = true,
           CreateDirs = createDirs
     };
     var config = new LoggingConfiguration();
    
     config.AddTarget("logfile", target);
    
     config.AddRuleForAllLevels(target);
    
     LogManager.Configuration = config;
    
  2. 或从字符串加载配置:

    string configXml = "<nlog>...<nlog>";
    XmlDocument doc = new XmlDocument();
    doc.LoadXml(configXml);
    var config = new XmlLoggingConfiguration(doc.DocumentElement, Environment.CurrentDirectory);
    LogManager.Configuration = config;
    
  3. 或者至少但不是最后,找到 nlog.config 和 "feed" 到 NLog 的正确路径。

    var pathToNlogConfig = "c:\..";
    var config = new XmlLoggingConfiguration(pathToNlogConfig);
    LogManager.Configuration = config;