【发布时间】:2014-09-16 12:11:06
【问题描述】:
我刚刚重写了一个 Windows 服务进程,它将重要的信息调试输出到 /programdata/myservice/ 文件夹中的日志文件。
但是在午夜的晚上,我有一份工作应该获取当前日期的日志文件并删除它的内容,然后创建一个名称为 3 天的存档日志文件,例如 LogfileArchived15092014.log。
然后运行一些代码来删除早于该日期的日志文件,因此我只有今天的当前日志文件和 2 个用于调试旧问题等的存档文件。
现在我已经从一个正在运行的旧服务中复制了执行此操作的代码,它会归档日志文件并删除旧文件。但是由于某种原因,当这个新作业运行时,我会收到诸如此类的 I/O 错误(来自事件查看器)
错误运行系统作业:I/O 错误归档日志文件:C:\ProgramData\Brainiac\LogfileArchived;该进程无法访问文件“C:\ProgramData\Brainiac\Logfile.log”,因为它正被另一个进程使用。
现在第一个路径上没有扩展名的原因,例如 C:\ProgramData\Brainiac\LogfileArchived 是因为它在到达创建文件日期以附加到文件名例如
// set a lock up to prevent other processes locking
this.Locked = true;
// wrap in try as it keeps failing!!!!
try
{
// take contents of current log file - the daily one I have been logging to all day
// I guess this is where the error is being raised due to the absence
// of a .log extension in the error message when mentioning the filename
string content = this.ReadFileString(this.logFilePath);
// for some reason todays log file was empty
// why would this be unless loggging was disabled?
if (!String.IsNullOrEmpty(content))
{
// create a new log file with date stamp of yesterday added to the filename and guff removed to make it valid
string file_date = DateTime.Now.Date.AddDays(-1).ToString().Replace("/", "").Replace("-", "");
// remove time part - should be done at midnight but if not ensure colons and spaces are removed
file_date = file_date.Replace("00:00:00", "").Replace(":", "").Replace(" ", "");
// append .log to it
this.logfilearchivepath += file_date + ".log";
//Append all the contents of my daily log file to this new file
File.AppendAllText(this.logfilearchivepath, content, Encoding.UTF8);
所以我怀疑它在这条线上爆炸了
string content = this.ReadFileString(this.logFilePath);
由于错误消息中没有扩展名。那么也许我需要一种不同的方式来访问内容?
现在我不知道它锁定了哪些其他进程(我能以某种方式找到吗?)但我尝试了以下方法。
- 确保我没有在我自己的计算机上打开该文件。
-
添加一个标志,以防止任何日志记录到日志文件。正如你在顶部看到的那样,我走了
// 设置一个锁定以防止其他进程锁定 this.Locked = true;
在我的日志记录方法中,我检查了它是否尽快退出,例如
// log to our application data folder - unless locked for some reason
public void LogMsg(string msg, string debugLevel = "HIGH")
{
// we are prevented from logging at this point in time
if (this.Locked) return;
-
我还在 3 个 try/catch 语句中封装了对 ArchiveLogFile() 方法的调用,每个语句之间都有一个 Thread.Sleep,间隔越来越长,以防仍有记录。
我也尝试过使用数据库锁。
所以我有一个名为 LOCKS 的表和插入/删除锁定记录的方法,还有一种检查不存在的方法。
因此,如果多个进程尝试同时从不同的应用程序运行相同的代码,那么它不应该能够,因为数据库中将存在锁定记录,该锁定记录在作业开始运行之前被插入并在作业之后被删除已完成(一个 RUNNING 锁)
一旦完成,就会插入一个 LOGFILE_ARCHIVED 锁定记录,以便相同或不同的作业知道该日志文件已被归档,并且不会再次尝试归档它。
我在锁定文件中使用计算机名称,因为该进程可以随时在多台服务器/计算机上运行。
那么我可以采取哪些其他解决方案来解决这个问题?
我是否应该使用不同的方法来获取不会被锁定文件的东西阻止的日志文件内容(我不知道是什么在锁定,但是 this.Locked = True 应该防止任何内容被记录到归档作业期间的文件)但显然文件上的“锁定”高于我的代码。
这是在 Win 7 机器上用 C# .NET 4.5 编写的 Windows 服务。
感谢您的帮助。
【问题讨论】:
-
顺便说一句,函数 ReadFileString 是一个静态函数,它是使用 StreamReader 读取文件内容的包装器。它确实存在于项目中。
-
那是我运行它的时候。午夜过后。我还从数据库中获取了一条记录,说明在我尝试对日志文件执行任何操作以防并发进程尝试访问 DLL 之前,日志记录是否为 ON/OFF,该记录设置为 OFF。我该怎么做才能确保可以从文件中读取日志文件而不会被进程“锁定”呢?顺便说一句,我在这个归档过程中使用与我以前的工作完全相同的代码,并且每晚都很有效。事件查看器中可能存在一些 I/O 错误,但最终它可以完成工作并复制数据结束。
-
目前“记录”方法,将任何消息记录到文件的方法是使用 File.AppendAllText(LogFilePath, msg, Encoding.UTF8);其中 msg 是新的 msg + "\n" to b 添加到文件中。它在 Try/Catch 中。我是否应该使用其他方法来确保在我输出到它发布的文件后?
-
我还将对“Archive”方法的调用包装在 3 个 try/catch 中,并在它们之间增加时间的 thread.sleep。如果毕竟 3 它仍然无法运行,我会在 5 分钟后重试。
-
为什么你把你所有的cmets和我在这个问题下的问题的答案都删了?看来我只是在自言自语!!我不是疯了有人在这里写 cmets 但已经删除了它们!
标签: c# .net logging service locking