繁体   English   中英

读取旋转日志文件和文件锁定

[英]Reading rotation log files and file locking

我有一个Python服务将日志吐出到文本文件。 它每隔约400KB旋转一次。 所以Python服务打开了文件的句柄,我们称之为app.log 然后,它会立即将内容写入文件,并再次将其刷新到磁盘。 当它达到一定大小时,它会关闭它的句柄,并将其移动到app.log.1并在app.log上启动一个新句柄。

所以我无法更改此服务,但我有一个C#应用程序将读取这些日志。 我遇到了3个场景:

  • 如果我只是尝试使用new FileStream(path, FileMode.Open);读取那些日志new FileStream(path, FileMode.Open); ,它不允许我,因为Python服务有一个句柄。
  • 如果我尝试使用new FileStream(path, FileMode.Open, FileAccess.Read);打开它new FileStream(path, FileMode.Open, FileAccess.Read); ,这允许我阅读它,但如果服务试图旋转日志,它将无法,因为我的C#应用​​程序现在有文件的句柄。
  • 如果我尝试使用new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Delete);打开文件new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Delete); ,我的Python服务在删除文件时不会失败,但是在app.log上创建一个新句柄会失败,因为C#应用程序仍然会有一个句柄。

我所知道的唯一解决方案是使用Windows Shadow Copy(VSS)来创建日志快照,然后读取该快照,但这将非常昂贵,因为我们需要每5分钟查询一次日志。

另外,我对阅读旋转日志, app.log.1app.log.2等不感兴趣。

在Windows下记录文本文件似乎是所有锁定/句柄的痛苦。 有没有人有任何建议?

您应该能够像Dmitry Popov在下面的回答中所建议的那样打开您的文件并且不会影响Python写入它,但是它取决于Python应用程序对文件的锁定,它可以完全锁定您并且没有任何关系没有黑客入侵Windows就可以做到这一点。

FileSream fs = File.Open(@"c:\Test.txt", FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete)

在对其执行操作系统文件移动操作以重命名后,以这种方式创建的FileStream对象仍将连接到同一文件。

因此,假设您的python应用程序打开一个名为Test.log的文件并开始写入它。 您可以使用从上面的行返回的文件流读取写入它的任何数据(在python刷新其缓冲区之后)。 python应用程序可以按照每次写入的频率关闭并重新打开文件,并且读取应用程序将保持与其连接。 当python应用程序发出文件移动操作以将文件重命名为Test1.log时,上面返回的文件流仍将连接到现在称为Test1.log的文件,因此您可以在开始之前继续读取文件的末尾新日志文件,如果这是你想要的。 有一点需要注意。 Python应用程序需要使用移动/重命名操作,而不是将文件复制到新文件并删除旧文件,但如果这是它的功能,我会感到惊讶。

在您的书写应用程序完成阅读之前,您的阅读应用程序可能会到达文件的末尾。 在这种情况下,fs.Read将在超时后继续返回0,直到写入应用程序打开文件并写入更多内容。 如果需要,您可以将时间设置为非常长/无限。

由于您不想在启动新文件之前读取到一个文件的末尾,因此您可以关闭并定期重新打开文件。 没有数字后缀的日志文件应始终是最新的。

但是,如果您希望读取应用程序在下一个日志文件开始之前读取到一个日志文件的末尾,则需要在写入应用程序写入日志文件时解决。 此外,它需要找出现在调用的文件,以便下次读取n-1。 是否有一些由python应用程序编写的标记,你可以寻找它来表示文件的结尾? 它写的是“日志结束”还是类似的东西?

还要注意,当LogFile n-1不存在时,会有很短的时间。 这是因为如果你有日志文件0,1,2和3,它需要将日志文件3放入日志文件4,然后才能将日志文件2放入日志文件3.虽然这样做会有一段短暂的时间有日志文件0,1,2,4和3的时间。

就个人而言,我会发现为Python应用程序编写日志记录的开发人员首先给他/她造成这种头痛的邪恶之眼。 使最新的日志文件具有最大数量有什么问题?

using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))
{
  //Do works
}

在这种情况下,C#thread不会锁定文件,您的Python脚本可以写入并关闭该文件以创建另一个没有死锁的文件。

您可以组合FileShare标志:

FileShare.Write | FileShare.Delete

这是一个演示:

using (var cSharp = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Write | FileShare.Delete))
{
    // The Python service will be able to change and to rename the file:
    using (var python = new FileStream(filename, FileMode.Open, FileAccess.Write, FileShare.Read))
    {
    }
    File.Move(filename, newFilename);
}

您将不得不处理并发问题。 您可以使用FileSystemWatcher来监视文件更改。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM