17

我已经在我的应用程序中成功配置了 log4net,但有一件事对我来说有点烦人。

即使没有发生错误,我的应用程序启动后也会创建日志文件(为空)。我想仅在出现一些错误后才创建日志文件。

4

7 回答 7

15

我实际上在这个线程中找到了一种方法:

http://www.l4ndash.com/Log4NetMailArchive/tabid/70/forumid/1/postid/18271/view/topic/Default.aspx

我已经测试了第一种方法并且它有效。以防万一该链接不再有效,我将在此处重现代码。基本上,作者指出有两种方法可以做到这一点。

第一种方式:

如果该记录器的适当阈值有效,则创建一个仅获取锁(并创建文件)的新锁定模型。

public class MyLock : log4net.Appender.FileAppender.MinimalLock
{
      public override Stream AcquireLock()
      {
            if (CurrentAppender.Threshold == log4net.Core.Level.Off)
                  return null;

            return base.AcquireLock();
      }
}

现在在配置文件中,将阈值设置为:

<threshold value="OFF" />

并确保在建模时设置了这个新的 LockingModel:

<lockingModel type="Namespace.MyLock" />

我将它与滚动文件附加程序一起使用。

第二种方法在链接中列出。我没有尝试过这种技术,但它似乎在技术上是合理的。

于 2011-02-11T19:03:58.723 回答
8

我知道这是一个老问题,但我认为这对其他人有用。

我们遇到了类似的情况,要求应用程序在没有发生错误的情况下不应留下空的日志文件。

我们通过创建以下自定义 LockingModel 类解决了这个问题:

public class MinimalLockDeleteEmpty : FileAppender.MinimalLock
{
    public override void ReleaseLock()
    {
        base.ReleaseLock();

        var logFile = new FileInfo(CurrentAppender.File);
        if (logFile.Exists && logFile.Length <= 0)
        {
            logFile.Delete();
        }
    }
}

它派生自 FileAppender.MinimalLock 类,该类将在写入每个日志消息后释放对日志文件的锁定。

我们添加了额外的功能,如果在锁被释放后它仍然是空的,它将删除日志文件。如果应用程序运行并退出而没有任何错误,它可以防止应用程序留下空的错误日志文件。

优点

  • 它仍然会在 Log4Net 的配置阶段创建一个空日志文件,以确保在应用程序的其余部分启动之前日志记录正在工作。但是,日志文件会立即被删除。
  • 它不需要您通过将阈值设置为“OFF”来关闭配置文件中的日志记录,然后在编写第一个日志事件之前以编程方式打开日志记录。

缺点

  • 这很可能是一种管理日志文件的缓慢方法,因为 ReleaseLock 方法和文件长度检查将在每个写入日志文件的日志事件之后调用。仅在您期望很少有错误时使用它,并且在没有错误时不应该存在日志文件是业务要求。
  • 日志文件在为空时创建和删除。如果您有其他工具监视日志目录中的文件系统更改,这可能是一个问题。但是,在我们的情况下,这不是问题。
于 2012-08-29T10:05:32.540 回答
6

以下对我有用。第一次调用 OpenFile() 发生在配置记录器时。后续调用是生成实际日志消息的时间。

class CustomFileAppender : RollingFileAppender
{
    private bool isFirstTime = true;
    protected override void OpenFile(string fileName, bool append)
    {
        if (isFirstTime)
        {
            isFirstTime = false;
            return;
        }

        base.OpenFile(fileName, append);
    }
}

并在配置文件中,更改附加程序

<log4net>
<appender name="RollingFile" type="<your namespace>.CustomFileAppender">
...
</log4net>

来自 log4Net 源的序列如下:


  • 第一次调用 OpenFile() 是因为从 FileAppender 的构造函数调用了 ActivateOptions()。
  • 当生成日志消息时,AppenderSkeleton 的 DoAppend() 调用 PreAppendCheck()
  • PreAppendCheck() 在 FileAppender 的基础 TextWriterAppender 中被覆盖。
  • 如果文件尚未打开,则覆盖的 PreAppendCheck() 调用虚拟 PrepareWriter 。
  • FileAppender 的 PrepareWriter() 调用 SafeOpenFile(),后者又调用 OpenFile()
于 2016-02-29T03:23:00.693 回答
3

这种方法的问题在于,如果文件存在但是只读的,或者位于不存在的目录中等,那么直到另一个错误已经导致问题时,您才会发现。您真的希望在应用程序的其余部分启动之前确信日志记录正在工作。

无论如何,可能有一种方法可以做到这一点,但如果没有,我怀疑这就是原因。

于 2010-03-28T15:32:14.793 回答
2

邮件列表存档的此消息中描述了另一种非常简单的方法

基本上,使用 log4net,日志文件是在配置记录器时创建的。将其配置为其他方式有点hacky。解决方案是推迟配置的执行。上面的消息建议在设置记录器时执行以下操作:

private static ILog _log = LogManager.GetLogger(typeof(Program));
public static ILog Log
{
    get
    {
        if(!log4net.LogManager.GetRepository().Configured)
            log4net.Config.XmlConfigurator.Configure(new FileInfo(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile));
        return _log;
    }
}

我通常使用程序集属性配置 log4net ,它会自动配置记录器(从而创建日志文件),以及用于日志的简单 getter:

[assembly: log4net.Config.XmlConfigurator(Watch = true)]
...
public static log4net.ILog Log { get { return _log; } }
private static readonly log4net.ILog _log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

但是删除它并在上面的吸气剂中添加额外的逻辑反而为我解决了这个问题。

注意:总的来说,我同意在大多数情况下,最好在应用程序启动时配置记录器并创建文件(甚至写入文件)。

于 2012-02-08T22:49:05.070 回答
0

AcquireLock 和 ReleaseLock 方法对我有用,但让我感到困扰的是文件被创建/删除了很多次。这是另一个类似的选项,它关闭记录器并在程序完成时删除空日志文件。完成日志记录后,只需调用 RemoveEmptyLogFile。

/// <summary>
/// Sets the logging level for log4net.
/// </summary>
private static void RemoveEmptyLogFile()
{
  //Get the logfilename before we shut it down
  log4net.Appender.FileAppender rootAppender = (log4net.Appender.FileAppender)((log4net.Repository.Hierarchy.Hierarchy)log4net.LogManager.GetRepository()).Root.Appenders[0];
  string filename = rootAppender.File;

  //Shut down all of the repositories to release lock on logfile
  log4net.Repository.ILoggerRepository[] repositories = log4net.LogManager.GetAllRepositories();
  foreach (log4net.Repository.ILoggerRepository repository in repositories)
  {
    repository.Shutdown();
  }

  //Delete log file if it's empty
  var f = new FileInfo(filename);
  if (f.Exists && f.Length <= 0)
  {
    f.Delete();
  }
} // RemoveEmptyLogFile
于 2014-10-08T20:03:52.023 回答
-2
private static ILog _log = LogManager.GetLogger(typeof(Program));
public static ILog Log
{
    get
    {
        if(!log4net.LogManager.GetRepository().Configured)
        log4net.Config.XmlConfigurator.Configure(new FileInfo(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile));
        return _log;
    }
}
于 2013-10-16T03:38:39.327 回答