简体   繁体   English

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

[英]Reading rotation log files and file locking

I have a Python service spitting out logs to text files. 我有一个Python服务将日志吐出到文本文件。 It rotates them every ~400KB. 它每隔约400KB旋转一次。 So the Python service opens up a handle on the file, let's call it app.log . 所以Python服务打开了文件的句柄,我们称之为app.log It then writes content to the file every now and again flushes it to the disk. 然后,它会立即将内容写入文件,并再次将其刷新到磁盘。 When it reaches a certain size, it closes it's handle, and move it to app.log.1 and starts a new handle on app.log . 当它达到一定大小时,它会关闭它的句柄,并将其移动到app.log.1并在app.log上启动一个新句柄。

So I can't change this service, but I have a C# application that will read those logs. 所以我无法更改此服务,但我有一个C#应用程序将读取这些日志。 I ran into 3 scenarios: 我遇到了3个场景:

  • If I just try to read those those logs using new FileStream(path, FileMode.Open); 如果我只是尝试使用new FileStream(path, FileMode.Open);读取那些日志new FileStream(path, FileMode.Open); , it won't allow me as the Python service has an handle on it. ,它不允许我,因为Python服务有一个句柄。
  • If I try to open it using new FileStream(path, FileMode.Open, FileAccess.Read); 如果我尝试使用new FileStream(path, FileMode.Open, FileAccess.Read);打开它new FileStream(path, FileMode.Open, FileAccess.Read); , this allows me to read it, but if the service tries to rotate the log, it won't be able to as my C# application now has a handle on the file. ,这允许我阅读它,但如果服务试图旋转日志,它将无法,因为我的C#应用​​程序现在有文件的句柄。
  • And if I try to open the file using new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Delete); 如果我尝试使用new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Delete);打开文件new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Delete); , my Python service won't fail on deleting the file, but it will fail creating a new handle on app.log as the C# application would still have a handle on it. ,我的Python服务在删除文件时不会失败,但是在app.log上创建一个新句柄会失败,因为C#应用程序仍然会有一个句柄。

The only solution which I'm aware of would be using Windows Shadow Copy (VSS) to create a snapshot of the logs and then read that snapshot but this would be quite expensive as we need to query the logs at every 5 minutes. 我所知道的唯一解决方案是使用Windows Shadow Copy(VSS)来创建日志快照,然后读取该快照,但这将非常昂贵,因为我们需要每5分钟查询一次日志。

Also, I'm not interested in reading the rotated logs, app.log.1 , app.log.2 etc. 另外,我对阅读旋转日志, app.log.1app.log.2等不感兴趣。

Logging to text files under Windows seems to be a pain what with all the locking/handles. 在Windows下记录文本文件似乎是所有锁定/句柄的痛苦。 Does anyone have any suggestion? 有没有人有任何建议?

You should be able to open your file as Dmitry Popov suggested in his answer as below and not affect Python writing to it, however it depends upon what locks the Python application holds on the file, it can lock you out completely and there is nothing you to do to prevent that without hacking Windows. 您应该能够像Dmitry Popov在下面的回答中所建议的那样打开您的文件并且不会影响Python写入它,但是它取决于Python应用程序对文件的锁定,它可以完全锁定您并且没有任何关系没有黑客入侵Windows就可以做到这一点。

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

The FileStream object created in this way will still be connected to the same file after an operating system file move operation has been performed on it to rename it. 在对其执行操作系统文件移动操作以重命名后,以这种方式创建的FileStream对象仍将连接到同一文件。

