BUGTRAP for WIN32/64 & .NET开发者指南

1、前言

前段时间,我正在开发一个具有相当复杂逻辑的多层应用程序。该应用程序正在处理医疗信息,在任何情况下正确同步数据都很重要。我添加了额外的代码以使应用程序尽可能稳定,添加了自动备份和自我恢复。您认为它解决了所有问题吗?- 不,我仍在寻找一种工具来处理客户远程看到的问题。如果我住在地球的另一端,我该如何帮助他们并调试问题?最终,我找到了 Jim Crafton 的优秀文章,该文章介绍了一种能够拦截未处理错误的工具。那是一个解决方案!不幸的是,最初的 BlackBox 是不可自定义的,它不支持小型转储文件、Unicode 字符串,并且它没有任何服务器。尽管存在这些限制,但这是一个很好的起点,因为我确切地知道我需要什么样的工具。我开始研究自己的工具,希望能做出灵活、可定制和强大的解决方案。

2、详情

通常,收到客户的消息说您的程序不起作用是非常令人沮丧的。大多数用户可能不会让您知道应用程序中哪些内容不正确以及哪段代码出错。Windows 具有用于未处理错误的内置处理程序,但是当客户端发生错误时,此默认处理程序可能毫无用处,因为您很少希望将错误报告发送给 Microsoft:

BugTrap 通过覆盖默认错误处理程序来解决此问题。BugTrap 收集错误详细信息,例如地址、调用堆栈和计算机环境。还可以使用内置或外部日志记录函数将任意数量的自定义日志文件和其他信息添加到默认错误报告中。BugTrap 可以将错误报告保存在磁盘上,或者通过电子邮件、HTTP 或基于快速的低级 TCP 网络协议自动将错误报告发送到开发人员的计算机。BugTrap 服务器会自动管理错误报告存储库,并通知开发人员新的错误。

BugTrap 将错误描述存储在日志和小型转储文件中。小型转储文件可以在 Microsoft Visual Studio .NET 和 WinDbg 中打开。BugTrap 包还包括 CrashExplorer 实用程序,它可以从 MAP 和 PDB 文件中提取符号信息。有一个用于 .NET 应用程序的特殊 BugTrap 版本。.NET 版本可以处理纯 .NET 应用程序中的异常,也可以处理用 C++ 编写的混合 .NET 组合(托管/非托管组合)。

3 、基于Win32/64的BugTrap

3.1 向 Win32/64 应用程序添加 BugTrap

BugTrap 作为动态链接库 (DLL) 重新分发。BugTrap DLL 有两个版本可用:ANSI 版本和 Unicode 版本。

建议在面向 Windows NT/2000/ XP/Vista 平台的新应用程序中使用 Unicode 字符串。Unicode 应用程序不仅可以更好地处理国家字符集,而且速度也会更快。例如,BugTrap 以 UTF-8 格式对报告和日志文件进行编码。虽然 Unicode 和 UTF-8 编码字符之间存在直接且非常简单的映射,但 ANSI 字符串需要与 Unicode 进行额外的转换。这些转换会影响 XML 解析器、日志生成器和网络通信的性能。

下面的代码为 Win32/64 应用程序添加了 BugTrap 支持:

#include "BugTrap.h"
#pragma comment(lib, "BugTrap.lib") // Link to ANSI DLL
// #pragma comment(lib, "BugTrapU.lib") // Link to Unicode DLL
static void SetupExceptionHandler()
{
BT_InstallSehFilter();
BT_SetAppName(_T("Your application name"));
BT_SetSupportEMail(_T("your@email.com"));
BT_SetFlags(BTF_DETAILEDMODE | BTF_EDITMAIL);
BT_SetSupportServer(_T("localhost"), 9999);
BT_SetSupportURL(_T("http://www.your-web-site.com"));
}

SetupExceptionHandler() 函数可以从 InitInstance() 或 main() 函数调用,具体取决于应用程序的类型。

注意:

如果您的应用程序包含版本信息块,则可以省略 BT_SetAppName()和 BT_SetAppVersion()调用。BugTrap 可以从应用程序资源中检索应用程序名称和版本号。

3.2 重新分发 Win32/64 的 BugTrap

BugTrap 与 MS Windows 98/Me/NT/2000/XP/Vista 兼容。它需要在 Windows NT 4.0 上安装 MS Internet Explorer 4.0 的 shlwapi.dll。Windows 98/Me 和 Windows 2000/XP 已经具有所需的系统库。

BugTrap 使用 DbgHelp 库,该库作为 dbghelp.dll 重新分发。此 DLL 包含在 MS Windows 2000 及更高版本中。要在早期系统(如 Windows NT 4.0 或 Windows 98)上使用此 DLL,应将 DLL 与应用程序一起重新分发dbghelp.dll。要获取最新版本的 dbghelp.dll,请下载适用于 Windows 的调试工具。建议将最新版本的 dbghelp.dll 与 BugTrap DLL 放在同一个文件夹中,否则某些功能可能会被禁用。BugTrap 始终尝试从其文件夹中加载最新版本的 dbghelp.dll。如果在该文件夹中找不到dbghelp.dll,则会尝试从 Windows 系统文件夹加载dbghelp.dll。

3.3 Win32/64 应用程序的错误分析

通常,希望从错误地址中获取源文件名、函数名称和行号信息,因为这些信息可以大大简化进一步的错误分析和更正。

有几种方法可以获取此信息:

  • PDB 文件中的符号信息(如果可用);
  • 小型转储文件;
  • 执行事后 MAP 和 PDB 文件分析的实用程序。

让我们讨论每种方法:

3.3.1 符号信息和 PDB 文件

程序数据库 (PDB)文件包含调试和项目状态信息,允许增量链接程序的 Debug 配置。使用 /ZI 或 /Zi 编译 C/C++ 程序或使用 /debug 编译 Visual Basic/C# .NET 程序时,将创建 PDB 文件。

BugTrap 在遇到问题时自动使用 PDB 文件(如果可用)。PDB 文件必须与 EXE 文件位于同一目录中才能找到。当 BugTrap 找到合适的 PDB 文件时,它会自动在主窗口中显示调用堆栈条目的源文件名、函数名称和行号。如果在客户的计算机上找不到应用程序的 PDB 文件,则 BugTrap 将显示没有符号信息的十六进制地址。这些地址稍后可以在开发人员的计算机上进行分析。PDB 文件中的调试信息不会影响程序的大小和速度,Visual Studio 只会在 EXE 文件中保存 PDB 文件的路径。您可以在项目中为 Release configuration 启用 PDB 文件生成,并将 PDB 文件与程序 EXE 文件一起重新分发给您的客户。

但是,PDB 文件有几个缺点:

  1. 它们非常大,例如,300KB 应用程序的 PDB 文件可能需要 3MB 磁盘空间;
  2. 尽管 PDB 文件不包含应用程序源代码,但许多开发人员不会将 PDB 文件与应用程序一起重新分发,因为 PDB 文件可能会简化逆向工程。

通常,最好将 PDB 文件重新分发给应用程序测试人员和质量保证人员,但不要在公开版本中包含 PDB 文件。

希望不必为了利用这项技术而将 PDB 文件与应用程序一起重新分发。CrashExplorer 可以从 PDB 文件中提取符号信息,并将其与开发人员计算机上的原始错误日志合并。可以存储 PDB 文件
本地用于所有公共版本,并在以后用于生成用户可读的错误报告。
以下步骤为 Release configuration 启用 PDB 文件:

  1. 在 “Project Settings” 对话框中选择 Release configuration;
  2. 在 “C/C++General” 选项卡上选择调试信息的 “Program Database” 格式;
  3. 启用“Generate Debug Info”选项。

请使用这些图片作为参考:

注意:

