如何使用App.config和System.Diagnostics动态设置日志文件?

5
我在寻找一个解决方案,为我的最新项目提供日志记录时,我遇到了一篇文章(http://www.daveoncsharp.com/2009/09/create-a-logger-using-the-trace-listener-in-csharp/),介绍了如何使用System.Diagnostics和App.config通过Trace方法进行日志记录。我成功地实现了类和App.config,但我真的很想能够动态分配日志文件的值/位置(在initializeData内部),但我不知道怎么做。如果您有任何建议,请随意发布!

App.config:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.diagnostics>
    <trace autoflush="true" indentsize="4">
      <listeners>
        <add name="myListener" 
             type="System.Diagnostics.TextWriterTraceListener" 
             initializeData="fileSizeThreshold=512, fileSizeUnit=kilobytes, 
             fileAgeThreshold=1, fileAgeUnit=months, fileNameTemplate='{0}\MyApp-{1:MMM-yy}.log'"/>
        <remove name="Default" />
      </listeners>
    </trace>
  </system.diagnostics>
</configuration>

日志记录器类:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;


namespace MyCurrentProject
{
    class Logger
    {
        public void Error(string module, string message)
        {
            WriteEntry(message, "ERROR:", module);
        }

        public void Error(Exception ex, string module)
        {
            WriteEntry(ex.Message, "ERROR:", module);
        }

        public void Warning(string module, string message)
        {
            WriteEntry(message, "WARNING:", module);
        }

        public void Info(string module, string message)
        {
            WriteEntry(message, "INFO:", module);
        }

        private void WriteEntry(string message, string type, string module)
        {
            Trace.WriteLine(
                    string.Format("{0} {1} [{2}] {3}",
                                  DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
                                  type,
                                  module,
                                  message));
        }
    }
}

RE: 抱歉表达不清...我需要明确一下,我需要动态设置日志文件输出的文件路径。我希望将路径保存到%AppData%中的某个位置。我在配置方面遇到的问题是,一旦我设置了'initializeData'的值,我就找不到更改或动态设置/重置该值的方法。说实话...现在我只想要一个能够工作并允许我管理日志文件位置的解决方案。

2个回答

7

以下是一个使用Systems.Diagnostics的实例,相比于非基类库有两个优点。它总是被允许的(在大型组织中),总是可用的,并且在开发人员熟悉基类库的程度上,下一批维护开发人员将会听说过它。

using System.Diagnostics;

namespace DynamicTraceLog
{
    class Program
    {
        static void Main(string[] args)
        {
            //Use TraceSource, not Trace, they are easier to turn off
            TraceSource trace = new TraceSource("app");
            //SourceSwitches allow you to turn the tracing on and off.
            SourceSwitch level =new SourceSwitch("app");
            //I assume you want to be dynamic, so probalby some user input would be here:
            if(args.Length>0 && args[0]=="Off")
                level.Level= SourceLevels.Off;
            else
                level.Level = SourceLevels.Verbose;
            trace.Switch = level;
            //remove default listner to improve performance
            trace.Listeners.Clear();
            //Listeners implement IDisposable
            using (TextWriterTraceListener file = new TextWriterTraceListener("log.txt"))
            using (ConsoleTraceListener console = new ConsoleTraceListener())
            {
                //The file will likely be in /bin/Debug/log.txt
                trace.Listeners.Add(file);
                //So you can see the results in screen
                trace.Listeners.Add(console);
                //Now trace, the console trace appears immediately.
                trace.TraceInformation("Hello world");
                //File buffers, it flushes on Dispose or when you say so.
                file.Flush();
            }
            System.Console.ReadKey();
        }
    }
}

关于如何格式化输出

使用Systems.Diagnostics类中实现模板化跟踪格式化/输出的跟踪侦听器中的任一种尝试: http://essentialdiagnostics.codeplex.com 或者 http://ukadcdiagnostics.codeplex.com/ Systems.Diagnostics不提供任何特定的标记格式化或输出。

感谢您的精彩文章...我希望能够在我的App.config中初始化它,以便于在项目中所有不同的类/对象中都可以普遍使用,并且我想在生成输出时能够格式化输出。请问我该如何使用您的示例来实现这一点? - Simpleton
好的,那么我不确定我是否理解了你在问题中所说的“动态分配日志文件的值/位置”。App.config 在应用程序域加载时只读取一次--对于 winforms 来说,只在应用程序启动时读取一次;对于 asp.net 来说,在第一次请求或应用程序回收(或当 web.config 编辑导致回收)时读取一次。并不是非常动态。为了使其普遍可用,请将其放在静态类中,这些类在整个应用程序域中共享。在 ASP.NET 中,在 global.asax 中进行设置工作。要拦截输出并按您的喜好格式化它,您需要一个自定义侦听器。请参见帖子以获取建议。 - MatthewMartin
抱歉没有表达清楚...为了明确起见,我需要动态设置日志文件输出保存的文件路径。我想将路径保存到%AppData%中的某个位置。我在配置中遇到的问题是一旦设置了'initializeData'的值,我就找不到改变或动态设置/重置该值的方法。说实话...现在我只想要一个可行的解决方案,并允许我管理日志文件的位置。 - Simpleton
以上代码应该可以起作用,文件路径在TextWriterTraceListener的构造函数中。当您需要写入不同的文件时(例如通过将其命名为log + DateTime.Now + .txt),请删除并重新添加侦听器。 - MatthewMartin

1

我知道这可能会被贬低,但是我想离题一下,建议您使用工具箱中的其他工具。Log4Net是一个非常强大而简洁的日志框架。例如,以下是一个使用它的控制台应用程序,完全符合您的需求。

using Com.Foo;

// Import log4net classes.
using log4net;
using log4net.Config;

public class MyApp 
{
    // Define a static logger variable so that it references the
    // Logger instance named "MyApp".
    private static readonly ILog log = LogManager.GetLogger(typeof(MyApp));

    static void Main(string[] args) 
    {
        // Set up a simple configuration that logs on the console.
        BasicConfigurator.Configure();

        log.Info("Entering application.");
        Bar bar = new Bar();
        bar.DoIt();
        log.Info("Exiting application.");
    }
}

但是假设我们想要使用配置文件来完成你所暗示的操作。 那么,这非常简单! 下面是我们将放置在App.config中以完成相同操作的配置:

<log4net>
    <!-- A1 is set to be a ConsoleAppender -->
    <appender name="A1" type="log4net.Appender.ConsoleAppender">

        <!-- A1 uses PatternLayout -->
        <layout type="log4net.Layout.PatternLayout">
            <conversionPattern value="%-4timestamp [%thread] %-5level %logger %ndc - %message%newline" />
        </layout>
    </appender>

    <!-- Set root logger level to DEBUG and its only appender to A1 -->
    <root>
        <level value="DEBUG" />
        <appender-ref ref="A1" />
    </root>
</log4net>

然后可以像这样使用该配置:

using Com.Foo;

// Import log4net classes.
using log4net;
using log4net.Config;

public class MyApp 
{
    private static readonly ILog log = LogManager.GetLogger(typeof(MyApp));

    static void Main(string[] args) 
    {
        // BasicConfigurator replaced with XmlConfigurator.
        XmlConfigurator.Configure(new System.IO.FileInfo(args[0]));

        log.Info("Entering application.");
        Bar bar = new Bar();
        bar.DoIt();
        log.Info("Exiting application.");
    }
}

不要让模式的东西抓住你的猝不及防,它只是配置你上面编码的内容,以便您在消息中保持一致性。这确实使它变得容易,因为您所需要记录的所有信息都只需插入到模式中,然后将模式封装起来即可。
这是一个关于Log4Net的速成课程,但我真正推荐它的原因是在上面的两个示例中,你可以看到它们记录到了控制台,但你有无数种可能的记录器,只需看一下这个列表: log4net.Appender.AdoNetAppender:使用预处理语句或存储过程将日志事件写入数据库。 log4net.Appender.AnsiColorTerminalAppender:将颜色突出显示的日志事件写入ANSI终端窗口。 log4net.Appender.AspNetTraceAppender:将日志事件写入ASP跟踪上下文。然后可以在ASP页面的末尾或ASP跟踪页面上呈现这些事件。 log4net.Appender.ColoredConsoleAppender:将颜色突出显示的日志事件写入应用程序的Windows控制台。 log4net.Appender.ConsoleAppender:将日志事件写入应用程序的控制台。事件可以发送到标准输出流或标准错误流。 log4net.Appender.DebugAppender:将日志事件写入.NET系统。 log4net.Appender.EventLogAppender:将日志事件写入Windows事件日志。

log4net.Appender.FileAppender: 将日志事件写入文件系统中的文件。

log4net.Appender.LocalSyslogAppender: 将日志事件写入本地 syslog 服务(仅限 UNIX)。

log4net.Appender.MemoryAppender: 将日志事件存储在内存缓冲区中。

log4net.Appender.NetSendAppender: 将日志事件写入 Windows Messenger 服务。这些消息将在用户终端上的对话框中显示。

log4net.Appender.OutputDebugStringAppender: 将日志事件写入调试器。如果应用程序没有调试器,则系统调试器会显示该字符串。如果应用程序没有调试器且系统调试器未激活,则忽略该消息。

log4net.Appender.RemoteSyslogAppender: 使用 UDP 网络将日志事件写入远程 syslog 服务。

log4net.Appender.RemotingAppender: 使用 .NET remoting 将日志事件写入远程接收器。

log4net.Appender.RollingFileAppender: 将日志事件写入文件系统中的文件。RollingFileAppender 可以根据日期或文件大小约束配置为记录到多个文件。

log4net.Appender.SmtpAppender: 将日志事件发送到电子邮件地址。

log4net.Appender.SmtpPickupDirAppender: 将日志事件发送到电子邮件地址,但将电子邮件写入可配置目录而不是直接通过SMTP发送。

log4net.Appender.TelnetAppender: 客户端通过Telnet连接以接收日志事件。

log4net.Appender.TraceAppender: 将日志事件写入.NET跟踪系统。

log4net.Appender.UdpAppender: 使用UdpClient将日志事件作为无连接的UDP数据报发送到远程主机或多播组。


所以,正如您所看到的,它在OOB方面非常有能力。我希望这篇文章对您有所帮助。


好的,我来试试看。你怎么安装这个包,以便我可以将其引用到我的项目/解决方案中?如果有关系的话,我正在使用VS 2012。 - Simpleton
@MeikelDeitrick,log4net有一个NuGet包,您可以在此处找到它(https://nuget.org/packages/log4net),因此您只需通过NuGet Package Manager将其下载即可。如果您没有,请在此处获取它(http://visualstudiogallery.msdn.microsoft.com/27077b70-9dad-4c64-adcf-c7cf6bc9970c?SRC=VSIDE)。 - Mike Perrenoud
@Mike,我已经通过NuGet安装了log4net,但是在可用引用列表中找不到该包。我该如何添加引用? - Simpleton
@MeikelDeitrick,没错,使用NuGet为所有项目安装log4net...它会自动添加引用,就像你所看到的那样。 - Mike Perrenoud
@MatthewMartin,那不是很可爱吗。 - Mike Perrenoud
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接