跨 AppDomains 的 NLog 配置

Posted

技术标签:

【中文标题】跨 AppDomains 的 NLog 配置【英文标题】:NLog configuration across AppDomains 【发布时间】:2011-03-17 23:00:55 【问题描述】:

我有一个将 dll 加载到单独的 appdomain 的服务(需要 appdomain,因为 dll 正在加载动态生成的程序集并且需要能够卸载它们)

如何复制 nlog 配置,以便新的 appdomain 使用相同的设置?

另一个复杂之处是我在程序开始时使用 GlobalDiagnosticsContext 设置日志记录参数。除了必须在每个 appdomain 中重新设置它们之外,还有其他选择吗?

static void Main()

    // Setup NLog variables
    GlobalDiagnosticsContext.Set("ConnectionString", @"...");
    GlobalDiagnosticsContext.Set("ApplicationName", @"appName");

    // ... loads appdomain and does logging from the new appdomain

这是我的配置文件:

<?xml version="1.0" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

  <variable name="TextErrorLayout" value ="$gdc:item=ApplicationName $date:format=yyyy-MM-dd HH\:mm\:ss.fff$newline
Level: $level$newline
Description: $message$newline
Machine: $machinename$newline
User: $windows-identity$newline
Process: $processname$newline
WorkingDir: $basedir$newline
Exception: $exception:format=tostring$newline
DetailedMessage: $event-context:item=Details$newline"/>

  <targets async="true">
    <target name="LogMill" xsi:type="FallbackGroup">
      <target xsi:type="Database"
              connectionString="$gdc:item=ConnectionString"
              commandText="exec dbo.Usp_Log_CreateWithExtended @applicationName, @logLevel, @entryDate, @description, @machineName, @userName, @assembly, @workingDirectory, @exception, @detailedMessage">
        <dbProvider>mssql</dbProvider>
        <parameter name="@applicationName" layout="$gdc:item=ApplicationName"/>
        <parameter name="@logLevel" layout="$level"/>
        <parameter name="@entryDate" layout="$date:format=yyyy-MM-dd HH\:mm\:ss.fff"/>
        <parameter name="@description" layout="$message"/>
        <parameter name="@machineName" layout="$machinename"/>
        <parameter name="@userName" layout="$windows-identity"/>
        <parameter name="@assembly" layout="$processname"/>
        <parameter name="@workingDirectory" layout="$basedir"/>
        <parameter name="@exception" layout="$exception:format=tostring"/>
        <parameter name="@detailedMessage" layout="$event-context:item=Details"/>
      </target>
      <target xsi:type="File" fileName="LogMill-FailSafe.log" layout="$TextErrorLayout"/>
    </target>

    <target name="EmailDevelopers" xsi:type="Mail"
            smtpServer="smtp.local"
            from="errors@email.com"
            to="email@email.com"
            subject="$gdc:item=ApplicationName $level Error: $message"
            layout="$TextErrorLayout"/>

    <target name="Console" xsi:type="ColoredConsole" layout="$date:format=yyyy-MM-dd HH\:mm\:ss.fff $message $exception:format=tostring"/>
  </targets>

  <rules>
    <logger name="*" minlevel="Info" writeTo="LogMill" />
    <logger name="*" minlevel="Error" writeTo="EmailDevelopers" />
  </rules>
</nlog>

【问题讨论】:

【参考方案1】:

我不知道是否有更自动的方法让每个 AppDomain 使用相同的配置信息,但您也许可以使用这篇文章中的技术:

Most useful NLog configurations

通过 XML 以编程方式设置配置。对于您加载的每个 AppDomain,您可以读取 NLog 配置文件,然后在新 AppDomain 中的 NLog 上设置 XML。

将全局值添加到新 AppDomain 的一种可能解决方案是使用 CallContext.LogicalSetData 存储它们。这些值将流向新的 AppDomain。编写自定义 LayoutRenderer 以使用 CallContext.LogicalGetData 获取值。 LayoutRenderer 很容易编写。

有关如何编写自定义 LayoutRenderer 以查找基于键的值(就像 GDC 一样)的示例,请参阅这篇文章。对于内部,只需使用 CallContext.LogicalGetData 来检索值:

Custom log4net property PatternLayoutConverter (with index)

请参阅 Jeffrey Richter 的这篇关于使用 CallContext 的博文:

http://www.wintellect.com/CS/blogs/jeffreyr/archive/2010/09/27/logical-call-context-flowing-data-across-threads-appdomains-and-processes.aspx

【讨论】:

谢谢!我之前没听说过 CallContext【参考方案2】:

我刚刚做了一些非常相似的事情,我发现每个子 AppDomain 中的静态成员 NLog.LogManager.Configuration 开始时与父 AppDomain 中的成员具有相同的值。我不确定它是否结束从 app.config 重新读取值,或者如果静态成员直接从父 AppDomain 复制。

此外,我最终使用 CallContext 过滤所有符合特定条件(例如,导致程序运行的激励请求 ID)的日志消息(无论记录器名称如何),并将它们分组到内存中的日志目标.

【讨论】:

以上是关于跨 AppDomains 的 NLog 配置的主要内容,如果未能解决你的问题,请参考以下文章

插件 AppDomains 解决方法

AppDomains之间如何最好地进行通信?

跨 AppDomain 的自定义序列化

NLog 无法读取 .NET Core 2.2 控制台应用程序中的 app.config configSection

几个appdomains调用相同的非托管DLL

C# 使用NLog记录日志