2013-06-05 18 views
7

Ứng dụng C# winforms 4.0 của tôi đã sử dụng trình viết luồng an toàn cho luồng để thực hiện thông tin ghi nhật ký, gỡ lỗi nội bộ. Khi ứng dụng của tôi mở ra, nó sẽ xóa tệp và tạo lại. Khi ứng dụng đóng, nó sẽ lưu tệp.Sử dụng StreamWriter để triển khai nhật ký cuộn và xóa từ đầu

Điều tôi muốn làm là sửa đổi ứng dụng của tôi để ứng dụng đó được thêm vào thay vì thay thế. Đây là một sửa chữa đơn giản.

Tuy nhiên, đây là câu hỏi của tôi:

Tôi muốn giữ tệp nhật ký của mình tối đa 10 megabyte. Ràng buộc của tôi sẽ đơn giản. Khi bạn đóng tệp, nếu tệp lớn hơn 10 megabyte, hãy cắt bớt 10% đầu tiên.

Có cách nào 'tốt hơn' thì làm như sau:

  1. Đóng tệp
  2. Kiểm tra nếu tập tin là> 10 meg
  3. Nếu vậy, hãy mở tập tin
  4. Phân tích các toàn bộ điều
  5. Cull 10% đầu tiên
  6. Viết tệp ra sau
  7. Đóng

Chỉnh sửa: tốt, tôi đã tự mình chuyển sang Log4Net là một điều tốt, nhưng thời gian cần để tìm hiểu thư viện mới và di chuyển tất cả các báo cáo nhật ký của tôi (hàng ngàn) không phải là thời gian hiệu quả cho việc tăng cường nhỏ mà tôi đã cố gắng thực hiện.

private static void PerformFileTrim(string filename) 
    { 
    var FileSize = Convert.ToDecimal((new System.IO.FileInfo(filename)).Length); 

    if (FileSize > 5000000) 
    { 
     var file = File.ReadAllLines(filename).ToList(); 
     var AmountToCull = (int)(file.Count * 0.33); 
     var trimmed = file.Skip(AmountToCull).ToList(); 
     File.WriteAllLines(filename, trimmed); 
    } 
    } 
+5

Và việc sử dụng thư viện cụ thể được viết để ghi nhật ký đã triển khai chức năng này thì sao? (Log4Net xuất hiện trong đầu) – Steve

+0

Tôi chưa dành thời gian để nhìn vào Log4Net. Cho đến giờ, lớp soạn thảo đơn giản của tôi đã làm rất tốt. Nếu Log4Net cho phép nhật ký 'lăn' tôi đang tìm kiếm, thì đó là giải pháp tôi nên sử dụng. – greggorob64

+0

Người đọc trong tương lai: '" ... [để] di chuyển tất cả các báo cáo đăng nhập (nghìn) của tôi không hiệu quả về thời gian "- và đây là lý do tại sao chúng tôi dựa vào tiêm phụ thuộc và giao diện. :) Một thiết kế tốt hơn, hãy tiêm một cá thể 'ILogger' (ví dụ) vào tất cả các lớp cần đăng nhập - hoặc thậm chí chỉ có một lớp/hàm khai thác chính duy nhất - sẽ cho phép bạn sửa đổi tất cả chức năng ghi nhật ký ở một vị trí khi thay đổi yêu cầu ghi nhật ký . – brichins

Trả lời

1

Tôi đã xem qua win32 api và tôi thậm chí không chắc chắn có thể thực hiện điều này với các cuộc gọi win32 vfs gốc, không bao giờ qua .Net.

Về giải pháp duy nhất tôi có thể sẽ sử dụng các tệp được ánh xạ bộ nhớ và di chuyển dữ liệu theo cách thủ công, mà .Net dường như hỗ trợ như .Net 4.0.

Memory Mapped Files

+0

bộ nhớ ánh xạ tập tin là một overkill cho các tập tin 10mb – VladL

6

tôi nghiên cứu này một lần và không bao giờ đưa ra bất cứ điều gì, nhưng tôi có thể cung cấp cho bạn lên kế hoạch B ở đây:

tôi sử dụng lựa chọn dưới đây để giữ tối đa là 3 file log. Lúc đầu, tệp nhật ký 1 được tạo và nối thêm vào. Khi nó vượt quá maxsize, log 2 và sau đó log 3 được tạo. Khi nhật ký 3 quá lớn, nhật ký 1 sẽ bị xóa và các nhật ký còn lại sẽ bị đẩy xuống ngăn xếp.

