//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. iOS 视图间的几种通信方式

    注:此处视图为广义上的视图,不限于View,ViewController之类的都算. 大致分为三种,Notification, delegate, block 例: 假设要在A视图中调起B视图,B视图 ...

  2. Mybatis高级应用-2

    文章内容简介 1.回顾 2.Mybatis配置文件解析 3.Mybatis映射文件解析 ResultMap标签使用 自定义返回值处理(Map) 关联映射 主键映射 一.回顾 Mybatis是ORM(o ...

  3. 【362】python 正则表达式

    参考:正则表达式 - 廖雪峰 参考:Python3 正则表达式 - 菜鸟教程 参考:正则表达式 - 教程 re.match 尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,match ...

  4. ORA-00600: internal error code, arguments: [4193]问题解决

    操作环境 SuSE+Oracle11gR2 问题现象 单板宕机自动重启后,ORACLE运行不正常,主要表现如下: 1.执行shutdown immedate停止数据库时,提示ORA-00600: in ...

  5. Hibernate学习笔记1.1(简单插入数据)

    Hibernate是把以前的jdbc连接数据库的操作进行了一系列友好的封装,最好只用调用save即可,即将sql语句的这部分操作转化为面向对象的 Hibernate资源准备: 文档目录结构: 1.网址 ...

  6. /src/struts.xml

    <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC         ...

  7. 安装 gradle

    Gradle是一种现在很流程的构建工具,目前基本和Maven平分天下,而且大有取而代之的趋势.这篇教程教大家怎么在linux上安装Gradle. 一.获得一台linux服务器 要在linux下安装gi ...

  8. js jq 实现鼠标经过div背景以进度条方式 变宽,鼠标离开变小,同时文字颜色和原来不一样

    <!DOCTYPE html> <html> <head> <title></title> <script typet="t ...

  9. 微擎框架下拉分页(使用js模板引擎)

    1.需要分页的页面,引入一下文件 <script language="javascript" src="\addons\{$_GPC['m']}\template\ ...

  10. vl_sift函数用法

    I = vl_impattern('roofs1') ; image(I) ; %vl_sift函数的输入是一个单精度的灰度图像,灰度值区间归一化到[, ]. %因此图像 I 需要通过下面的函数转成相 ...