//BugSplat Crash模拟.net数据封装

unit uBugSplat;

interface

uses
Windows, SysUtils, Classes, StrUtils, ShellAPI, JclDebug; type
TBugSplat = class
class var
Instance: TBugSplat;
private
FBSPath: string;
FDBName: string;
FAppName: string;
FVersion: string;
FQuietMode: Boolean;
FUser: string;
FEMail: string;
FUserDescription: string;
FLogPath: string;
FAdditionalFiles: TStrings; //生成Crash报告
procedure CreateReport(E: Exception);
procedure WriteStack(sw: TStreamWriter; E: Exception);
function GetTempPath: string;
function ExecProcess(AppName, Params: string): Boolean;
procedure AddAdditionalFileFromFolder(const AFolder: string);
public
constructor Create(const ADBName, AAppName, AVersion: string); //Exception事件接管
procedure AppException(Sender: TObject; E: Exception);
procedure AddAdditionalFile(const AFileName: string); property User: string read FUser write FUser;
property EMail: string read FEmail write FEmail;
property UserDescription: string read FUserDescription write FUserDescription;
property QuietMode: Boolean read FQuietMode write FQuietMode;
property LogPath: string read FLogPath write FLogPath;
property AdditionalFiles: TStrings read FAdditionalFiles write FAdditionalFiles;
end; implementation { TBugSplat } constructor TBugSplat.Create(const ADBName, AAppName, AVersion: string);
begin
FDBName := ADBName;
FAppName := AAppName;
FVersion := AVersion;
//FUserDescription := 'Crash of ' + FAppName;
FQuietMode := True;
FBSPath := ExtractFilePath(ParamStr()) + 'BsSndRpt.exe'; FAdditionalFiles := TStringList.Create;
if Instance = nil then Instance := Self;
end; procedure TBugSplat.AddAdditionalFile(const AFileName: string);
begin
if FileExists(AFileName) then
FAdditionalFiles.Append(AFileName);
end; procedure TBugSplat.WriteStack(sw: TStreamWriter; E: Exception);
function RPos(const substr, str: RawByteString): Integer;
begin
Result := Length(str) - Pos(ReverseString(substr), ReverseString(str)) + ;
end; var
i: Integer;
s, sFileName, sLineNumber: string;
sl: TStrings;
begin
sl := TStringList.Create;
try
sl.Text := E.StackTrace;
//Stack头
sw.WriteLine('<report>');
sw.WriteLine(' <process>');
sw.WriteLine(' <exception>');
sw.WriteLine(' <func><![CDATA[' + sl[] + ']]></func>');
sw.WriteLine(' <code><![CDATA[' + E.ClassName + ': ' + E.Message + ']]></code>');
sw.WriteLine(' <explanation><![CDATA[' + FAppName + ']]></explanation>');
sw.WriteLine(' <file><![CDATA[]]></file>');
sw.WriteLine(' <line><![CDATA[]]></line>');
sw.WriteLine(' <registers></registers>');
sw.WriteLine(' </exception>');
sw.WriteLine(' <modules numloaded="0"></modules>');
sw.WriteLine(' <threads count="1">');
sw.WriteLine(' <thread id="' + IntToStr(GetCurrentThreadId()) + '" current="yes" event="yes" framecount="1">'); //StackTrace
//[004560E8] Controls.TWinControl.MainWndProc (Line 9065, "Controls.pas")
for i := to sl.Count - do
begin
sFileName := '';
sLineNumber := '';
s := sl[i];
if Pos('"', s) <> then
sFileName := Copy(s, Pos('"', s) + Length('"'), RPos('"', s) - Pos('"', s) - Length('"'));
if Pos('Line', s) <> then
sLineNumber := Copy(s, Pos('Line ', s) + Length('Line '), Pos(',', s) - Pos('Line ', s) - Length('Line ')); sw.WriteLine(' <frame>');
sw.WriteLine(' <symbol><![CDATA[' + s + ']]></symbol>');
sw.WriteLine(' <arguments></arguments>');
sw.WriteLine(' <locals></locals>');
sw.WriteLine(' <file>' + sFileName + '</file>');
sw.WriteLine(' <line>' + sLineNumber + '</line>');
sw.WriteLine(' </frame>');
end;
sw.WriteLine(' </thread>');
sw.WriteLine(' </threads>');
sw.WriteLine(' </process>');
sw.WriteLine('</report>');
finally
sl.Free;
end;
end; procedure TBugSplat.AddAdditionalFileFromFolder(const AFolder: string);
var
sr: TSearchRec;
s: string;
begin
//取其中文件入附加文件列表
if FindFirst(AFolder + '\*.*', faAnyFile, sr) = then
begin
try
repeat
if (sr.Name = '.') or (sr.Name = '..') then Continue; s := IncludeTrailingPathDelimiter(AFolder) + sr.Name;
if sr.Attr and faDirectory = then
FAdditionalFiles.Append(s)
else if DirectoryExists(s) then
AddAdditionalFileFromFolder(s);
until FindNext(sr) <> ;
finally
FindClose(sr);
end;
end;
end; procedure TBugSplat.AppException(Sender: TObject; E: Exception);
begin
if not FileExists(FBSPath) then
raise Exception.Create('BsSndRpt.exe does not exists!'); CreateReport(E);
end; procedure TBugSplat.CreateReport(E: Exception);
var
i: Integer;
xmlName, iniName, args: string;
sw: TStreamWriter;
begin
//写.net stack解析文件
if Trim(E.StackTrace) <> '' then
begin
xmlName := IncludeTrailingPathDelimiter(GetTempPath()) + 'stack.net';
if FileExists(xmlName) then DeleteFile(xmlName);
sw := TStreamWriter.Create(xmlName);
try
WriteStack(sw, E);
finally
sw.Close;
end;
end; //写ini配置文件
iniName := IncludeTrailingPathDelimiter(GetTempPath()) + 'bs.ini';
if FileExists(iniName) then DeleteFile(iniName);
sw := TStreamWriter.Create(iniName);
try
sw.WriteLine('[BugSplat]');
sw.WriteLine('Vendor=' + FDBName);
sw.WriteLine('Application=' + FAppName);
sw.WriteLine('Version=' + FVersion);
if FileExists(xmlName) then
sw.WriteLine('DotNet=' + xmlName);
if FUser <> '' then
sw.WriteLine('User=' + FUser);
if FEMail <> '' then
sw.WriteLine('Email=' + FEMail);
if FUserDescription <> '' then
sw.WriteLine('UserDescription=' + FUserDescription); //附加文件
if DirectoryExists(FLogPath) then AddAdditionalFileFromFolder(FLogPath);
for i := to FAdditionalFiles.Count - do
begin
if FileExists(FAdditionalFiles[i]) then
sw.WriteLine('AdditionalFile' + IntToStr(i) + '=' + FAdditionalFiles[i]);
end;
finally
sw.Close;
end; //发送
args := '/i ' + '"' + iniName + '"';
if FQuietMode then
args := args + ' /q';
ExecProcess(FBSPath, args);
end; function TBugSplat.ExecProcess(AppName, Params: string): Boolean;
var
// Structure containing and receiving info about application to start
ShellExInfo: TShellExecuteInfo;
begin
FillChar(ShellExInfo, SizeOf(ShellExInfo), );
with ShellExInfo do
begin
cbSize := SizeOf(ShellExInfo);
fMask := see_Mask_NoCloseProcess;
Wnd := ;
lpFile := PChar(AppName);
lpParameters := PChar(Params);
nShow := SW_SHOWNORMAL;
end; Result := ShellExecuteEx(@ShellExInfo);
end; function TBugSplat.GetTempPath: string;
var
p: array[..MAX_PATH] of Char;
begin
Windows.GetTempPath(MAX_PATH, p);
Result := StrPas(p);
end; //Exception事件挂接...用此其取为空,其下面的可以
//function GetExceptionStackInfoProc(P: PExceptionRecord): Pointer;
//var
// LLines: TStringList;
// LText: String;
// LResult: PChar;
//begin
// LLines := TStringList.Create;
// try
// JclLastExceptStackListToStrings(LLines, True, True, True, True);
// LText := LLines.Text;
// LResult := StrAlloc(Length(LText));
// StrCopy(LResult, PChar(LText));
// Result := LResult;
// finally
// LLines.Free;
// end;
//end; function GetExceptionStackInfoProc(P: PExceptionRecord): Pointer;
var
LLines: TStringList;
LText: String;
LResult: PChar;
jcl_sil: TJclStackInfoList;
begin
LLines := TStringList.Create;
try
jcl_sil := TJclStackInfoList.Create(False, , p.ExceptAddr, False, nil, nil);
try
jcl_sil.AddToStrings(LLines); //, true, true, true, true);
finally
FreeAndNil(jcl_sil);
end;
LText := LLines.Text;
LResult := StrAlloc(Length(LText));
StrCopy(LResult, PChar(LText));
Result := LResult;
finally
LLines.Free;
end;
end; function GetStackInfoStringProc(Info: Pointer): string;
begin
Result := string(PChar(Info));
end; procedure CleanUpStackInfoProc(Info: Pointer);
begin
StrDispose(PChar(Info));
end; initialization
// Start the Jcl exception tracking and register our Exception
// stack trace provider.
if JclStartExceptionTracking then
begin
Exception.GetExceptionStackInfoProc := GetExceptionStackInfoProc;
Exception.GetStackInfoStringProc := GetStackInfoStringProc;
Exception.CleanUpStackInfoProc := CleanUpStackInfoProc;
end; finalization
// Stop Jcl exception tracking and unregister our provider.
if JclExceptionTrackingActive then
begin
Exception.GetExceptionStackInfoProc := nil;
Exception.GetStackInfoStringProc := nil;
Exception.CleanUpStackInfoProc := nil;
JclStopExceptionTracking;
end; end.