string[] logFileList = Directory.GetFiles(Path.GetTempPath(), "add_all_*.log", SearchOption.TopDirectoryOnly); 
if (logFileList.Count() > 1) 
{ 
    Array.Sort(logFileList, 0, logFileList.Count()); 
} 

if (logFileList.Any()) 
{ 
    string currFilePath = logFileList.Last(); 
    string[] dotSplit = currFilePath.Split('.'); 
    string lastChars = dotSplit[0].Substring(dotSplit[0].Length - 3); 
    ctr = Int32.Parse(lastChars); 
    FileInfo f = new FileInfo(currFilePath); 

    if (f.Length > MaxLogSize) 
    { 
     if (logFileList.Count() > MaxLogCount) 
     { 
      File.Delete(logFileList[0]); 
      for (int i = 1; i < MaxLogCount + 1; i++) 
      { 
       Debug.WriteLine(string.Format("moving: {0} {1}", logFileList[i], logFileList[i - 1])); 
       File.Move(logFileList[i], logFileList[i - 1]); // push older log files back, in order to pop new log on top 
      } 
     } 
     else 
     { 
      ctr++; 
     } 
    } 
} 
+0

Tôi đã phải thực hiện một vài sửa đổi để có được điều này để chạy cho tôi - Tôi đã thêm nó như là một câu trả lời riêng biệt vì ràng buộc kích thước ... – user3902302

2

này bắt nguồn từ câu trả lời của bigtech:

private static string RollLogFile() 
    { 
     string path = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); 
     string appName = Path.GetFileNameWithoutExtension(Environment.GetCommandLineArgs()[0]); 
     string wildLogName = string.Format("{0}*.log",appName); 

     int fileCounter = 0; 
     string[] logFileList = Directory.GetFiles(path, wildLogName, SearchOption.TopDirectoryOnly); 
     if (logFileList.Length > 0) 
     { 
      Array.Sort(logFileList, 0, logFileList.Length); 
      fileCounter = logFileList.Length - 1; 
      //Make sure we apply the MaxLogCount (but only once to reduce the delay) 
      if (logFileList.Length > MaxLogCount) 
      { 
       //Too many files - remove one and rename the others 
       File.Delete(logFileList[0]); 
       for (int i = 1; i < logFileList.Length; i++) 
       { 
        File.Move(logFileList[i], logFileList[i - 1]); 
       } 
       --fileCounter; 
      } 

      string currFilePath = logFileList[fileCounter]; 
      FileInfo f = new FileInfo(currFilePath); 
      if (f.Length < MaxLogSize) 
      { 
       //still room in the current file 
       return currFilePath; 
      } 
      else 
      { 
       //need another filename 
       ++fileCounter;     
      } 

     } 
     return string.Format("{0}{1}{2}{3:00}.log", path, Path.DirectorySeparatorChar, appName, fileCounter); 
    } 

Cách sử dụng:

string logFileName = RollLogFile(); 
using (StreamWriter sw = new StreamWriter(logFileName, true)) 
{ 
    sw.AutoFlush = true; 
    sw.WriteLine(string.Format("{0:u} {1}", DateTime.Now, message)); 
} 
2

Các giải pháp ở đây không thực sự làm việc cho tôi. Tôi lấy câu trả lời của user3902302, một lần nữa dựa trên câu trả lời của bigtech và viết một lớp hoàn chỉnh. Ngoài ra, tôi không sử dụng StreamWriter, bạn có thể thay đổi một dòng (AppendAllText chống lại tương đương StreamWrite).

Có rất ít lỗi khi xử lý (ví dụ: thử lại truy cập khi không thành công, mặc dù khóa sẽ bắt tất cả truy cập đồng thời nội bộ).

Điều này có thể là đủ đối với một số người đã phải sử dụng một giải pháp lớn như log4net hoặc đăng nhập trước đó. (Và log4net RollingAppender thậm chí không thread-safe, chương trình này là :).)

public class RollingLogger 
{ 
    readonly static string LOG_FILE = @"c:\temp\logfile.log"; 
    readonly static int MaxRolledLogCount = 3; 
    readonly static int MaxLogSize = 1024; // 1 * 1024 * 1024; <- small value for testing that it works, you can try yourself, and then use a reasonable size, like 1M-10M 

    public static void LogMessage(string msg) 
    { 
     lock (LOG_FILE) // lock is optional, but.. should this ever be called by multiple threads, it is safer 
     { 
      RollLogFile(LOG_FILE); 
      File.AppendAllText(LOG_FILE, msg + Environment.NewLine, Encoding.UTF8); 
     } 
    } 

