Loading

.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

容器部署,需要做以下几点:

  1. dockerfile中添加环境变量。
  2. 需要一个有写入权限的目录
  3. 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

运行

  1. 使用docker的方式启动应用程序后,在下图中显示了环境变量的值,这说明设置是成功的。

  2. 接下来调用我们抛异常的api后,就会看到容器虽然退出了,但是dump的还是产生了,我们也可以在文件中查看生成的dump文件。

注意事项

如果你在测试的过程没有成功,检测下环境变量和所使用的版本是否对应。

参与文献

  1. https://www.cnblogs.com/InCerry/p/how_to_automic_create_dump_when_app_crash.html
  2. https://github.com/dotnet/coreclr/blob/master/Documentation/botr/xplat-minidump-generation.md#configurationpolicy
posted @ 2024-01-11 19:01  一只小青蛙  阅读(186)  评论(0编辑  收藏  举报