.net ocre 程序崩溃自动dump在多平台中的实现
前言
经常排查问题的朋友都知道,我们在遇到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文件。
注意事项
如果你在测试的过程没有成功,检测下环境变量和所使用的版本是否对应。