So lets assume your python app opens a file called Test.log and starts writing to it. 因此,假设您的python应用程序打开一个名为Test.log的文件并开始写入它。 You can read any data written to it (after python flushes its buffer) using the file stream returned from the line above. 您可以使用从上面的行返回的文件流读取写入它的任何数据(在python刷新其缓冲区之后)。 The python application can close and reopen the file as often as it wants writing each time and the reading application will remain connected to it. python应用程序可以按照每次写入的频率关闭并重新打开文件,并且读取应用程序将保持与其连接。 When the python application issues a File Move operation to rename the file to Test1.log, the file stream returned above will still be connected to the file which is now called Test1.log so you can continue reading to the end of the file before starting the new log file if that is what you want. 当python应用程序发出文件移动操作以将文件重命名为Test1.log时,上面返回的文件流仍将连接到现在称为Test1.log的文件,因此您可以在开始之前继续读取文件的末尾新日志文件,如果这是你想要的。 There is one caveat to this. 有一点需要注意。 The Python application needs to use a Move/Rename operation rather than copying the file to a new one and deleting the old one, I'd be surprised if that is what it does though. Python应用程序需要使用移动/重命名操作,而不是将文件复制到新文件并删除旧文件,但如果这是它的功能,我会感到惊讶。

There is a possibility that your reading application will reach the end of the file before your writing application has finished reading from it. 在您的书写应用程序完成阅读之前,您的阅读应用程序可能会到达文件的末尾。 In this case fs.Read will keep returning 0 after a timeout until the writing application opens the file and writes some more. 在这种情况下,fs.Read将在超时后继续返回0,直到写入应用程序打开文件并写入更多内容。 You can make the time out very long / infinite if you want. 如果需要,您可以将时间设置为非常长/无限。

As you don't want to read to the end of one file before starting the new one you could just close and reopen the file at regular intervals. 由于您不想在启动新文件之前读取到一个文件的末尾,因此您可以关闭并定期重新打开文件。 The log file without the numeric suffix should always be the most recent. 没有数字后缀的日志文件应始终是最新的。

If however you want your reading application to read to the end of one log file before starting at the beginning of the next one you will need to work out when the writing application has finished writing to the log file. 但是,如果您希望读取应用程序在下一个日志文件开始之前读取到一个日志文件的末尾,则需要在写入应用程序写入日志文件时解决。 Also it needs to find out what the file is now called so it can read n-1 next. 此外,它需要找出现在调用的文件,以便下次读取n-1。 Is there some marker written by the python application that you could look for to denote the end of a file? 是否有一些由python应用程序编写的标记,你可以寻找它来表示文件的结尾? Does it write 'End Of Log' or something similar? 它写的是“日志结束”还是类似的东西?

Be warned also that there are going to be short periods of time when LogFile n-1 does not exist. 还要注意,当LogFile n-1不存在时,会有很短的时间。 This is because if you have log files 0, 1, 2 and 3 it needs to make log file 3 into log file 4 before it can make log file 2 into log file 3. While it is doing this there will be a short period of time when you have log files 0, 1, 2, 4 and no 3. 这是因为如果你有日志文件0,1,2和3,它需要将日志文件3放入日志文件4,然后才能将日志文件2放入日志文件3.虽然这样做会有一段短暂的时间有日志文件0,1,2,4和3的时间。

Personally I would find the developer that wrote the logging for your Python application give him/her the evil eye for causing this headache in the first place. 就个人而言,我会发现为Python应用程序编写日志记录的开发人员首先给他/她造成这种头痛的邪恶之眼。 What is wrong with having the most recent log file have the largest number? 使最新的日志文件具有最大数量有什么问题?

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

C# thread don't lock the file in this case, your Python script can write and close the file to create another one without deadlock. 在这种情况下,C#thread不会锁定文件,您的Python脚本可以写入并关闭该文件以创建另一个没有死锁的文件。

You can combine FileShare flags: 您可以组合FileShare标志:

FileShare.Write | FileShare.Delete

Here's a demo: 这是一个演示:

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);
}

You will have to deal with concurrency. 您将不得不处理并发问题。 You can use FileSystemWatcher to monitor file changes. 您可以使用FileSystemWatcher来监视文件更改。

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

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