首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

C# 將日誌寫入文字檔:完整實作與最佳實踐

     編輯:關於C#

基礎實作


using System;
using System.IO;
using System.Text;

public static class LogHelper
{
    /// 
    /// 寫入文字日誌檔
    /// 
    /// 日誌內容
    /// 檔案名稱(不含副檔名與日期)
    /// 輸出錯誤訊息
    /// 是否成功
    public static bool WriteLog(string content, string fileName, out string errorMsg)
    {
        errorMsg = string.Empty;
        StreamWriter writer = null;
        
        try
        {
            // 檔案命名:yyyy-MM-dd_FileName.txt
            var dateStr = DateTime.Now.ToString("yyyy-MM-dd");
            var fullPath = Path.Combine(@"D:\Log", $"{dateStr}_{fileName}.txt");
            
            // 確保目錄存在
            var dir = Path.GetDirectoryName(fullPath);
            if (!Directory.Exists(dir)) Directory.CreateDirectory(dir);
            
            // 判斷檔案是否存在決定是否附加
            var append = File.Exists(fullPath);
            writer = new StreamWriter(fullPath, append, Encoding.UTF8);
            
            var timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
            writer.WriteLine($"<{timestamp}> {content}");
            return true;
        }
        catch (IOException ex)
        {
            errorMsg = ex.Message;
            return false;
        }
        finally
        {
            writer?.Close();
        }
    }
}

改進版:非同步、高效能、自動輪替


using System;
using System.IO;
using System.Text;
using System.Threading.Tasks;

public sealed class AsyncLogWriter : IDisposable
{
    private readonly string _logDir;
    private readonly string _baseName;
    private StreamWriter _writer;
    private string _currentDate;
    private readonly object _lock = new object();

    public AsyncLogWriter(string logDir, string baseName)
    {
        _logDir = logDir;
        _baseName = baseName;
        Directory.CreateDirectory(_logDir);
    }

    public async Task WriteAsync(string content)
    {
        var now = DateTime.Now;
        var dateStr = now.ToString("yyyy-MM-dd");
        var timestamp = now.ToString("HH:mm:ss.fff");
        var line = $"[{dateStr} {timestamp}] {content}";

        lock (_lock)
        {
            // 日期變更時切換檔案
            if (_currentDate != dateStr)
            {
                _writer?.Dispose();
                var path = Path.Combine(_logDir, $"{dateStr}_{_baseName}.log");
                _writer = new StreamWriter(path, true, Encoding.UTF8) { AutoFlush = true };
                _currentDate = dateStr;
            }
            _writer.WriteLine(line);
        }
        await Task.CompletedTask; // 保持非同步簽名,實際寫入已由 AutoFlush 處理
    }

    public void Dispose() => _writer?.Dispose();
}

使用範例


// 簡單同步版
LogHelper.WriteLog("使用者登入成功", "Auth", out var err);

// 非同步高效能版(建議單例或 DI 注入)
var logger = new AsyncLogWriter(@"D:\Logs", "App");
await logger.WriteAsync("訂單建立: OrderId=12345");
await logger.WriteAsync("付款完成: Amount=999");
logger.Dispose(); // 程式結束時釋放

最佳實踐清單

項目建議
編碼統一 UTF-8(Encoding.UTF8),避免中文亂碼
時間格式含毫秒 yyyy-MM-dd HH:mm:ss.fff,利於追蹤順序
檔案輪替按日期/大小分割,避免單一檔案過大
目錄權限確保執行身分對日誌目錄有寫入權限
例外處理日誌寫入失敗不應拋出影響主流程,記錄到 Console/EventLog 為備援
結構化日誌生產環境建議 Serilog/NLog + JSON 格式,支援 ELK/Seq 分析
非同步高頻寫入使用非同步或批次寫入,避免阻塞主執行緒

進階:結構化日誌範例


// Serilog 設定(Program.cs)
Log.Logger = new LoggerConfiguration()
    .MinimumLevel.Information()
    .WriteTo.File(@"D:\Logs\App-.log", 
        rollingInterval: RollingInterval.Day,
        outputTemplate: "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff} {Level:u3}] {Message:lj}{NewLine}{Exception}")
    .CreateLogger();

// 使用
Log.Information("訂單 {OrderId} 建立,金額 {Amount}", 12345, 999);
Log.Error(ex, "付款失敗 OrderId={OrderId}", 12345);

從簡單的 StreamWriter 到企業級結構化日誌,根據專案規模與需求選擇適合的方案,核心原則:**可靠、可查、不影響主流程效能**。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved