如何以编程方式强制 log4net 释放日志文件以便可以访问?

How to programmatically force log4net to release log file so it can be accessed?

我需要在大型流程执行后发送一封电子邮件,并将日志文件作为附件,以便用户可以识别任何问题。我们使用 log4net 来处理我们所有的日志记录,但我无法让 log4net 发布文件以便将其添加为附件。

到目前为止,我遵循了这个问题的结果: 关于将 appender 阈值设置为 "Off",但由于 DLL 未释放日志文件,我继续收到异常。我可以在调试器中验证 appender 实际上在 "Off" 中,但进程资源管理器确认我的 exe 仍在文件上锁定。

这是我从链接问题中得到的方法:

 private static void SetThreshold(string appenderName, log4net.Core.Level threshold)
        {
            foreach (log4net.Appender.AppenderSkeleton appender in log4net.LogManager.GetRepository().GetAppenders())
            {
                if (appender.Name == appenderName)
                {
                    appender.Threshold = threshold;
                    break;
                }
            }
        }

任何关于如何强制发布此日志的想法都将非常有帮助。谢谢

日志已打开以供写入,因此释放锁定的唯一方法是停止应用程序。您确实有选择:1)使用 maximumFileSize 设置将日志文件分成块,以便只有最近的日志不可用; 2) 将消息记录到数据库(log4net提供了这样的接口,见https://www.c-sharpcorner.com/article/configure-log4net-with-database-tutorial-for-beginners/)。

使用FileAppenderRollingFileAppender时,可以配置日志文件LockingModel。使用适当的 LockingModel 应该允许所需的文件访问权限。
来自 log4net 文档 (https://logging.apache.org/log4net/release/sdk/index.html)

内置三种锁定模型:

  • FileAppender.ExclusiveLock
  • FileAppender.MinimalLock
  • FileAppender.InterProcessLock

第一个从记录开始到结束锁定文件,第二个仅在记录每条消息时锁定最短的时间,最后一个使用命名的系统范围互斥体同步进程。

默认锁定模型是 FileAppender.ExclusiveLock。

下面的配置示例来自 https://logging.apache.org/log4net/release/config-examples.html

<appender name="FileAppender" type="log4net.Appender.FileAppender">
    <file value="${TMP}\log-file.txt" />
    <appendToFile value="true" />
    <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
    <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
    </layout>
</appender>

编辑: LockingModel 公开了一个 ReleaseLock 方法,该方法将强制进程释放文件。要继续记录,您必须调用 AcquireLock.

使用我从同事那里得到的以下代码块,我能够 read-only 访问日志(需要写入权限才能用作电子邮件中的附件):

 var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
            var lines = new List<string>();
            using (var sr = new StreamReader(fs))
            {
                while(!sr.EndOfStream)
                {
                    lines.Add(sr.ReadLine());
                }
            }

我能够获取此列表并将其写入临时文件并使用它来发送我们的附件,而不必担心修改 log4net 和危及针对相同 log4net DLL 的其他程序集的任何依赖项。

感谢分享想法的两位!