如果您的应用程序动态链接到 MFC,则即使 BugTrap 可以访问应用程序的 PDB 文件,也可能在 BugTrap 堆栈跟踪窗口中看不到 MFC 函数名称和行号。相反,您可能会注意到 OrdinalXXX() 形式的多个条目。这是因为应用程序的 PDB 文件不包含 MFC 类的符号信息。通过将 MFC 的 PDB 文件从 System32 文件夹复制到应用程序的文件夹,或者将项目静态链接到 MFC,可以解决此问题。但是,即使 MFC 的符号信息不可用,它仍然可以从小型转储文件或通过运行 CrashExplorer 进行还原。

3.3.2 小型转储文件

BugTrap 可以生成用户模式小型转储文件,其中包含故障转储文件中包含的有用信息子集。BugTrap 可以非常快速有效地创建小型转储文件,因为小型转储文件很小,因此可以通过 Internet 将其发送给应用程序的技术支持。小型转储文件包含的信息不如完整故障转储文件多,但它包含的信息足以执行基本调试操作。若要读取小型转储文件,必须具有可用于调试器的二进制文件和符号文件。小型转储文件不需要客户计算机上的 PDB 文件,但您应该将 PDB 文件保留在开发人员的计算机上,以便在调试器中进一步进行错误分析。小型转储文件可以在 WinDbg 中进行分析,WinDbg 作为 Windows 调试工具的一部分或在 Visual Studio .NET 中重新分发。小型转储文件为在开发人员的计算机上重现客户端错误提供了最佳选项。

小型转储文件有几个缺点:

  • 与 BugTrap 生成的默认文本输出相比,小型转储文件相对较大。BugTrap 会存档小型转储文件以减小生成报告的大小。
  • 小型转储文件以二进制格式存储,因此如果没有 WinDbg 或 Microsoft Visual Studio .NET 等特殊工具,则无法读取它们。
  • 无法在 Windows 9x 上创建小型转储文件。希望这对 BugTrap 来说不是一个大问题,因为您可以使用 CrashExplorer 实用程序,它可以从十六进制错误地址中提取错误位置。

BugTrap 始终以纯文本或 XML 格式生成日志文件。小型转储文件仅在详细报告模式下生成。您必须指定 BTF_DETAILEDMODE 选项才能启用此模式:

BT_SetFlags(/* other options */ | BTF_DETAILEDMODE);

BugTrap 将日志文件和小型转储文件存储在一个 zip 存档中,以减小错误报告的大小。您可以将自定义日志文件添加到同一个 zip 存档中。可以使用内置的 BugTrap 函数生成自定义日志文件:

INT_PTR iLogHandle = BT_OpenLogFile(NULL, BTLF_TEXT);
BT_AddLogFile(BT_GetLogFileName(iLogHandle));
BT_InsLogEntry(iLogHandle, BTL_INFO, _T("custom log message"));
- or -
BT_InsLogEntryF(iLogHandle, BTL_WARNING, _T("numeric output: %d"), 123);

有关详细信息,请参阅“自定义日志文件”主题。

3.3.3 运行测试应用程序

BugTrap 附带了几个测试应用程序。您可以启动 BugTrapTest 示例并点击工具栏上的 “Access Violation!”按钮:

此按钮执行以下代码:

void CBugTrapTestApp::OnTestAccessViolation()
{
int* ptr = 0;
*ptr = 0; // ACCESS VIOLATION!!!
}

点击“Access Violation!”按钮后,您应该会看到 BugTrap 主窗口。此窗口显示异常信息、CPU 寄存器、调用堆栈和几个按钮: 

ButtonDescription
Close关闭 BugTrap 窗口并退出应用程序。
Submit Bug通过电子邮件或网络将错误报告发送给产品支持。应在应用程序启动时指定服务器地址/电子邮件地址。
Mail To…根据BTF_EDITMAIL标志,打开“发送邮件”对话框或启动系统电子邮件客户端,用户可以在其中准备发送给支持人员的自定义电子邮件。
Preview…打开 Preview 对话框,其中显示错误报告文件的内容。
Save…将错误报告保存到文件中。文件可能包括小型转储和自定义日志文件,具体取决于BTF_DETAILEDMODE标志。
Information…显示有关已安装操作系统的一般信息。
State…显示有关正在运行的进程和已加载模块的通用信息。

无需指定服务器地址、支持电子邮件或支持网站的 URL。未指定的链接将不会显示在屏幕上。用户可以按 Preview 或 Save 按钮来检查报表内容。默认情况下,报表名称包括唯一性的日期和时间。

Error report 包括以下部分:

  1. 应用程序名称和版本;
  2. 计算机和用户名(用于识别本地网络中的问题);
  3. 错误的日期和时间;
  4. 错误描述;
  5. 用户定义的消息(如果可用);
  6. COM错误信息(如果有);
  7. CPU 寄存器的值;
  8. 通用 CPU 信息;
  9. 操作系统信息;
  10. 内存使用统计;
  11. 所有正在运行的线程的堆栈跟踪信息;
  12. 进程命令行和当前目录;
  13. 进程环境变量;
  14. 正在运行的进程和加载的模块的可选列表;
  15. 可选在程序崩溃期间截取的屏幕截图。

错误信息可以以纯文本或 XML 格式显示:

        Excerpt from log file in plain text format
BugTrapTest.exe caused ACCESS_VIOLATION in module "<Executable
Path>\BugTrapTest.exe" at 001B:00401333,
CBugTrapTestApp::OnTestAccessViolation()+19 byte(s) in "<Source
Path>\BugTrapTest.cpp", line 161+3 byte(s)
            Excerpt from log file in XML format
<error>
	<what>ACCESS_VIOLATION</what>
	<process>
		<name>BugTrapTestE.exe</name>
		<id>6936</id>
	</process>
	<module>
		<Executable Path>\BugTrapTestE.exe< module>
				<address>001B:00401333</address>
				<function>
					<name>CBugTrapTestApp::OnTestAccessViolation</name>
					<offset>19</offset>
				</function>
				<file>
					<Source Path>\BugTrapTest.cpp< file>
						<line>
							<number>161</number>
							<offset>3</offset>
						</line>
</error>

您可以打开 “BugTrapTest.cpp” 并检查第 161 行: *ptr = 0;

3.3.3.1Visual Studio .NET 中的小型转储文件

小型转储文件可以在 Visual Studio IDE 中打开。在 Visual Studio 中打开此类文件并启动调试器 – IDE 将要求您创建一个新的解决方案,调试器将创建一个假进程。现在,您可以使用已知环境检查问题:

注意:

通常很难在 Release 版本中发现问题,因为优化编译器可能会删除一些变量,甚至重新定位代码。优化会影响存储在小型转储文件和 BugTrap 报告中的信息。在这种特殊情况下,无法在启用优化的 Visual Studio 调试器中看到 ptr 值。通常,在项目开发和测试期间禁用编译器优化会更好:

在大多数情况下,客户端计算机上的环境与开发人员计算机上的环境不同:应用程序二进制文件可能位于不同的文件夹中,系统 DLL 的版本可能不匹配。在这种情况下,“Call Stack” 窗口不会显示太多有用的信息,并且 Modules 窗口将显示警告 “No matching binary found”:

在这种情况下,您应该创建一个文件夹,将具有适当版本的有效二进制文件复制到该文件夹,并在 MODPATH 命令参数中指定该文件夹的路径:

重启后,调试器应按预期工作,并且您应该能够发现问题。尽管您可能会注意到 Modules 窗口仍然为系统 DLL 显示警告 “Cannot find or open a required DBG file” 或 “No symbols loaded” :

将剩余的符号文件 (PDB 和 DBG 文件) 复制到二进制文件文件夹或指定 Microsoft 符号服务器的路径后,可以修复此类警告:

3.3.3.2WinDbg 中的小型转储文件

WinDbg 是一个功能强大的调试器,具有可以调试用户模式和内核模式代码的图形界面。WinDbg 可以查看源代码、设置断点、查看变量 (包括 C++ 对象) 、堆栈跟踪和内存。WinDbg 包括一个命令窗口,用于发出各种命令,并支持使用两台计算机 (主机和目标计算机) 进行内核模式远程调试。它还允许远程调试用户模式代码和 64 位调试。WinDbg 可以从 Microsoft Windows 调试工具网站免费下载。

