簡體   English   中英

日志文件輪換 IOException

[英]Log File Rotation IOException

我有一個日志文件輪換功能,如下所示:

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

我已經在下面的評論中說明了,但很明顯,只有一個線程正在運行。 這是一項服務,所以它必須在一個單獨的線程中,但只有一個線程在運行。

編輯:根據您的評論,我已經嘗試了您的代碼並發現了您遇到的問題。 當你調用這一行File.Create(@"C:\\temp\\dataTransferErrorLog.txt"); 它返回從未關閉的FileStream 因此,您可以使用兩種方法。 首先,您需要將該FileStream分配給一個變量,並在FileStream上顯式調用Close() ,例如:

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

從您的堆棧跟蹤來看,此代碼中沒有發生異常。 在您的LogMessage函數中,您正在調用AppendText ,這就是它失敗的地方。 在代碼頂部(主應用程序入口點)添加一個異常處理程序並登錄(如,直接寫入文本文件或控制台,沒有花哨的日志記錄,只需獲取數據),異常的詳細信息將提供你更多的信息。

作為第二個建議, log4net是一個非常有用的日志庫。 它有一個內置的滾動文件附加程序。它易於配置和設置,並可通過NuGet 您可能需要考慮使用它。 很多產品都可以。

將 pdbs 與程序集一起部署,您將在堆棧跟蹤中獲得行號,這將使您能夠確定引發異常的位置。 你確實生成 pdbs 不是嗎?

它不在旋轉函數中。 對我來說,看起來你正在做旋轉,同時你想附加到文件(寫日志)所以它崩潰了。

但是發布異常消息,這將清除一切

我認為您正在嘗試用一個線程在日志中寫入一些內容,而另一個線程正在嘗試旋轉日志...

改變你的代碼就足夠了,以便更好地了解正在發生的事情

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。

他們的工作做得很好

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM