在运行时修改 app.config <system.diagnostics> 部分

Modify app.config <system.diagnostics> section at runtime

我需要在运行时修改 app.config<configuration><system.diagnostics> 部分,以便我可以:

  1. <sharedListeners>元素下增加一个CustomTraceListener,需要特殊的initializeData,只能在运行时确定。

  2. CustomTraceListener 共享侦听器添加到 <source><listeners> 元素下的现有源。

  3. CustomTraceListener 持久化到从配置文件加载其跟踪源和侦听器配置的其他程序集。

app.config 中的相关部分目前看起来像这样:

<system.diagnostics>
  <sources>
    <source name="mysource" switchName="..." switchType="...">
      <listeners>
        <add name="console" />
        <add name="customtracelistener" /> /// need to add new listener here
      </listeners>
    </source>
  </sources>
  <sharedListeners>  
    <add name="console" type="..." initializeData="..." />
    <add name="customtracelistener" type="..." initializeData="..."> /// need to add custom trace listener here 
      <filter type="..." initializeData="Warning"/> /// with a filter
    </add>
  </sharedListeners>
  <switches>
    <add name="..." value="..." />
  </switches>
</system.diagnostics>

使用ConfigurationManager我可以轻松做到:

Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
ConfigurationSection diagnostics = config.GetSection("system.diagnostics");

当我这样做时,diagnosticsSystem.Diagnostics.SystemDiagnosticsSection 类型。有趣的是,我无法将 diagnostics 转换为 SystemDiagnosticsSection 类型,因为我无法在任何命名空间中找到它。无论如何,ConfigurationSection 似乎没有任何方法可用于将数据写入该部分。

我也无法将其转换为 NameValueConfigurationCollection,因为 diagnostics 基本类型是 ConfigurationSection。听说过这个技巧,但是我好像不会用。

我是否必须恢复使用普通的 XML 才能完成此操作?我真的不喜欢重新发明轮子。

如果您直接更改 <configuration><system.diagnostics> 运行 时 app.config 文件的一部分,需要重新启动应用程序或必须调用 Trace.Refresh() 才能使更改生效。

另一种选择是在应用程序启动时以编程方式添加 TraceListeners,例如 Trace.Listeners.Add(new TextWriterTraceListener("output.log", "myListener"));

参见 https://msdn.microsoft.com/en-us/library/sk36c28t(v=vs.110).aspx

要按照您的问题添加具有 initializeData 值的过滤器,您可以使用 TraceListener.Filter 属性

要跨应用程序共享设置,您可以在 <system.diagnostics> 元素上使用 configSource 属性 并将该元素放在单独的配置文件中。这样做的缺点是文件需要与 app.config 位于同一文件夹中。因此,对一个文件的更改要么需要复制并粘贴到其他位置,要么以其他方式共享。

另一种方法是将包含跟踪侦听器信息的自定义配置文件保存在所有应用程序都可以访问的位置,然后在每个应用程序启动时加载该文件并如上所述配置跟踪侦听器。


更新

要在整个应用程序中共享日志记录,您可以创建一个 class 实现单例模式到 return 您的 TraceSource 实例或包装您的日志记录活动。这样你就不必绕过同一个实例

public class Logger
{
    private static Logger _logger;
        private TraceSource _ts;

        private Logger()
        {
        // Configure TraceSource here as required, e.g.
            _ts = new TraceSource("Whosebug", SourceLevels.All);
            _ts.Listeners.Add(new TextWriterTraceListener(@"c:\temp\tracefile.log"));
        }

        public static Logger Get()
        {
            if (_logger == null)
            {
                _logger = new Logger();
            }

            return _logger;
        }

        public void TraceInfo(string message)
        {
            _ts.TraceInformation(message);
            _ts.Flush();
        }
}

// To use
Logger.Get().TraceInfo("This is a trace message");

您可以扩展它,然后封装您要记录的实际消息,这样执行记录的代码就不知道具体细节,您只有一个定义事件的地方,例如

public void TraceApplicationStarting()
{
    _ts.TraceEvent(TraceEventType.Verbose, 1, "Application Starting");
}

您可以通过 ConfigurationManager 找到 app.exe.config 文件的路径,然后将配置文件加载为 XDocument.

string configPath = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None).FilePath;

XDocument config = XDocument.Load(configPath);
XElement diagnostics = config.Descendants().FirstOrDefault(e => e.Name == "system.diagnostics");

if (diagnostics == default(XElement))
{
    /// <system.diagnostics> element was not found in config
}
else
{
    /// make changes within <system.diagnostics> here...
}

config.Save(configPath);

Trace.Refresh();  /// reload the trace configuration

完成所需的更改后,将 XDocument 保存回磁盘,然后调用 Trace.Refresh() 重新加载跟踪配置。

See MSDN regarding the Trace.Refresh method here.

如果使用良好的安装程序在受保护的目录下部署应用程序,我会警告您对应用程序进行 app.config 更改,例如。 MS OS 中的程序文​​件已激活 UAC。

有时您需要一些管理员权限才能更新配置文件。

坏事是 运行 在 visual studio / 调试或某些测试程序下正确,部署后,在生产中,您可能会遇到一些问题...