前言
經常排查問題的朋友都知道,我們在遇到CPU或者記憶體高的時候,有時會生成dump檔案來做分析。但是我們也會遇到一些場景,應用程式直接崩潰退出,這個時候我們已經沒法使用常規方式dump了,因為整個程序樹已經退出了,那麼我們有沒有辦法讓系統自動做dump,答案是肯定的:讓系統在程式崩潰時自動建立Dump。
無論是 .net framework還是 .net core 專案,都支援應用程式崩潰時生成轉儲,本篇我們重點看下 .net core應用在docker、macOS(lunix類似)環境下是如何實現的。
配置
設定一些變數引數:
- COMPlus_DbgEnableMiniDump 或 DOTNET_DbgEnableMiniDump: 如果設定為 1,則發生故障時啟用CoreDump生成。預設值為:0
- COMPlus_DbgMiniDumpType 或 DOTNET_DbgMiniDumpType: 要收集的轉儲型別。 有關詳細資訊,請看下文的說明。預設值為:2
- COMPlus_DbgMiniDumpName 或 DOTNET_DbgMiniDumpName: 寫入轉儲的檔案路徑。 確保執行 dotnet 程序的使用者具有指定目錄的寫入許可權。預設值為:/tmp/coredump.
- COMPlus_CreateDumpDiagnostics 或 DOTNET_CreateDumpDiagnostics: 如果設定為 1,則啟用轉儲程序的診斷日誌記錄。預設值為:0
- COMPlus_EnableCrashReport 或 DOTNET_EnableCrashReport:(需要 .NET 6 或更高版本,目前僅Linux和MacOS可用)如果設為 1,執行時會生成 JSON 格式的故障報表,其中包括有關故障應用程式的執行緒和堆疊幀的資訊。 故障報表名稱是追加了 .crashreport.json 的轉儲路徑/名稱。
- COMPlus_CreateDumpVerboseDiagnostics 或 DOTNET_CreateDumpVerboseDiagnostics:(需要 .NET 7 或更高版本)如果設為 1,則啟用轉儲程序的詳細診斷日誌記錄。
- COMPlus_CreateDumpLogToFile 或 DOTNET_CreateDumpLogToFile:(需要 .NET 7 或更高版本)應寫入診斷訊息的檔案路徑。 如果未設定,則將診斷訊息寫入故障應用程式的控制檯。
對於這些環境變數,.NET 7 標準化字首 DOTNET_,而不是 COMPlus_。 但是,COMPlus_ 字首仍將繼續正常工作。 如果使用的是早期版本的 .NET 執行時,則環境變數仍應該使用 COMPlus_ 字首。
關於DOTNET_DbgMiniDumpType的說明如下所示:
1: Mini 小型Dump,其中包含模組列表、執行緒列表、異常資訊和所有堆疊。
2: Heap 大型且相對全面的Dump,其中包含模組列表、執行緒列表、所有堆疊、異常資訊、控制代碼資訊和除對映影像以外的所有記憶體。
3: Triage 與 Mini 相同,但會刪除個人使用者資訊,如路徑和密碼。
4: Full 最大的轉儲,包含所有記憶體(包括模組映像)。
一般情況下,我們會配置下面的環境變數:
DOTNET_DbgEnableMiniDump = 1
DOTNET_DbgMiniDumpName = [有許可權的Path目錄]
DOTNET_CreateDumpDiagnostics = 1
DOTNET_EnableCrashReport = 1
用一段程式碼試試
由於筆者所使用的是 .net 6.0,所以這裡我們先在程式啟動的時候列印出字首為COMPlus_
的環境變數的值。(這一段不要省,因為很多時候,你以為設定了環境變數,但是其實沒生效。)
foreach (DictionaryEntry environmentVariable in Environment.GetEnvironmentVariables())
{
if (environmentVariable.Key.ToString()?.StartsWith("COMPlus") == true)
{
Console.WriteLine($"{environmentVariable.Key}={environmentVariable.Value}");
}
}
然後我們在Thread中丟擲一個異常,這會導致應用程式退出或者容器退出。
public static void Bar()
{
var thread = new Thread(() => throw new Exception("Crash"));
thread.Start();
}
配置
macOS
注意:.net5 開始才支援macOS的dump。
可以在powershell中執行命令用於測試,注意這種方式設定的環境變數僅限於當前會話中有效,設定完成後啟動你的應用即可。
$env:DOTNET_DbgEnableMiniDump = 1
$env:DOTNET_DbgMiniDumpType = 4
$env:DOTNET_CreateDumpDiagnostics = 1
$env:DOTNET_EnableCrashReport = 1
$env:DOTNET_DbgMiniDumpName = "有許可權的路徑"
docker
容器部署,需要做以下幾點:
- dockerfile中新增環境變數。
- 需要一個有寫入許可權的目錄
- docker 容器中的核心轉儲生成需要 ptrace 功能(--cap-add=SYS_PTRACE 或 --privileged)
docker中需要把目錄掛載到宿主機,否則容器退出,dump檔案也會刪除。
下方是一個dockerfile示例,以作參考。
FROM mcr.microsoft.com/dotnet/aspnet:6.0
COPY . /publish
WORKDIR /publish
EXPOSE 5100
ENV ASPNETCORE_URLS http://*:5100
# 設定環境變數
ENV COMPlus_DbgEnableMiniDump=1
ENV COMPlus_CreateDumpDiagnostics=1
ENV COMPlus_DbgMiniDumpType=4
ENV COMPlus_DbgMiniDumpName=/publish/dump/dumptest.dmp
ENV COMPlus_EnableCrashReport=1
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
RUN echo 'Asia/Shanghai' > /etc/timezone
# 建立資料夾組給許可權
RUN mkdir -p /publish/dump/ && chmod 777 /publish/dump/
CMD ["dotnet", "WebApplication7.dll"]
在建立容器時,帶引數--cap-add=SYS_PTRACE
使我們容器擁有相應的許可權
sudo docker run --cap-add=SYS_PTRACE -d --name apitest -p 5101:5100 apitest\:v1
執行
-
使用docker的方式啟動應用程式後,在下圖中顯示了環境變數的值,這說明設定是成功的。
-
接下來呼叫我們拋異常的api後,就會看到容器雖然退出了,但是dump的還是產生了,我們也可以在檔案中檢視生成的dump檔案。
注意事項
如果你在測試的過程沒有成功,檢測下環境變數和所使用的版本是否對應。
參與文獻
- https://www.cnblogs.com/InCerry/p/how_to_automic_create_dump_when_app_crash.html
- https://github.com/dotnet/coreclr/blob/master/Documentation/botr/xplat-minidump-generation.md#configurationpolicy