通过选择“FileOpen Crash Dump”菜单命令,在 WinDbg 中打开故障转储文件。通过选择 “ViewCommand” 菜单命令切换到命令视图。输入以下命令:

  • 输入 .sympath 命令,后跟带有 PDB 和 DBG 文件的分号分隔目录列表;
  • 输入 .srcpath 命令,后跟带有源文件的分号分隔目录列表;
  • 输入 .exepath 命令,后跟带有可执行文件的分号分隔目录列表;
  • 输入 .ecxr 以显示与当前异常关联的上下文记录;

例如:

.sympath c:\test\sym
.srcpath c:\test\src
.exepath c:\test\bin
.ecxr
  •  您可能希望将 Microsoft Symbol Server 的路径附加到 .sympath 命令,以便下载系统 DLL 的符号:
.sympath c:\test\sym;SRV*c:\symbols*http://msdl.microsoft.com/download/symbols

如果一切都配置良好,WinDdg 可能会显示以下信息:

3.3.4 自动 MAP 文件分析

MAP 文件是一个文本文件,其中包含有关所链接程序的以下信息:

  • 模块名称,即文件的基本名称;
  • 来自程序文件头 (而不是来自文件系统) 的时间戳;
  • 程序中的组列表,包括每个组的起始地址 (如 section:offset)、长度、组名称和类;
  • 公共符号列表,其中包含每个地址 (如 section:offset)、符号名称、平面地址和定义符号的 OBJ 文件;
  • 入口点 (如 section:offset);

注意:从 Microsoft Visual Studio 2005 开始,Microsoft 已停止对 MAP 文件的适当支持。新链接器无法在 MAP 文件中生成行号,并且不再支持 /MAPINFO:LINES 选项。CrashExplorer 不会从此类 MAP 文件中提取源文件名和行号,这使得 MAP 文件在新平台上毫无用处。但是,这并不意味着没有理由将 CrashExplorer 与 Microsoft Visual Studio 2005 一起使用,因为 CrashExplorer 可以从 PDB 文件中提取符号信息。大多数开发人员不会向他们的客户发布带有随附 PDB 文件的产品,因为 PDB 文件可以简化逆向工程。因此,最好在开发人员的机器上保留每个公开版本的 PDB 文件,并使用 CrashExplorer 将原始地址从日志文件转换为带有符号信息的人类可读报告。

MAP 文件可能会在项目链接期间生成。您不应将此文件分发给您的客户。对于每个公开版本,它都应该保存在开发人员的计算机上。如果您没有 PDB 文件或未成功生成故障转储(DbgHelp 在 Windows 9x 上存在某些问题),则 MAP 文件是您查找有关错误的符号信息的最新机会。

要为您的项目生成 MAP 文件,请执行以下步骤:

  1. 在 “Project Settings” 对话框中选择 Release configuration。
  2. 如果您为 Release 配置制作 PDB 文件,您应该已经在 “C/C++General” 选项卡上选择了调试信息的 “Program Database” 格式。此选项可用于 MAP 文件。如果您不想制作 PDB 文件,您至少应该选择 “Line Numbers Only” 格式(它启用 /Zd 编译器选项)。
  3. 启用“LinkerDebugging”选项卡上的“Generate Map File”选项。
  4. 在 Visual Studio 2003 中启用“最大导出数”和“映射线”选项,或在 Visual Studio 6 中添加自定义链接器开关““/MAPINFO:EXPORTS”和“/MAPINFO:LINES”。
  5. 可选地在 Visual Studio 2003 中配置“映射文件名”选项,或在 Visual Studio 6 中调整自定义链接器开关“/MAP:<Map File Name>”。

请使用这些图片作为参考:

日志文件可以以纯文本 (BTRF_TEXT) 或 XML (BTRF_XML) 格式生成。纯文本更适合人类使用,但如果要解析和自动处理日志信息,它几乎没用。默认情况下,BugTrap 以 XML 格式生成日志文件。可以通过调用 BT_SetReportFormat()来更改输出格式。XML 格式有一个很大的优点:它可以被 CrashExplorer 解析。CrashExplorer 将从 XML 文件中检索到的原始地址与 MAP 或 PDB 文件中找到的符号信息合并,并恢复完整的堆栈跟踪,即使带有符号信息的 PDB 文件在客户的计算机上不可用:

在使用 CrashExplorer 之前,您应该为项目中的所有模块(EXE 或 DLL 文件)准备一个包含 MAP 或 PDB 文件的文件夹。如果您尚未使用除 MFC 或标准 Windows DLL 之外的任何库,则只需为主可执行文件复制一个 MAP 或 PDB 文件即可。如果项目包含主可执行文件和两个附加 DLL,则应将三个 MAP/PDB 文件复制到此文件夹。如果您没有某些模块的 MAP 和 PDB 文件,并且 XML 日志文件不包含这些模块的符号信息,则 CrashExplorer 将无法显示包含此类模块的函数名称和行号的堆栈跟踪。每个 MAP/PDB 文件都应具有与相应模块相同的基本名称:

准备好包含 MAP 和 PDB 文件的文件夹后,指定 XML 日志文件的路径,然后按 Calculate 按钮。程序输出可以复制到剪贴板或保存到文本文件:

您也可以手动恢复符号信息 (在 Manual Mode 选项卡上)。如果您选择了日志文件的纯文本格式,这可能很有用。BugTrap 始终将十六进制崩溃地址存储在文本日志文件中,即使您不将 PDB 文件分发给客户也是如此。以下示例显示了不带符号信息(不带源文件
名称和行号):
 

BugTrapTest.exe caused ACCESS_VIOLATION in module "<Executable
Path>\BugTrapTest.exe" at 001B:00401333

001B:00401333 是一个崩溃地址,但你只需要知道地址偏移量(冒号后的地址部分)。当前是00401333。

文本日志还包括进程地址空间中加载的每个模块 (DLL 或 EXE 文件) 的物理加载地址。物理加载地址对于将崩溃地址映射到项目中的源文件名和行号至关重要。大多数开发人员很少对项目模块进行变基(调整每个加载模块的加载地址,以避免模块在内存中重叠)。操作系统更改重叠模块的加载地址。因此,物理加载地址可能与模块链接期间指定的首选加载地址不匹配。您可以在 module information block 中找到模块加载地址,例如:

Process: BugTrapTest.exe, PID: 2312, Modules:
----------------------------------------
<Executable Path>\BugTrapTest.exe (1.0.0.1), Base: 00400000, Size: 002C8000
C:\WINDOWS\system32\ntdll.dll (5.1.2600.2180), Base: 7C900000, Size: 000B0000
C:\WINDOWS\system32\kernel32.dll (5.1.2600.2180), Base: 7C800000, Size:
000F4000
C:\WINDOWS\system32\USER32.dll (5.1.2600.2622), Base: 77D40000, Size: 00090000
C:\WINDOWS\system32\GDI32.dll (5.1.2600.2818), Base: 77F10000, Size: 00047000

进程的地址空间中加载了很多模块。我们需要知道一个模块的物理负载地址。我们正在寻找导致异常的模块。根据日志文件,此模块BugTrapTest.exe:

BugTrapTest.exe caused ACCESS_VIOLATION in module "<Executable
Path>\BugTrapTest.exe" at 001B:00401333

所以,现在你有了BugTrapTest.exe模块的物理加载地址——根据日志文件,它是 00400000。顺便说一句,大多数 EXE 文件都是在此地址加载的,尽管它可能因不同的 DLL 而异。让我们总结一下所有可用的信息:

如果您有BugTrapTest.exe模块的 MAP 文件,那么找到源文件名、函数名称和行号就足够了。注意,CrashExplorer 会自动从 BugTrapTest.map 文件中提取首选加载地址(在我们的示例中为 00400000)。首选加载地址与此模块的物理加载地址相同,因此您可以保持原样。CrashExplorer 不知道崩溃地址,因此您应该将 00401333 放在相应的字段中。按下 Calculate 按钮并检查结果:

