建立健全的錯誤記錄機制包含三大支柱:
Global.asax Application_Error 攔截所有未處理例外。web.config <customErrors> 導向自訂錯誤頁,避免暴露敏感資訊。using System;
using System.IO;
using System.Web;
using System.Globalization;
public static class Logger
{
public static void WriteError(string errorMessage)
{
try
{
// 每日一檔:yyMMdd.txt (如 240115.txt)
var fileName = DateTime.Today.ToString("yyMMdd") + ".txt";
var virtualPath = "~/Error/" + fileName;
var physicalPath = HttpContext.Current.Server.MapPath(virtualPath);
// 確保目錄存在
var dir = Path.GetDirectoryName(physicalPath);
if (!Directory.Exists(dir)) Directory.CreateDirectory(dir);
// 追加寫入,自動建立檔案
using (var sw = File.AppendText(physicalPath))
{
sw.WriteLine("\r\n--- Log Entry ---");
sw.WriteLine(DateTime.Now.ToString(CultureInfo.InvariantCulture));
sw.WriteLine(errorMessage);
sw.WriteLine(new string('_', 60));
}
}
catch (Exception ex)
{
// 寫入失敗最後防線:輸出到系統診斷追蹤,避免遞迴
System.Diagnostics.Trace.TraceError($"Logger.WriteError 失敗: {ex}");
}
}
}
void Application_Error(object sender, EventArgs e)
{
var ex = Server.GetLastError().GetBaseException(); // 取得根本原因
var ip = Request.UserHostAddress;
var url = Request.Url.ToString();
var msg = ex.Message;
var logEntry = $"IP【{ip}】{Environment.NewLine}" +
$"URL【{url}】{Environment.NewLine}" +
$"Message【{msg}】{Environment.NewLine}" +
$"StackTrace【{ex.StackTrace}】";
Logger.WriteError(logEntry);
// 可選:發送郵件通知管理員、記錄到資料庫等
// 清除錯誤,避免 ASP.NET 預設黃色死機畫面 (由 customErrors 接管導向)
Server.ClearError();
}
<system.web>
<customErrors mode="RemoteOnly" defaultRedirect="~/Error/GenericErrorPage.htm">
<!-- 可針對特定狀態碼客製化 -->
<error statusCode="404" redirect="~/Error/404.htm" />
<error statusCode="500" redirect="~/Error/500.htm" />
</customErrors>
<!-- 開發時期建議 Off 以看詳細錯誤,上線改 RemoteOnly 或 On -->
</system.web>
<!DOCTYPE html>
<html><head><title>系統發生錯誤</title>
<style>body{font-family:sans-serif;max-width:600px;margin:3rem auto;padding:1rem;text-align:center;} .code{font-family:monospace;background:#f4f4f4;padding:.2rem .5rem;border-radius:4px;}</style></head><body>
<h1>😞 系統暫時無法處理您的請求</h1>
<p>我們已記錄此錯誤 (參考代碼: <%= DateTime.Now.Ticks %>) 並通知技術團隊儘快處理。</p>
<p><a href="javascript:history.back()">返回上一頁</a> | <a href="/>回首頁</a></p>
</body></html>
| 維度 | 建議做法 | 工具/套件 |
|---|---|---|
| 結構化查詢 | 改寫 JSON 格式或直接寫入資料庫 (SQL/Elasticsearch) | Serilog, NLog, log4net |
| 即時告警 | 整合 Email/Slack/DingTalk Webhook 於 WriteError 例外處理中 | FluentEmail, WebhookClient |
| 效能與非阻塞 | 使用非同步寫入或背景佇列 (Channel/BlockingCollection) | System.Threading.Channels |
| 敏感資料過濾 | 記錄前移除密碼、Token、信用卡號等 (GDPR/個資法遵循) | 自訂 Scrubber / Serilog Enrichers |
| 雲端部署 | 輸出到 stdout/stderr,由容器日誌驅動程式收集 (Docker/K8s) | Serilog.Sinks.Console |
WriteError 內部拋出例外再呼叫自己 → StackOverflow。務必用 Trace.TraceError 或寫入 Windows Event Log 作為最後防線。~/Error/ 目錄寫入權限。這套機制輕量、零依賴、易部署,適合中小型專案快速落地;大型系統建議直接採用成熟記錄框架 (Serilog/NLog) 並整合集中式日誌平台。