调用方法:

procedure InitBugSplat();
var
sVersion: string;
begin
sVersion := GetFileVersion(Application.ExeName);
if TBugSplat.Instance = nil then
TBugSplat.Create('XXX_DSB', SDefaultProductName, sVersion); Application.OnException := TBugSplat.Instance.AppException;
TBugSplat.Instance.LogPath := IncludeTrailingBackslash(g_DocumentPath) + 'Log';
TBugSplat.Instance.EMail := 'xx@xx.com';
TBugSplat.Instance.UserDescription := 'DSB_' + sVersion;
end;

以做备忘

Delphi:基于jcl的Bugsplat Crash收集单元的更多相关文章

  1. 基于云开发开发 Web 应用(四):引入统计及 Crash 收集

    在完成了产品的基础开发以后,接下来需要进行一些周边的工作,这些周边工具将会帮助下一步优化产品. 为什么要加应用统计和 Crash 收集 不少开发者在开发的时候,很少会意识到需要添加应用统计和 Cras ...

  2. 漫谈iOS Crash收集框架

    漫谈iOS Crash收集框架   Crash日志收集 为了能够第一时间发现程序问题,应用程序需要实现自己的崩溃日志收集服务,成熟的开源项目很多,如 KSCrash,plcrashreporter,C ...

  3. 基于Flume的美团日志收集系统(二)改进和优化

    在<基于Flume的美团日志收集系统(一)架构和设计>中,我们详述了基于Flume的美团日志收集系统的架构设计,以及为什么做这样的设计.在本节中,我们将会讲述在实际部署和使用过程中遇到的问 ...

  4. 基于Flume的美团日志收集系统(一)架构和设计

    美团的日志收集系统负责美团的所有业务日志的收集,并分别给Hadoop平台提供离线数据和Storm平台提供实时数据流.美团的日志收集系统基于Flume设计和搭建而成. <基于Flume的美团日志收 ...

  5. 基于Flume的美团日志收集系统(一)架构和设计【转】

    美团的日志收集系统负责美团的所有业务日志的收集,并分别给Hadoop平台提供离线数据和Storm平台提供实时数据流.美团的日志收集系统基于Flume设计和搭建而成. <基于Flume的美团日志收 ...

  6. RED_HAWK:基于PHP实现的信息收集与SQL注入漏洞扫描工具

    无事早上就去逛freebuf看到一款不错的工具,打算介绍给大家 RED_HAWK:基于PHP实现的信息收集与SQL注入漏洞扫描工具 RED HAWK 最新版本:v1.0.0[2017年6月11日] 下 ...

  7. 基于spring-boot的应用程序的单元+集成测试方案

    目录 概述 概念解析 单元测试和集成测试 Mock和Stub 技术实现 单元测试 测试常规的bean 测试Controller 测试持久层 集成测试 从Controller开始测试 从中间层开始测试 ...

  8. 转:基于Flume的美团日志收集系统(一)架构和设计

    美团的日志收集系统负责美团的所有业务日志的收集,并分别给Hadoop平台提供离线数据和Storm平台提供实时数据流.美团的日志收集系统基于Flume设计和搭建而成. <基于Flume的美团日志收 ...

  9. 基于Flume的美团日志收集系统 架构和设计 改进和优化

    3种解决办法 https://tech.meituan.com/mt-log-system-arch.html 基于Flume的美团日志收集系统(一)架构和设计 - https://tech.meit ...