还可以通过在 “Crash Address” 字段中指定不同的调用地址来遍历调用堆栈条目。

3.3.4.1总结

有三种不同的方法来跟踪信息:PDB 文件、小型转储和 MAP 文件。哪种方法更好?没有绝对的答案,但我会推荐以下内容:

  1. 在 beta 测试期间将 PDB 文件重新分发给内部测试人员和 SQA 组;
  2. 不要将 PDB 文件重新分发给最终用户;
  3. 相反,将所有公共版本的 PDB 文件存储在本地存储库中;
  4. 始终使用小型转储文件;
  5. 将 CrashExplorer 与 PDB 或 MAP 文件一起使用以进行快速错误分析;
  6. 将小型转储与 PDB 文件一起使用,以便在调试器中进行深入的错误分析。

3.4 本机 C++ 异常

还可以使用 BugTrap 拦截未处理的 C++ 异常。以下代码行安装运行时在未处理的 C++ 异常时调用的 BugTrap terminate-handler:

BT_SetTerminate();

BT_SetTerminate() 只是一个调用 C 运行时中定义的 set_terminate()  的宏。由于 set_terminate()  没有在 BugTrap 头文件中定义,你应该在程序源代码中包含 <eh.h>。请注意,set_terminate()  仅在活动线程中安装终止例程。在多线程环境中,您应该在每个线程中调用 BT_SetTerminate() 。正确安装终止例程后,BugTrap 会自动展开堆栈跟踪到导致未处理的 C++ 异常的 throw 语句的位置,您通常可以在堆栈顶部查看您的函数。

3.4.1 与 MFC 集成

默认情况下,MFC 会截获从 CException 类派生的所有未捕获的异常,但你可以使用 BugTrap 而不是 MFC 错误处理程序。但是,这需要对代码进行少量的额外更改,因为 BugTrap 无法在 BugTrap 处理程序之前截获 MFC 捕获的错误。为了让 BugTrap 首先收到异常通知,您应该从 BTWindow 类派生 frame、view、dialog 和 window 类。BTWindow 类是一个模板,它采用基窗口类的名称作为参数。例如,如果要处理主框架类中所有未捕获的异常,则应从 BTWindow<CFrameWnd> 而不是 CFrameWnd 派生框架类:

class CMainFrame : public BTWindow<CFrameWnd>

同样,如果要处理视图类中的所有异常,则应使用以下代码:

class CMyView : public BTWindow<CView>
- or -
class CMyView : public BTWindow<CScrollView>

除此之外,不需要其他更改,无需更改 RTTI 宏 (IMPLEMENT_XXX) 或消息映射宏 (BEGIN_MESSAGE_MAP) 中的基类名称。作为奖励,BugTrap 还可以识别从 STL 异常类派生的异常。对于这两种类型的异常,BugTrap 都可以提取错误描述并将其放入报告中。

如果您注意到,在这些更改之后,Visual Studio 不会适当地处理您的框架或视图类,并且不会在向导中显示类的命令处理程序,则可以将这些行添加到类的标头中:

// this is required to bypass VS.NET parser issues
#ifdef __NEVER_DEFINED__
#define BTWindow<CView> CView
#endif
class CMyView : public BTWindow<CView>

3.4.2 与 ATL/WTL 集成

ATL/WTL 项目还可以利用 BugTrap 窗口类。即使 ATL 不提供默认的异常处理程序,最好还是让 BugTrap 在将异常传递到 Windows 之前处理所有未捕获的错误。为 ATL 定义了 BTWindow 类的特殊版本。从用户的角度来看,此类采用相同的模板参数并提供相同的语法:

class CMainFrame : public BTWindow< CFrameWindowImpl<CMainFrame> >

与在内部将对话框作为普通窗口处理的 MFC 不同,ATL 对对话框使用特定的类。这就是为什么所有 ATL 对话派生类都应该使用 BTDialog 而不是 BTWindow 的原因:

class CMyDialog : public BTDialog< CDialogImpl<CMyDialog> >

更复杂的项目可能会同时使用 ATL 和 MFC。对于此类项目,您应该在 BTWindow 类名前加上 ATL 或 MFC 命名空间:

class CMyAtlView : public ATL::BTWindow< CWindowImpl<CMyAtlView> >
- and -
class CMyMfcView : public MFC::BTWindow<CView>

3.5 自定义日志文件

通常,普通代码会导致异常作为另一个逻辑错误的副作用。在这种情况下,标准错误报告可能无济于事。不幸的是,没有通用的方法可以解决所有逻辑错误。只有一些技术可以简化错误检测。自定义日志记录可能是最有效的防错机制。开发人员在日志文件中跟踪重要的程序活动。崩溃后可以查看和发现这些文件。BugTrap 具有内置函数,这些函数可以在详细模式下将任意数量的附加文件附加到报告中(指定了标志 BTF_DETAILEDMODE)。您可以将自定义日志文件附加到报表中,如下所示:

BT_AddLogFile(_T("LogFile1.txt"));
BT_AddLogFile(_T("LogFile2.txt"));

如果您想从 Windows 注册表中导出一些密钥并将它们附加到报告中,您可以利用内置的 BugTrap 功能:

BT_AddRegFile(_T("Settings.reg"),
_T("HKEY_CURRENT_USER\\Software\\My Company\\My Application\\Settings"));

可以在应用程序启动时添加自定义日志文件,也可以设置自定义错误处理程序并在此处理程序中执行其他初始化。自定义错误处理程序由 BugTrap 调用,以响应未处理的异常:

void CALLBACK MyErrHandler(INT_PTR nErrHandlerParam)
{
... // last-minute customization
}
...
BT_SetPreErrHandler(MyErrHandler, 0);

C/C++ 开发人员没有标准的日志记录函数。许多开发人员编写自己的代码。通常,开发人员会打开一个文件,附加一个字符串,然后关闭该文件。这种方法没有什么坏处;但是,BugTrap 包含可以进一步简化此任务的内置函数。与常规方法相比,这些函数具有以下几个优点:

一、关于如何存储日志文件记录,有两种不同的方法:

  • 传统方法可确保在将新消息附加到日志时立即将其存储在磁盘上。此方法非常适合具有数十万条记录的大型日志文件,因为内存中不存储任何数据。向此类日志文件添加记录需要更多时间。此外,无法从日志文件中清除旧记录。最近的记录将附加到文件末尾。要将记录永久存储在磁盘上,请在 BTLF_STREAM 模式下打开日志文件。
  • 作为替代方案,BugTrap 可以在正常的应用程序处理期间将所有消息保存在一个列表中,以便可以快速添加新消息,并且可以从日志中快速删除旧消息。BugTrap 在退出应用程序之前自动将所有消息刷新到磁盘。这种方法在日志更新速度和抗崩溃性之间提供了最佳权衡,但您不应对非常大的日志文件(通常超过 10,000 条记录)使用此方法。BTLF_TEXT 和 BTLF_XML 文件都将日志记录缓存在内存中。

二、日志文件可以以 XML (BTLF_XML) 或纯文本 (BTLF_TEXT) 格式存储。

XML 数据可以导出为任何其他格式,例如,您可以使用几行 XSL 代码将 XML 记录导出到漂亮的 HTML 表格中。但是,纯文本加载到内存中的速度比 XML 数据集快 5-10 倍。BugTrap 使用自定义 XML 解析器,针对流式处理大型 XML 数据集进行了优化,您不会注意到包含几千个条目的文件的速度有太大差异。较大的文件可能需要更多时间来解析。因此,在决定日志格式之前,您应该考虑文件的大小。

三、所有日志记录函数都是线程安全的,您可以安全地将日志条目从不同的线程添加到同一日志文件中,而无需显式同步。

四、日志记录函数可以正确处理国家字符。

日志信息以 UTF-8 格式编码,您可以正确解释任何与区域设置相关的信息,例如文件路径。

五、日志消息可以回显到 STDOUT、STDERR 和调试器控制台。

六、日志消息可以根据其严重性自动过滤。

Ⅰ、Opening & closing

