我有一个服务将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>
答案 0 :(得分:2)
我不知道是否有更自动的方式让每个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的博客文章:
答案 1 :(得分:1)
我只是做了一些非常相似的事情,我发现每个子AppDomain中的静态成员NLog.LogManager.Configuration开始具有与父AppDomain中该成员相同的值。我不确定它是否结束了重新读取app.config中的值,或者是否直接从父AppDomain复制静态成员。
此外,我最终使用CallContext过滤所有符合特定条件的日志消息(无论记录器名称)(例如,导致程序运行的激励请求ID),并将它们分组到内存中的日志目标。