随机推荐

  1. dshow采集过程

    捕捉静态图片常用的filter是Sample Graber filter,它的用法参考手册.然后将捕捉filter的静态PIN连接到Sample Grabber,再将Sample Grabber连接到 ...

  2. Python2 错误记录1File "<string>", line 1, in <module> NameError: name 'f' is not defined

    Python 2下 count = 0 while count < 3: user = input('>>>') pwd = input('>>>') if ...

  3. lientDataset的Delta与XML相互转换

    一个ClientDataset的Delta与XML相互转换的文章:大家都知道TClientDataSet的Delta属性保存数据集的变化,但是Delta是OleVariant类型的属性,这样如果用De ...

  4. Notepad++好用的功能和插件

    Notepad++是一款Windows环境下免费开源的代码编辑器,支持Python,shell,Java等主流语言编写.本文主要描述Notepad++一些好用但是容易忽视的功能. 1.根据文件内容查找 ...

  5. 关于C# WinForm中进度条的实现方法

    http://www.cnblogs.com/Sue_/articles/2024932.html 进度条是一个软件人性化考虑之一,他给用户的感觉就是程序内部在不停的动作,执行到了什么程度,而不是整个 ...

  6. 去除文件BOM头工具

    <?php /** * 用法:复制以下代码至新建的php文件中,将该php文件放置项目目录,运行即可.代码来源于网络. * chenwei 注. */ header('content-Type: ...

  7. 尚未解决的webpack问题

    91% additional asset processing 打包过程中,在91%的时候会出现卡顿几秒 在js,css使用chunkhash替代hash 字体和图片:没有此chunkhash,只有h ...

  8. shiro中的授权

  9. ubuntu上装MySQL遇到的问题及解决办法

    验证原有主机上是否已安装mysql                运行sudo netstat -tap | grep mysql命令查看是否有Mysql的端口 查看到mysql已安装上了: 启动my ...

  10. 吴裕雄 python深度学习与实践(5)

    import numpy as np data = np.mat([[1,200,105,3,False], [2,165,80,2,False], [3,184.5,120,2,False], [4 ...