您可以打开任意数量的日志文件。使用 BT_OpenLogFile() 获取新打开的日志文件的句柄。此句柄必须传递给以下函数之一:BT_AppLogEntry()  或 BT_InsLogEntry() 。您可以在 BT_OpenLogFile()  中使用任意日志文件名,也可以传递 NULL 指针以将默认名称分配给日志。默认日志文件名为 “%APPDATA%<Application Name><Main Module Name>.log”。应使用函数 BT_CloseLogFile()  关闭日志文件。此功能释放内部分配的资源。

Ⅱ、Controlling log size

您可以限制日志文件 (BT_SetLogSizeInEntries()) 中的最大字节数 (BT_SetLogSizeInBytes()) 或记录数。较旧的记录会自动从文件中提取。默认情况下,日志文件不受限制(日志大小 = MAXDWORD)。

Ⅲ、Adding new records

BT_InsLogEntry()在文件开头插入新记录。BT_AppLogEntry() 将新记录追加到文件末尾。这些函数有一些特殊版本,具有类似 printf 的语法。也可以通过在 BT_SetLogFlags() 函数中指定 BTLF_SHOWTIMESTAMP 标志来启用所有日志条目的时间统计信息。时间戳以与区域设置无关的格式 YYYY/MM/DD HH:MM:SS 存储。
请注意,在 BTLF_STREAM 模式下,您不能将记录插入到日志文件的请求中。在
此模式记录在附加到日志后立即存储在磁盘上。

Ⅳ、Filtering output

可以使用各种日志级别筛选日志输出。将日志级别分配给每个日志条目。可以使用以下日志级别:

  • BTL_ERROR – 错误消息(最高优先级);
  • BTL_WARNING – 警告消息;
  • BTL_IMPORTANT – 重要信息消息;
  • BTL_INFO – 定期信息消息;
  • BTL_VERBOSE – 详细信息消息 (最低优先级)。

您可以将最小期望日志级别传递给 BT_SetLogLevel() ,随后的 BT_InsLogEntry()  或 BT_AppLogEntry() 操作会将具有指定或更高优先级的所有消息添加到日志中。例如,您可以将日志级别设置为 BTL_WARNING,并且只会将警告和错误消息添加到日志中。您甚至可以通过将 BTL_NONE 传递给 BT_SetLogLevel()  来禁用所有日志消息的输出。每个 BT_InsLogEntry()  或 BT_AppLogEntry()  操作都将消息级别作为参数。程序的不同部分可能会添加信息消息、警告消息和错误消息。您不必添加任何额外的代码来指定必须将哪些消息添加到日志中。单个 BT_SetLogLevel()  调用控制所有输出。通常,此设置存储在程序配置中的某个位置,用户可以动态控制生成的日志输出量。默认情况下,所有消息都会添加到日志文件中。

Ⅴ、Echo mode

可以在控制台应用程序的屏幕上复制日志消息,也可以将消息转储到调试器控制台。默认情况下,日志消息仅存储在文件中,但可以使用 BT_SetLogEchoMode()  函数启用回声模式。请注意,启用回显模式会降低日志更新的速度,因为共享相同回显模式的日志文件的输出是相互同步的。不使用任何回显的普通日志更新的执行速度要快得多 - 实际上是即时的。

Ⅵ、Code example

以下代码片段调用不同的日志记录函数:

// open new log file, use the default log file name
INT_PTR iLogHandle = BT_OpenLogFile(NULL, BTLF_TEXT);
// set log size = 100 records
BT_SetLogSizeInEntries(iLogHandle, 100);
// automatically add time statistics to log output
BT_SetLogFlags(iLogHandle, BTLF_SHOWLOGLEVEL | BTLF_SHOWTIMESTAMP);
// apply filter to log output
BT_SetLogLevel(iLogHandle, BTL_WARNING);
// get default log file name
PCTSTR pszLogFileName = BT_GetLogFileName(iLogHandle);
// add custom log file to the report
BT_AddLogFile(pszLogFileName);
// insert log entries at the begging of the file
BT_InsLogEntry(iLogHandle, BTL_INFO, _T("custom log message"));
BT_InsLogEntryF(iLogHandle, BTL_WARNING, _T("numeric output: %d"), 123);
// - or -
// append log entries to the end of file
BT_AppLogEntry(iLogHandle, BTL_ERROR, _T("another message"));
BT_AppLogEntryF(iLogHandle, BTL_INFO, _T("printf-like syntax: %s"),
pszMessage);
// Close log file
BT_CloseLogFile(iLogHandle);

C++ 开发人员可能更喜欢内置 BTTrace 类的简化接口,该类包装了以下函数:

BTTrace trace(NULL, BTLF_TEXT);
trace.InsertF(_T("printf-like syntax: %s"), pszMessage);
// - or -
trace.Append(BTL_WARNING, _T("something is wrong"));

3.6 配置报表传递

报告可以通过电子邮件、HTTP 或基于 TCP 的网络协议发送给产品支持。每种方法都有自己的优点,有关详细信息,请参阅 BugTrap 服务器主题。可以使用以下代码指定错误报告的目标电子邮件地址:

BT_SetSupportEMail(_T("your@email.com"));

你可以配置 BugTrap 通过基于 TCP 的低级网络协议向 BugTrap 服务器发送错误报告,只需指定所需的服务器主机和端口号即可:

BT_SetSupportServer(_T("localhost"), 9999);

如果您想通过 HTTP 而不是原生 BugTrap 协议发送错误报告,只需将服务器 URL 指定为主机名,并将 BUGTRAP_HTTP_PORT 或 80 指定为端口号:

BT_SetSupportServer(_T("http://localhost/BugTrapWebServer/RequestHandler.aspx")
, BUGTRAP_HTTP_PORT);

您可以指定电子邮件地址,以便接收来自 BugTrap 服务器的传入错误报告的通知消息:

BT_SetNotificationEMail(_T("another@email.com"));

注意:通知电子邮件可能在 BugTrap 服务器配置文件中被禁用。

3.7 在服务器应用程序中使用 BugTrap for Win32/64

服务器应用程序和各种服务不得显示 GUI。可以为此类应用程序预配置默认操作,并且 BugTrap 不会为此类应用程序显示任何对话框。

例如:

// Force BugTrap to submit reports to support server w/o GUI
BT_SetActivityType(BTA_SENDREPORT);

还可以在问题发生后从自定义错误处理程序重新启动服务器。您可以使用 BT_SetPostErrHandler()设置自定义错误处理程序。

4 BugTrap for .NET

4.1 向 .NET 应用程序添加 BugTrap

BugTrap 的 .NET 版本作为托管库重新分发:BugTrapN.dll。此 DLL 由托管代码和非托管代码组成。这种设计使 BugTrap 支持纯托管的 .NET 程序集以及可能引发托管 .NET 异常和本机 Win32/64 异常的混合 C++ 程序集。

BugTrap for .NET 公开托管和非托管 (本机) 接口。托管接口可从 C# 或 VB.NET 代码访问:

ExceptionHandler.AppName = "Your application name";
ExceptionHandler.Flags = FlagsType.DetailedMode | FlagsType.EditMail;
ExceptionHandler.DumpType = MinidumpType.NoDump;
ExceptionHandler.SupportEMail = "your@email.com";
ExceptionHandler.SupportURL = "http://www.your-web-site.com";
ExceptionHandler.SupportHost = "localhost";
ExceptionHandler.SupportPort = 9999;

非托管接口可从本机 Win32/64 代码访问,前面已经讨论过。可以在同一应用程序中使用任何接口,甚至可以使用两个接口。

4.2 重新分发 BugTrap for .NET

出于性能原因,BugTrap 的 .NET 版本使用宽字符串。此代码与 Windows NT/2000/XP 兼容。Windows 98/Me 支持已放弃 .NET 版本也依赖于 DbgHelp - 您可以在上面找到更多信息。更重要的是,它需要 Microsoft .NET Framework 2.0 和 Visual C++ 运行时。具体而言,需要以下 DLL:

  • msvcm80.dll
  • msvcp80.dll
  • msvcr80.dll

