2

我有一个看起来像这样的日志文件轮换函数:

    private static void RotateLogs()
    {
        FileInfo LogFile = new FileInfo(@"C:\temp\dataTransferErrorLog.txt");

        if (LogFile.Exists && (LogFile.Length) >= 10 * 1048576)
        {
            Compress(LogFile);
            LogFile.Delete();
            File.Create(@"C:\temp\dataTransferErrorLog.txt");
        }
    }

    private static void Compress(FileInfo fi)
    {
        // Get the stream of the source file.
        using (FileStream inFile = fi.OpenRead())
        {
            // Prevent compressing hidden and 
            // already compressed files.
            if ((File.GetAttributes(fi.FullName)
                & FileAttributes.Hidden)
                != FileAttributes.Hidden & fi.Extension != ".gz")
            {
                string destFileName = fi.FullName.Substring(0, fi.FullName.LastIndexOf('.')) + System.DateTime.Now.ToString("yyyyMMddHHmm") + fi.FullName.Substring(fi.FullName.LastIndexOf('.')) + ".gz";
                // Create the compressed file.
                using (FileStream outFile =
                            File.Create(destFileName))
                {
                    using (GZipStream Compress =
                        new GZipStream(outFile,
                        CompressionMode.Compress))
                    {
                        // Copy the source file into 
                        // the compression stream.
                        inFile.CopyTo(Compress);
                    }
                }
            }
        }
    }

任何时候尝试轮换日志文件时都会引发 IOException。我认为它在尝试写入 .gz 文件时会引发异常,但我不确定。这是堆栈跟踪:

Framework Version: v4.0.30319
Description: The process was terminated due to an unhandled exception.
Exception Info: System.IO.IOException
Stack:
   at System.IO.__Error.WinIOError(Int32, System.String)
   at System.IO.FileStream.Init(System.String, System.IO.FileMode, System.IO.FileAccess, Int32, Boolean, System.IO.FileShare, Int32, System.IO.FileOptions, SECURITY_ATTRIBUTES, System.String, Boolean, Boolean)
   at System.IO.FileStream..ctor(System.String, System.IO.FileMode, System.IO.FileAccess, System.IO.FileShare, Int32, System.IO.FileOptions)
   at System.IO.StreamWriter.CreateFile(System.String, Boolean)
   at System.IO.StreamWriter..ctor(System.String, Boolean, System.Text.Encoding, Int32)
   at System.IO.StreamWriter..ctor(System.String, Boolean)
   at System.IO.File.AppendText(System.String)
   at XRayDataTransferService.XRayDataTransferService.LogMessage(System.String)
   at XRayDataTransferService.XRayDataTransferService.RunAgent()
   at System.Threading.ThreadHelper.ThreadStart_Context(System.Object)
   at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
   at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
   at System.Threading.ThreadHelper.ThreadStart()

有人可以确认它在尝试将压缩信息写入 .gz 文件时抛出异常,并告诉我导致它抛出异常的情况如何?

编辑

这是 LogMessage 函数。大多数情况下,这有效,唯一一次抛出异常是在轮换日志时。

static void LogMessage(string messageText)
    {
        string ErrorLogFileName = @"C:\temp\dataTransferErrorLog.txt";

        using (StreamWriter Log = File.AppendText(ErrorLogFileName))
        {
            try
            {
                Log.WriteLine("{0}: {1}", dateStamp, messageText);
            }
            catch { }
        }
    }

更新:

static void RunAgent()
    {
        while (!shutdown)
        {
            LogMessage("Starting data transfer...");
            errors = 0;

           // Do some data processing

            LogMessage("Finished running with " + errors.ToString() + " error(s).");

            RotateLogs();
        }
        shutdownSignal.Set();
    }

我已经在下面的评论中说明了,但很明显,只有一个线程在运行。这是一项服务,因此它必须位于单独的线程中,但只有一个线程在运行。

4

5 回答 5

2

编辑:根据您的评论,我已经尝试了您的代码并发现了您遇到的问题。当您调用此行时File.Create(@"C:\temp\dataTransferErrorLog.txt");,它会返回FileStream永远不会关闭的。因此,您可以使用两种方法。首先是您需要将其分配FileStream给一个变量并显式调用Close()类似FileStream

if (!LogFile.Exists)
{
        Compress(LogFile);
        LogFile.Delete();
        FileStream fs = File.Create(@"C:\Users\On\Documents\dataTransferErrorLog.txt");
        fs.Close();
}

或者更好的方法是甚至不在那里创建文件,因为稍后调用File.AppendText()将创建它不存在的文件。所以我建议你把你的方法做成RotateLogs这样:

private static void RotateLogs()
{
    FileInfo LogFile = new FileInfo(@"C:\temp\dataTransferErrorLog.txt");

    if (LogFile.Exists && (LogFile.Length) >= 10 * 1048576)
    {
         Compress(LogFile);
         LogFile.Delete();
    }
}
于 2012-11-16T15:09:52.730 回答
1

从您的堆栈跟踪中,此代码中没有发生异常。在您LogMessage正在调用的函数中AppendText,这就是它失败的地方。在代码顶部(主应用程序入口点)添加异常处理程序并登录(如直接写入文本文件或写入控制台,没有花哨的日志记录,只需获取数据),异常的详细信息将给出你更多的信息。

作为第二个建议,log4net是一个非常有用的日志库。它内置了一个滚动文件附加程序。它易于配置和设置,并可通过NuGet. 您可能要考虑使用它。很多产品都可以。

于 2012-11-16T14:38:36.420 回答
0

将您的 pdb 与您的程序集一起部署,您将在堆栈跟踪中获得行号,这将使您能够查明引发异常的位置。你会生成 pdbs 不是吗?

于 2012-11-16T14:34:16.743 回答
0

它不在旋转功能中。对我来说,看起来你正在轮换,同时你想追加到文件(写日志)所以它崩溃了。

但是发布异常消息,这将清除所有内容

于 2012-11-16T14:34:42.583 回答
0

我认为你正试图用一个线程在你的日志中写一些东西,而另一个线程正试图旋转日志......

更改您的代码就足够了,以便更好地了解正在发生的事情

static void LogMessage(string messageText)
{
    try
    {
        string ErrorLogFileName = @"C:\temp\dataTransferErrorLog.txt";

        using (StreamWriter Log = File.AppendText(ErrorLogFileName))
        {
            Log.WriteLine("{0}: {1}", dateStamp, messageText);
        }
     }
     catch(Exception) { throw; }
}

无论如何,您最好的选择是使用强大的日志库作为 log4net 或 NLog。

他们的工作做得很好

于 2012-11-16T14:49:00.770 回答