Delphi:基于jcl的Bugsplat Crash收集单元
//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收集单元的更多相关文章
- 基于云开发开发 Web 应用(四):引入统计及 Crash 收集
在完成了产品的基础开发以后,接下来需要进行一些周边的工作,这些周边工具将会帮助下一步优化产品. 为什么要加应用统计和 Crash 收集 不少开发者在开发的时候,很少会意识到需要添加应用统计和 Cras ...
- 漫谈iOS Crash收集框架
漫谈iOS Crash收集框架 Crash日志收集 为了能够第一时间发现程序问题,应用程序需要实现自己的崩溃日志收集服务,成熟的开源项目很多,如 KSCrash,plcrashreporter,C ...
- 基于Flume的美团日志收集系统(二)改进和优化
在<基于Flume的美团日志收集系统(一)架构和设计>中,我们详述了基于Flume的美团日志收集系统的架构设计,以及为什么做这样的设计.在本节中,我们将会讲述在实际部署和使用过程中遇到的问 ...
- 基于Flume的美团日志收集系统(一)架构和设计
美团的日志收集系统负责美团的所有业务日志的收集,并分别给Hadoop平台提供离线数据和Storm平台提供实时数据流.美团的日志收集系统基于Flume设计和搭建而成. <基于Flume的美团日志收 ...
- 基于Flume的美团日志收集系统(一)架构和设计【转】
美团的日志收集系统负责美团的所有业务日志的收集,并分别给Hadoop平台提供离线数据和Storm平台提供实时数据流.美团的日志收集系统基于Flume设计和搭建而成. <基于Flume的美团日志收 ...
- RED_HAWK:基于PHP实现的信息收集与SQL注入漏洞扫描工具
无事早上就去逛freebuf看到一款不错的工具,打算介绍给大家 RED_HAWK:基于PHP实现的信息收集与SQL注入漏洞扫描工具 RED HAWK 最新版本:v1.0.0[2017年6月11日] 下 ...
- 基于spring-boot的应用程序的单元+集成测试方案
目录 概述 概念解析 单元测试和集成测试 Mock和Stub 技术实现 单元测试 测试常规的bean 测试Controller 测试持久层 集成测试 从Controller开始测试 从中间层开始测试 ...
- 转:基于Flume的美团日志收集系统(一)架构和设计
美团的日志收集系统负责美团的所有业务日志的收集,并分别给Hadoop平台提供离线数据和Storm平台提供实时数据流.美团的日志收集系统基于Flume设计和搭建而成. <基于Flume的美团日志收 ...
- 基于Flume的美团日志收集系统 架构和设计 改进和优化
3种解决办法 https://tech.meituan.com/mt-log-system-arch.html 基于Flume的美团日志收集系统(一)架构和设计 - https://tech.meit ...
随机推荐
- day06-三元表达式
python中没有其他语言中的三元表达式,不过有类似的实现方法 其他语言中,例如java的三元表达式是这样int a = 1;String b = "";b = a > 1? ...
- fb发布打包外部资源
将资源放在src文件夹下面即可 然后在打包那就会看到资源,勾上即可
- MySQL数据库备份工具mysqldump的使用(转)
说明:MySQL中InnoDB和MyISAM类型数据库,这个工具最新版本好像都已经支持了,以前可能存在于MyISAM的只能只用冷备份方式的说法. 备份指定库: mysqldump -h127.0.0. ...
- AS_简单的开始
1.注释 单行注释 // 多行注释 /* src */ 2.变量 变量名,可以包含字母.数字.下划线.$.但不以数字开头. 变量类型,是严格数据类型.AS有静态类型 ...
- 去除文件BOM头工具
<?php /** * 用法:复制以下代码至新建的php文件中,将该php文件放置项目目录,运行即可.代码来源于网络. * chenwei 注. */ header('content-Type: ...
- Jsp基本语法 第二节
关于JSP的声明 即在JSP页面定义方法或者变量: <%!Java代码%> 在JSP页面中执行的表达式:<%=表达式%> 这个里尤其注意不能以:结束 JSP页面生命周期 ...
- C++ CTreeview的checkbox使用方法
1. 消息事件 (1)鼠标点击当前ITEM的CHECKBOX:引发NM_CLICK事件并传递TVHT_ONITEMSTATEICON. (2)鼠标点击当前ITEM的TEXT:引发NM_CLIC ...
- 【转】Unity网格合并_材质合并
原帖请戳:Unity网格合并_材质合并 写在前面: 从优化角度,Mesh需要合并. 从换装的角度(这里指的是换形状.换组成部件的换装,而不是挂点型的换装),都需要网格合并.材质合并.如果是人物的换装, ...
- 关于php laravel5.1框架出现路由找不到的情况
开启apache模块在apache配置文件LoadModule rewrite_module modules/mod_rewrite.so前面的#去掉然后修改 vim /etc/init.d/htt ...
- shell脚本中比较两个小数的办法
具体情况#man bc 然而对小数进行比较的相关方法有几个: 1. 自己的解决方法,判断小数点后最多有几位数(N),然后对将要比较的两个数值进行 乘与10的N次方 也就是将小数点去掉来进行比较(小数点 ...