您可以将这些 DLL 随应用程序一起提供,或者您可能希望安装 Microsoft Visual C++ 2005 Redistributable Package。

4.3 .NET 应用程序的错误分析

除了 Win32/64 版本,BugTrap for .NET 还会生成几种格式的错误信息:

  • 日志文件(如果可能)使用 PDB 文件进行扩充;
  • 小型转储文件。

4.3.1 异常日志

BugTrap for .NET 以 XML 或文本格式生成详细的错误日志。日志文件包含导致异常的线程的托管堆栈跟踪。由于 .NET 框架的某些限制,当前版本的 BugTrap 无法为任何其他线程生成托管堆栈跟踪(即只记录一个线程)。我们正在努力解决这个问题,试图扩展了 BugTrap 功能。
但是,当前线程的堆栈跟踪包括所有必要的详细信息:

<stack>
 <frame>
 <assembly>BugTrapNetTest</assembly>
 <native-offset>200</native-offset>
 <il-offset>49</il-offset>
 <type>BugTrapNetTest.MainForm</type>
 <method>System.Void exceptionButton_Click(System.Object sender,
System.EventArgs e)</method>
 <method>System.Void exceptionButton_Click(System.Object sender,
System.EventArgs e)</method>
 <file><Source Path>\MainForm.cs</file>
 <line>2d</line>
 <column>4</column>
 </frame>
 ...
<stack>

如果如前所述将应用程序与 PDB 文件一起重新分发,则日志文件将包含行号和源文件名。如果 PDB 文件不可访问,则日志文件仅包含程序集、类型和方法名称。

4.3.2 Minidump 文件

如前所述,可以在没有附带 PDB 文件的情况下生成重新分发应用程序,生成小型转储文件并在 WinDbg 或 Visual Studio 中对其进行分析。它是在 SOS 调试扩展 (sos.dll) 的帮助下处理的。此扩展作为 Microsoft .NET Framework 的一部分重新分发。SOS 向 Visual Studio Debugger 和 WinDbg 添加了多个命令。此时,最新版本的 SOS 有一个限制:它显示带有方法名称和类型的可读调用堆栈,但不显示行号和源文件名。据推测,此问题应在 Windows 调试工具的下一版本中得到解决。此外,还有另一个问题 - SOS 似乎不适用于小型转储文件 (MiniDumpNormal)。完整的小型转储文件 (MiniDumpWithFullMemory) 肯定有效,但它们要大得多。解压缩的故障转储可能会占用 100 – 150MB。存档的转储文件更小 – 40MB 更好,但在大多数情况下仍然不可用。准备大型转储和创建存档也需要更多时间。坦率地说,当前版本的 SOS 看起来不像成品。它在产品测试期间可能很有用,但不建议在生产环境中使用。以下代码行禁用 minidump 输出:

ExceptionHandler.DumpType = MinidumpType.NoDump;

要在托管应用程序中使用小型转储文件,请将 dump type (转储类型) 设置为 full:

ExceptionHandler.DumpType = MinidumpType.WithFullMemory;

以下示例演示了 WinDbg 中的示例会话:

  • 从 Microsoft .NET Runtime 文件夹加载 SOS 扩展:
.load C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\SOS.dll
  • 检查扩展是否已加载:
.check

输出:

Extension DLL chain:
 C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\sos.dll: image 2.0.50727.42,
API 1.0.0, built Fri Sep 23 00:27:26 2005
 [path: C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\sos.dll]
  • 设置 symbol/source 搜索路径:
.sympath c:\test\sym
.srcpath c:\test\src
.exepath c:\test\bin
  • 列出托管线程:
!threads

输出:

ThreadCount: 3
UnstartedThread: 0
BackgroundThread: 2
PendingThread: 0
DeadThread: 0
Hosted Runtime: no
 PreEmptive GC Alloc Lock
 ID OSID ThreadOBJ State GC Context Domain Count APT
Exception
 0 1 970 00164368 6020 Enabled 00000000:00000000 001584f8 1 STA
System.Exception (01293190)
 2 2 4b4 00170550 b220 Enabled 00000000:00000000 001584f8 0 MTA
(Finalizer)
 7 3 f40 0015bf48 220 Enabled 00000000:00000000 001584f8 0 Ukn

注意:第一个线程的 Exception 列中有一个 Exception 对象:System.Exception (01293190)

  • 显示此对象的异常信息:
!pe 01293190

输出:

Exception object: 01293190
Exception type: System.Exception
Message: <none>
InnerException: <none>
StackTrace (generated):
 SP IP Function
 0012F02C 00C8A759
BugTrapNetTest.MainForm.exceptionButton_Click(System.Object, System.EventArgs)
 0012F044 7B060A6B System.Windows.Forms.Control.OnClick(System.EventArgs)
 0012F054 7B105379 System.Windows.Forms.Button.OnClick(System.EventArgs)
 0012F060 7B10547F
System.Windows.Forms.Button.OnMouseUp(System.Windows.Forms.MouseEventArgs)
 0012F084 7B0D02D2
System.Windows.Forms.Control.WmMouseUp(System.Windows.Forms.Message ByRef,
System.Windows.Forms.MouseButtons, Int32)
 0012F0D0 7B072C74
System.Windows.Forms.Control.WndProc(System.Windows.Forms.Message ByRef)
 0012F134 7B0815A6
System.Windows.Forms.ButtonBase.WndProc(System.Windows.Forms.Message ByRef)
 0012F170 7B0814C3
System.Windows.Forms.Button.WndProc(System.Windows.Forms.Message ByRef)
 0012F178 7B07A72D
System.Windows.Forms.Control+ControlNativeWindow.OnMessage(System.Windows.Forms
.Message ByRef)
 0012F17C 7B07A706
System.Windows.Forms.Control+ControlNativeWindow.WndProc(System.Windows.Forms.M
essage ByRef)
 0012F190 7B07A515 System.Windows.Forms.NativeWindow.Callback(IntPtr, Int32,
IntPtr, IntPtr)
StackTraceString: <none>
HResult: 80131500

现在已经有了我们期待已久的堆栈信息。

4.4 GUI .NET 应用程序注意事项

Microsoft .NET Framework 2.0 允许您通过调用 Application.EnableVisualStyles() 来启用 Windows XP 主题支持。默认情况下,AppWizard 会将此代码添加到每个新项目中。BugTrap 可能会在代码中启用 XP 主题之前初始化 Windows 公共控件。Windows 公共控件 5.x 句柄可能由 ComCtl32 版本 6.x 不合理地解释。当您在 BugTrap GUI 中看不到任何图标时,您可能会注意到此问题。可以通过向应用程序添加清单文件来解决此问题:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
 <assemblyIdentity
 version="1.0.0.0"
 processorArchitecture="X86"
 name="Microsoft.Windows.Common-Controls"
 type="win32"
/>
 <description>Windows forms common controls manifest</description>
 <dependency>
 <dependentAssembly>
 <assemblyIdentity
 type="win32"
 name="Microsoft.Windows.Common-Controls"
 version="6.0.0.0"
 processorArchitecture="X86"
 publicKeyToken="6595b64144ccf1df"
 language="*"
 />
 </dependentAssembly>
 </dependency>
</assembly>

如果您的可执行文件名为 MyApp.exe,则此文件必须命名为 MyApp.exe.manifest。必须将其复制到与可执行文件相同的文件夹中。要自动执行此任务,请将此文件另存为 app.exe.manifest,将其放入您的项目中,并添加一个命令来发布构建事件:

此命令将自动重命名清单文件并将其复制到包含可执行文件的文件夹中。

5 BugTrap 服务器

错误报告可以通过电子邮件附件、HTTP 或基于 TCP 的低级网络协议发送给产品支持。

Ⅰ、电子邮件附件

电子邮件附件非常适合在 Internet 上分发小文件。