    private static void RollLogFile(string logFilePath) 
    { 
     try 
     { 
      var length = new FileInfo(logFilePath).Length; 

      if (length > MaxLogSize) 
      { 
       var path = Path.GetDirectoryName(logFilePath); 
       var wildLogName = Path.GetFileNameWithoutExtension(logFilePath) + "*" + Path.GetExtension(logFilePath); 
       var bareLogFilePath = Path.Combine(path, Path.GetFileNameWithoutExtension(logFilePath)); 
       string[] logFileList = Directory.GetFiles(path, wildLogName, SearchOption.TopDirectoryOnly); 
       if (logFileList.Length > 0) 
       { 
        // only take files like logfilename.log and logfilename.0.log, so there also can be a maximum of 10 additional rolled files (0..9) 
        var rolledLogFileList = logFileList.Where(fileName => fileName.Length == (logFilePath.Length + 2)).ToArray(); 
        Array.Sort(rolledLogFileList, 0, rolledLogFileList.Length); 
        if (rolledLogFileList.Length >= MaxRolledLogCount) 
        { 
         File.Delete(rolledLogFileList[MaxRolledLogCount - 1]); 
         var list = rolledLogFileList.ToList(); 
         list.RemoveAt(MaxRolledLogCount - 1); 
         rolledLogFileList = list.ToArray(); 
        } 
        // move remaining rolled files 
        for (int i = rolledLogFileList.Length; i > 0; --i) 
         File.Move(rolledLogFileList[i - 1], bareLogFilePath + "." + i + Path.GetExtension(logFilePath)); 
        var targetPath = bareLogFilePath + ".0" + Path.GetExtension(logFilePath); 
        // move original file 
        File.Move(logFilePath, targetPath); 
       } 
      } 
     } 
     catch (Exception ex) 
     { 
      System.Diagnostics.Debug.WriteLine(ex.ToString()); 
     } 
    } 
} 

chỉnh sửa:
Vì tôi chỉ nhận thấy rằng bạn hỏi một câu hỏi hơi khác nhau: đường dây của bạn nên thay đổi rất nhiều về kích thước , đây sẽ là một biến thể (rằng, trong 90% trường hợp không cải thiện so với bạn, và có thể nhanh hơn một chút, cũng đã giới thiệu một lỗi không được giải quyết mới (\ n không có mặt)):

private static void PerformFileTrim(string filename) 
    { 
     var fileSize = (new System.IO.FileInfo(filename)).Length; 

     if (fileSize > 5000000) 
     { 
      var text = File.ReadAllText(filename); 
      var amountToCull = (int)(text.Length * 0.33); 
      amountToCull = text.IndexOf('\n', amountToCull); 
      var trimmedText = text.Substring(amountToCull + 1); 
      File.WriteAllText(filename, trimmedText); 
     } 
    } 
2

Chức năng này sẽ cho phép bạn xoay nhật ký của mình dựa trên các ngày trong tuần. Lần đầu tiên y ứng dụng của chúng tôi sẽ khởi chạy vào thứ hai, sẽ kiểm tra bất kỳ mục nhập hiện có nào cho Ngày Thứ Hai, nếu chưa được khởi tạo cho hôm nay sẽ loại bỏ các mục cũ và khởi tạo lại tệp mới. Về sau cho toàn bộ ngày hôm đó, tệp sẽ tiếp tục chắp thêm văn bản vào cùng một tệp nhật ký.

Vì vậy, tổng số 7 tệp nhật ký sẽ được tạo. debug-Mon.txt, debog-Tue.txt ...

nó cũng sẽ thêm tên phương thức thực sự đã ghi nhật ký thư cùng với ngày giờ. rất hữu ích cho mục đích sử dụng chung.

private void log(string text) 
     { 
      string dd = DateTime.Now.ToString("yyyy-MM-dd"); 
      string mm = DateTime.Now.ToString("ddd"); 

      if (File.Exists("debug-" + mm + ".txt")) 
      { 
       String contents = File.ReadAllText("debug-" + mm + ".txt"); 


       if (!contents.Contains("Date: " + dd)) 
       { 
        File.Delete("debug-" + mm + ".txt"); 
       } 
      } 

      File.AppendAllText("debug-" + mm + ".txt", "\r\nDate: " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:s") + " =>\t" + new System.Diagnostics.StackFrame(1, true).GetMethod().Name + "\t" + text); 

     } 
Các vấn đề liên quan