我已经在我的应用程序中成功配置了 log4net,但有一件事对我来说有点烦人。
即使没有发生错误,我的应用程序启动后也会创建日志文件(为空)。我想仅在出现一些错误后才创建日志文件。
我已经在我的应用程序中成功配置了 log4net,但有一件事对我来说有点烦人。
即使没有发生错误,我的应用程序启动后也会创建日志文件(为空)。我想仅在出现一些错误后才创建日志文件。
我实际上在这个线程中找到了一种方法:
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" />
我将它与滚动文件附加程序一起使用。
第二种方法在链接中列出。我没有尝试过这种技术,但它似乎在技术上是合理的。
我知道这是一个老问题,但我认为这对其他人有用。
我们遇到了类似的情况,要求应用程序在没有发生错误的情况下不应留下空的日志文件。
我们通过创建以下自定义 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 类,该类将在写入每个日志消息后释放对日志文件的锁定。
我们添加了额外的功能,如果在锁被释放后它仍然是空的,它将删除日志文件。如果应用程序运行并退出而没有任何错误,它可以防止应用程序留下空的错误日志文件。
优点
缺点
以下对我有用。第一次调用 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 源的序列如下:
这种方法的问题在于,如果文件存在但是只读的,或者位于不存在的目录中等,那么直到另一个错误已经导致问题时,您才会发现。您真的希望在应用程序的其余部分启动之前确信日志记录正在工作。
无论如何,可能有一种方法可以做到这一点,但如果没有,我怀疑这就是原因。
邮件列表存档的此消息中描述了另一种非常简单的方法
基本上,使用 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);
但是删除它并在上面的吸气剂中添加额外的逻辑反而为我解决了这个问题。
注意:总的来说,我同意在大多数情况下,最好在应用程序启动时配置记录器并创建文件(甚至写入文件)。
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
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;
}
}