优点:

  1. 此方法不需要安装任何其他服务器。您可以简单地使用您的 Internet 服务提供商;
  2. 错误报告可以通过防火墙透明地传递;
  3. 产品支持部门可能会处理标准电子邮件客户端中的错误报告,并通过电子邮件向客户提供反馈。

缺点:

  1. 自动处理带有错误报告的电子邮件非常困难,甚至不可能。例如,您无法有效地筛选多个产品的错误报告;
  2. 大多数 SMTP 服务器拒绝带有大附件的电子邮件 – 这可能会导致附件中存储的大型小型转储文件出现问题。

Ⅱ、基于 TCP 的低级网络协议

BugTrap 可以通过轻量级网络协议向 BugTrap 服务器发送错误报告,该协议针对传输大量数据进行了优化。BugTrap 服务器为本地网络上具有复杂支持的产品提供了更好的机会。通常,这是在产品开发和 beta 测试期间最适合软件开发人员、SQA 小组和本地测试人员的选项。

优点:

  1. 错误报告可以自动存储在仓库中,按产品名称排列并根据配置文件进行过滤;
  2. 报告的大小没有限制,它可以包含大型小型转储文件,并且您可以向报告附加任意数量的自定义日志文件;
  3. BugTrap 服务器是极其快速和轻量级的服务器。它可以在本地网络上有效使用。它可以安装在任何计算机上,并且不需要 Web 服务器。

缺点:

  1. 原生 BugTrap 协议可能会被防火墙阻止,这就是为什么此选项主要用于局域网。

Ⅲ、HTTP 协议

由于大多数计算机都受到防火墙保护,因此 BugTrap 服务器可能无法成功接收来自 Internet 的错误报告。这可以使用 BugTrap Web 服务器来解决。

BugTrap Web 服务器可以处理通过 HTTP 协议收到的错误报告,HTTP 协议是一种透明地通过防火墙传递的标准传输协议。

HTTP 协议的数据传输效率不如本机 BugTrap 服务器协议,并且 BugTrap Web 服务器需要一台带有 Web 服务器 (Microsoft IIS 5 – 6) 的计算机,但 BugTrap Web 服务器可以自动处理所有报告,而无需任何用户交互。对于 Internet 上具有复杂支持的产品,这是最佳选择。

优点:

  1. 错误报告可以自动存储在仓库中,按产品名称排列并根据配置文件进行过滤;
  2. 报告大小没有限制,它可能包括大型小型转储文件,并且您可以附加任意数量的自定义日志文件;
  3. 错误报告可以通过防火墙透明地传输。

缺点:

  1. 您必须在网络上维护一台带有 Web 服务器 (Microsoft IIS 5 – 6) 的计算机;
  2. HTTP 协议的效率不如原生 BugTrap 协议,而且 BugTrap 服务器比在 Web 服务器上运行的 BugTrap Web 服务器快得多。

本章的其余部分介绍了 BugTrap 服务器和 BugTrap Web 服务器。

5.1 BugTrap 服务器

BugTrap 服务器是一个独立的服务器,它使用基于 TCP 的轻量级协议处理所有请求。它不需要 Web 服务器,可以在任何计算机上启动。同一服务器可能会接收来自多个产品的报告。您可以在一个配置文件中限制产品列表和接收信息的数量。Win32/64 和 .NET 版本重复使用相同的网络协议,因此同一服务器可用于这两种类型的应用程序。可以接收有关来自 BugTrap 服务器的传入报告的电子邮件通知。

有两个版本的 BugTrap 服务器可用:

  1. 针对 Windows 2000/XP 优化的 BugTrap 服务器的 .NET 版本;
  2. BugTrap 服务器的独立于平台的 Java 版本。

两个版本都重复使用相同格式的 XML 配置文件,并维护相同的存储库。这两个版本都使用异步网络操作和线程池,以实现最佳性能和可扩展性。BugTrap 服务器被设计为稳定,即使在出现意外的内部错误时也能继续正常的报告处理:它只是将错误信息写入系统事件日志(.NET 版本)或标准错误流(Java 版本),关闭断开的连接并终止损坏的任务。同时,其他线程保持稳定且不受影响。

5.1.1 安装 .NET 版本的 BugTrap 服务器

BugTrap 服务器的 .NET 版本需要 Microsoft .NET Framework 2.0。

BugTrap 服务器可以作为 Windows 服务安装在 Windows NT 平台上,也可以使用 /run 命令行选项作为典型的 Win32/64 应用程序启动。

虽然 BugTrap 服务器可以用作普通的 Windows 应用程序,但强烈建议在 Windows 2000 或 Windows XP 操作系统上将 BugTrap 服务器作为 Windows 服务运行。您可以在命令中安装和卸载 BugTrap 服务
提示:

安装命令行: BugTrapServer.exe /install 
卸载命令行: BugTrapServer.exe /uninstall

5.1.2 安装 Java 版本的 BugTrap 服务器

Java 版本的 BugTrap 服务器需要以下组件:

  • Java 2 Platform, Standard Edition 5.0 (J2SE) http://java.sun.com/j2se/1.5.0/download.jsp
  • JavaMail 1.4 http://java.sun.com/products/javamail/downloads/index.html
  • JavaBeans Activation Framework 1.1 http://java.sun.com/products/javabeans/jaf/downloads/index.html

服务器代码位于 BugTrapServerJBugTrapServerJBugTrapServer.jar 文件中。可以使用以下批处理文件执行 BugTrap 服务器(该示例假定您的计算机上安装了 J2SE、JavaMail 和 JAF):

@echo off
set JAVAHOME=%ProgramFiles%\Java
set JDK=jdk1.5.0_07
set JMAIL=javamail-1.4
set JAF=jaf-1.1
set JAVABIN=%JAVAHOME%\%JDK%\bin
set CLSPATH=".;%JAVAHOME%\%JDK%\jre\lib\rt.jar;%JAVAHOME%\%JMAIL%\mail.jar;
%JAVAHOME%\%JAF%\activation.jar"
"%JAVABIN%\java.exe" -classpath JBugTrapServer.jar;%CLSPATH%
BugTrapServer.ServerApp 2>>BugTrapServerError.log

注意:上面的示例将标准错误输出流重定向到BugTrapServerError.log文件。这对于跟踪内部服务器错误非常有用。

5.2 BugTrap Web 服务器

BugTrap Web 服务器是一个典型的 ASP.NET Web 应用程序。它应该在 Internet Information Server 5 或 6 中注册为典型的 Web 应用程序。

同一服务器可能会接收来自多个产品的报告。您可以在一个配置文件中限制产品列表和接收信息的数量。Win32/64 和 .NET 版本重复使用相同的网络协议,因此同一服务器可用于这两种类型的应用程序。可以接收有关来自 BugTrap Web 服务器的传入报告的电子邮件通知。

5.2.1 安装 BugTrap Web 服务器

BugTrap Web 服务器需要 ASP.NET 2.0 和 Microsoft .NET Framework 2.0。BugTrap Web 服务器目录包含多个文件,例如 RequestHandler.aspx 和 Web.config。RequestHandler.aspx 拦截客户端请求并将其重定向到位于 bin 目录中的相应 DLL。RequestHandler.aspx 应明确
在传递给 BT_SetSupportServer() 的 HTTP 地址中指定:

http://<domain name>/BugTrapWebServer/RequestHandler.aspx

默认情况下,BugTrap Web 服务器没有在您的计算机上创建新文件夹的权限。您应该创建存储库并手动将此文件夹的修改权限授予 ASPNET 用户。

假设您希望将错误报告存储在 Web 应用程序的 reports 子文件夹中。在这种情况下,您应该完成以下步骤:

  1. 创建新的报告文件夹(通常在C:\Inetpub\wwwroot\BugTrapWebServer 中);
  2. 打开新创建文件夹的属性窗口;
  3. 切换到 安全 文件夹属性中的选项卡;
  4. 点击 地址 按钮;
  5. 在对象名称字段中键入 ASPNET,然后按 OK 按钮;
  6. 选中 Modify 复选框;
  7. 按 OK 按钮保存更改。

5.2.2 测试 BugTrap Web 服务器

