【问题标题】:Unique log file for each instance of class每个类实例的唯一日志文件
【发布时间】:2011-09-05 17:16:05
【问题描述】:

我目前正在运行一个创建类的多个实例的 Windows 服务。

在我的解决方案中的服务类和所有其他类的顶部,我有这样的东西:

private static readonly ILog _log = LogManager.GetLogger(typeof(SomeClassTypeHere));

在我的 App.config 中,我为单个文件配置了 Log4Net:

<log4net debug="true">
    <appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
      <file value="Logs\SomeLogFileName.xml" />
      <appendToFile value="true" />
      <rollingStyle value="Size" />
      <countDirection value="1" />
      <maxSizeRollBackups value="30" />
      <maximumFileSize value="10MB" />
      <staticLogFileName value="true" />
      <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
      <layout type="log4net.Layout.XmlLayoutSchemaLog4j">
        <locationInfo value="true" />
      </layout>
    </appender>

    <root>
      <level value="INFO" />
      <appender-ref ref="RollingFileAppender" />
    </root>
  </log4net>

这在大多数方面都非常有效,并且所有内容都记录到一个文件中。但是,我真的很想为我的服务创建的特定类的每个实例创建一个单独的日志文件。
这是一个我们经常需要监控以获取支持的类,我们可以同时运行一些实例。
我们不知道在给定时间会运行哪些实例,因此在配置中创建静态文件有点痛苦。

我尝试取消只读修饰符并在类构造函数中设置以下内容:

_log = LogManager.GetLogger("DataCollectionClass_" + deviceName + "_" + DateTime.Now.ToString("MMddyyyy"), typeof(SomeClassTypeHere));

但这需要我在配置中手动定义一个 appender,这会很麻烦而且很难跟上。

对在 L4N 中执行此操作有什么想法吗?我看过链接here,但真的不知道是否需要这么多的框架。

【问题讨论】:

    标签: c# logging service log4net


    【解决方案1】:

    下面的代码展示了如何在不使用配置文件的情况下以编程方式配置 log4Net 以达到您想要的效果。基本上,它只涉及创建一个命名记录器并添加到层次结构中。

    我以here的答案之一作为起点。

    using log4net;
    using log4net.Appender;
    using log4net.Layout;
    using log4net.Repository.Hierarchy;
    
    namespace LoggerTest
    {
        class Program
        {
            static void Main(string[] args)
            {
                DeviceConnection dev1 = new DeviceConnection("Device1");
                DeviceConnection dev2 = new DeviceConnection("Device2");
    
                dev1.DoSomething();
                dev2.DoSomething();
            }
        }
    
        public class DeviceConnection
        {
            private string name;
            private readonly ILog logger;
    
            public DeviceConnection(string _name)
            {
                name = _name;
    
                logger = TestLogger.AddNamedLogger(name);
    
                logger.Info("----  Begin Logging for DeviceConnection: " + name);
            }
    
            public void DoSomething()
            {
                logger.Info("Doing something for device connection " + name);
            }
        }
    
        public static class TestLogger
        {
            private static PatternLayout _layout = new PatternLayout();
            private const string LOG_PATTERN = "%d [%t] %-5p %m%n";
    
            public static string DefaultPattern
            {
                get { return LOG_PATTERN; }
            }
    
            static TestLogger()
            {
                _layout.ConversionPattern = DefaultPattern;
                _layout.ActivateOptions();
    
                Hierarchy hierarchy = (Hierarchy)LogManager.GetRepository();
                hierarchy.Configured = true;
            }
    
            public static PatternLayout DefaultLayout
            {
                get { return _layout; }
            }
    
            public static ILog AddNamedLogger(string name)
            {
                Hierarchy hierarchy = (Hierarchy)LogManager.GetRepository();
                Logger newLogger = hierarchy.GetLogger(name) as Logger;
    
                PatternLayout patternLayout = new PatternLayout();
                patternLayout.ConversionPattern = LOG_PATTERN;
                patternLayout.ActivateOptions();
    
                RollingFileAppender roller = new RollingFileAppender();
                roller.Layout = patternLayout;
                roller.AppendToFile = true;
                roller.RollingStyle = RollingFileAppender.RollingMode.Size;
                roller.MaxSizeRollBackups = 4;
                roller.MaximumFileSize = "100KB";
                roller.StaticLogFileName = true;
                roller.File = name + ".log";
                roller.ActivateOptions();
    
                newLogger.AddAppender(roller);
    
                return LogManager.GetLogger(name);
            }
        }
    }
    

    【讨论】:

    • 如果从代码中看不出来,名为 dev1 的实例总是记录到 Device1.log,而名为 dev2 的实例记录到 Device2.log。代码已经测试过了,应该可以直接复制到新控制台项目的program.cs文件中试一试。
    【解决方案2】:

    使用 ADO.Net appender 并记录到 SQL Server 数据库,然后查询您需要的信息。

    另一种选择是 log4net 仪表板:http://www.l4ndash.com/。它在整合来自各种来源的日志方面做得相当不错,然后以不同的方式对它们进行切片和切块。价格也很合理。

    【讨论】:

    • 这听起来是个好计划;但是,在我的公司。环境中,我们没有专门用于记录此服务的数据库。也许团队最终会迁移到那个,但现在每个团队都需要使用一个平面文件(或其集合)。 >=(
    • @AdminK9:查看我修改后的答案。
    【解决方案3】:

    log4net 有一个称为记录器层次结构的概念。

    据说记录器是 另一个记录器的祖先,如果它 名称后跟一个点是前缀 后代记录器名称。记录器 据说是孩子的父母 记录器,如果没有祖先 在自己和后代之间 记录器。层次结构非常有效 以与命名空间相同的方式和 .NET 中的类层次结构。这是非常 方便,我们很快就会看到。

    因此,您确实应该使用 . 字符而不是 _ 字符创建特定于实例的记录器。

    _log = LogManager.GetLogger("DataCollectionClass." + deviceName + "." + DateTime.Now.ToString("MMddyyyy"), typeof(SomeClassTypeHere));
    

    然后在配置文件中引用记录器层次结构,如下所示。

    <log4net>
      <!-- Other log4net configuration omitted for brevity -->
      <logger name="DataCollectionClass">
        <!-- Put your appender-ref entries here -->
      </logger>
    </log4net>
    

    请注意记录器名称引用如何不包含代码中使用的完全限定名称。它仅引用名称的根。以与命名空间相同的方式来考虑它。

    【讨论】:

    • 这种方法+1。我有与 OP 相同的要求,看起来“层次结构”非常适合这个要求。我更喜欢使用配置文件而不是编程方法(尽管我猜 app.config 可以在那里以某种方式工作)。我将进一步调查您的选择。
    • 嗨。我不确定如何为每个实例创建不同的文件。附加程序控制文件名对吗?
    【解决方案4】:

    我有一篇文章可能会有所帮助:

    https://web.archive.org/web/20110502044414/http://horth.com/blog/?p=165

    这是关于在运行时更改日志文件。您可以做的是将每个实例的文件名传递到您的 log4net 文件中。这样你就可以为你的类的每个实例创建一个日志文件。这样您的配置文件就很简单,而且您可以灵活地为每个类实例创建一个新的日志文件。

    上面提到过,您也可以使用每个实例的指标登录到数据库。如果您不想购买任何东西,请使用允许 10GB 数据库的 SQL Express。您甚至可以直接写入 MDF 文件,而不是安装 SQL。

    【讨论】:

    • 链接已损坏。
    • 链接已修复。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-07
    • 1970-01-01
    • 2015-06-07
    • 2019-10-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多