通常,使用 “BugTrap Request Simulator” 网页测试 BugTrap Web 服务器会更容易,然后才使用真正的 BugTrap 客户端。

  • 在 Web.config 中启用自定义错误模式,以便于诊断。默认情况下,将向本地连接到 Web 服务器的用户显示详细的错误信息。您可以使此信息可供远程用户使用,只需在 Web.config 中设置 <customErrors mode=“On”/> 并保存更改即可;
  • 打开浏览器并转到 http://<服务器名称>/BugTrapWebServer/RequestSimulator.htm;
  • 使用任意产品信息填写测试表:

注意:除非您已在 Web.config 中正确配置了 SMTP-server,否则您应该将通知电子邮件留空,如下所述。

  • 按“Submit Report”按钮;
  • 如果所有内容都已正确配置,并且 ASPNET 用户可以访问存储库,您应该会看到以下消息:

  • 完成测试后,您可能希望在 Web.config 中禁用自定义错误模式并删除RequestSimulator.htm文件;
  • 现在是在 BugTrapTest 中更新服务器设置并确保 BugTrap 客户端可以建立连接的好时机。

5.3 配置 BugTrap 服务器

BugTrap 服务器和 BugTrap Web 都从结构几乎相同的 XML 文件中读取配置。

5.3.1 BugTrap 服务器配置文件

BugTrap 服务器配置存储在 BugTrapServer.exe.config XML 文件中,该文件必须与 BugTrapServer.exe(.NET 版本)或 JBugTrapServer.jar(Java 版本)文件位于同一文件夹中。

BugTrap 服务器配置文件具有以下结构:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
 <configSections>
 <section name="applicationSettings"
type="BugTrapServer.ApplicationSettingsHandler, BugTrapServer"/>
 </configSections>
 <applicationSettings>
 <logEvents>true</logEvents>
 <serverPort>9999</serverPort>
 <reportPath>c:\reports</reportPath>
 <reportsLimit>-1</reportsLimit>
 <maxReportSize>-1</maxReportSize>
 <smtpHost>smtp.server.address</smtpHost>
 <!--<smtpPort>25</smtpPort>-->
 <smtpUser>username</smtpUser>
 <smtpPassword>password</smtpPassword>
 <senderAddress>sender@email.com</senderAddress>
 <reportFileExtensions>log,xml,zip</reportFileExtensions>
 <applicationList>
 <!--
 <application>FirstApp</application>
 <application version="1.2">SecondApp</application>
 -->
 </applicationList>
 </applicationSettings>
</configuration>

这些参数如下所述。

5.3.2 BugTrap Web 服务器配置文件

BugTrap Web 服务器可以使用几乎相同的 XML 文件进行配置,但此文件应位于 BugTrap Web 服务器应用程序文件夹中,并且应称为 Web.config。通常,此文件包含有关 .NET Web 应用程序的标准信息,但 BugTrap Web 服务器配置文件具有几个自定义字段:

<?xml version="1.0"?>
<configuration>
 <configSections>
 <section name="applicationSettings"
type="BugTrapServer.ApplicationSettingsHandler"/>
 </configSections>
 <system.web>
 <compilation debug="false" urlLinePragmas="true"/>
 <authentication mode="None"/>
 <customErrors mode="RemoteOnly"/>
 <sessionState mode="Off" cookieless="true"/>
 <!--<trust level="BugTrapWebTrust"/>-->
 </system.web>
<applicationSettings>
 <logEvents>false</logEvents>
 <serverPort>9999</serverPort>
 <reportPath>reports</reportPath>
 <reportsLimit>-1</reportsLimit>
 <maxReportSize>-1</maxReportSize>
 <smtpHost>smtp.server.address</smtpHost>
 <!--<smtpPort>25</smtpPort>-->
 <smtpUser>username</smtpUser>
 <smtpPassword>password</smtpPassword>
 <senderAddress>sender@email.com</senderAddress>
 <reportFileExtensions>log,xml,zip</reportFileExtensions>
 <applicationList>
 <!--
 <application>FirstApp</application>
 <application version="1.2">SecondApp</application>
 -->
 </applicationList>
 </applicationSettings>
</configuration>

5.3.3 配置设置

这两个文件具有在 appSettings 部分中指定的相同参数集:

ParameterDescription
logEvents指示是否在系统事件日志中报告 Start、Stop 命令和错误消息。
serverPort服务器侦听传入错误报告的端口号。此数字必须与 BT_SetSupportServer()中指定的值相同。
reportPath存储报表的存储库的路径。
reportsLimit服务器为同一产品接受的最大报告数。-1 表示报告数量不受限制。
maxReportSize报告文件的最大可接受大小。-1 表示报告大小不受限制。
smtpHostSMTP 服务器的地址,用于向产品支持发送有关传入报告的通知电子邮件。如果此字段为空,则电子邮件通知将被禁用。
smtpPort此字段可用于覆盖 SMPT 服务器的默认端口号。
smtpUser用于建立与 SMTP 服务器的连接的用户名。
smtpPassword用于建立与 SMTP 服务器的连接的密码。
senderAddress发送的有关新错误的通知电子邮件的发件人地址(“发件人”字段)。
reportFileExtensions以冒号分隔的服务器接受的报表文件扩展名列表。如果此列表为空,则不会筛选报表文件。在大多数情况下,您不应更改此设置。

您可以在 applicationList 部分中配置接受的产品列表。BugTrap 服务器拒绝 applicationList 部分中未列出的产品的报告。如果您想接受来自任何应用程序的报告,您可以将此部分留空。

5.3.4 系统事件日志和 BugTrap Web 服务器

默认情况下,BugTrap Web 服务器不会将错误信息写入系统事件日志。如果要利用错误日志记录,可以在 Web.config 文件中设置 logEvents=true。此更改需要执行很少的额外步骤,因为 ASP.NET 应用程序已禁用对系统事件日志的访问。BugTrap 会安装自定义安全策略文件,该文件会覆盖 BugTrap Web 服务器的默认安全设置。此文件称为 bugtrap_web_trust.config,通常位于 C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\CONFIG中。此文件夹还包括计算机级 Web.config 文件。打开 Web.config 文件,在此文件的顶部,您将注意到可用安全策略的列表:

<location allowOverride="true">
 <system.web>
 <securityPolicy>
 <trustLevel name="Full" policyFile="internal" />
 <trustLevel name="High" policyFile="web_hightrust.config" />
 ...
 </securityPolicy>
 <trust level="Full" originUrl="" />
 </system.web>
</location>

向此列表添加一个新策略,如下所示:

<location allowOverride="true">
 <system.web>
 <securityPolicy>
 <trustLevel name="Full" policyFile="internal" />
 <trustLevel name="High" policyFile="web_hightrust.config" />
 <trustLevel name="Medium" policyFile="web_mediumtrust.config" />
 <trustLevel name="Low" policyFile="web_lowtrust.config" />
 <trustLevel name="Minimal" policyFile="web_minimaltrust.config" />
 <trustLevel name="BugTrapWebTrust"
 policyFile="bugtrap_web_trust.config" />
 </securityPolicy>
 <trust level="Full" originUrl="" />
 </system.web>
</location>

保存更改并打开本地 BugTrap Web.config 文件(通常存储在 C:\Inetpub\ wwwroot\BugTrapWebServer 中)。

找到以下行:<!-- <trust level=“BugTrapWebTrust”/> -->

从 XML 标记中删除注释并保存更改。现在 BugTrap Web 服务器应该在自定义安全策略中运行。

5.3.5 BugTrap 服务器存储库

BugTrap 服务器为不同的项目创建文件夹,并在这些文件夹之间排列报告。每个报表都有自己唯一的名称以避免冲突:

5.4 结论

BugTrap 软件包为您提供了一套全面的工具,这些工具可以跟踪和管理大多数环境中大多数类型应用程序中的意外错误。它简化了错误分析和问题修复,使产品更加稳定,提高了产品支持的质量。BugTrap 降低了整个产品生命周期的维护成本。

附录 A – 文件夹列表

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值