forked from layerfsd/Roomer-PMS-1
-
Notifications
You must be signed in to change notification settings - Fork 1
/
RoomerExceptionHandling.pas
195 lines (164 loc) · 5.53 KB
/
RoomerExceptionHandling.pas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
unit RoomerExceptionHandling;
interface
uses
SysUtils
;
type
ERoomerException = class(Exception)
public
/// <summary>
/// If set to false, the exception will only be logged (if logging is active) and the user will not be
/// notified.
/// </summary>
function ShowToUSer: boolean; virtual;
end;
ERoomerUserException = class(ERoomerException)
public
function ShowToUSer: boolean; override;
end;
TRoomerExceptionHandler = class(TObject)
private
FExceptionsLoggingActive: boolean;
FExceptionLogPath: string;
FLogFileName: string;
FLogStackTrace: boolean;
procedure SetExceptionLogPath(const Value: string);
function GetFullLogFilePath: string;
procedure LogStackTrace(ExceptObj: TObject; ExceptAddr: Pointer; IsOS: boolean);
function AppendToLogfile(const line : string; addDate : boolean = false) : boolean;
public
constructor Create(const aLogFileName: string = '');
/// <summary>
/// Eventhandler for Application.OnException
/// </summary>
procedure ExceptionHandler(Sender: TObject; E: Exception);
property ExceptionsLoggingActive: boolean read FExceptionsLoggingActive write FExceptionsLoggingActive;
property ExceptionLogPath: string read FExceptionLogPath write SetExceptionLogPath;
property ExceptionLogFilename: string read FLogFileName write FLogFileName;
property FullLogfilePath: string read GetFullLogFilePath;
property LogStackTraceOnException: boolean read FLogStackTrace write FLogStackTrace;
end;
implementation
uses
Classes
, uRoomerExceptions
, JclDebug, JclHookExcept, TypInfo
// , uSplashRoomer
, VCL.Forms
, IOUtils
, uUtils
, Windows
;
procedure TRoomerExceptionHandler.LogStackTrace(ExceptObj: TObject; ExceptAddr: Pointer; IsOS: boolean);
var
TmpS: string;
ModInfo: TJclLocationInfo;
StackTrace: TStringlist;
begin
if ExceptionsLoggingActive then
begin
AppendToLogFile('--------------------------------------------------------------------------------------------', true);
TmpS := ExceptObj.ClassName + ' occurred';
if ExceptObj is Exception then
TmpS := TmpS + ': ' + Exception(ExceptObj).message;
if IsOS then
TmpS := TmpS + ' (OS Exception)';
AppendToLogfile(TmpS, true);
ModInfo := GetLocationInfo(ExceptAddr);
AppendToLogfile(Format(' Exception occured at $%p (Module "%s", Procedure "%s", Unit "%s", Line %d)',
[ModInfo.Address, ModInfo.UnitName, ModInfo.ProcedureName, ModInfo.SourceName, ModInfo.LineNumber]), true);
StackTrace := TStringlist.Create;
try
JclLastExceptStackListToStrings(StackTrace, True, False, True, True);
for TmpS in StackTrace do
AppendToLogfile(TmpS, true);
finally
StackTrace.Free;
end;
AppendToLogFile('--------------------------------------------------------------------------------------------', true);
end;
end;
constructor TRoomerExceptionHandler.Create(const aLogFileName: string = '');
begin
if not aLogFileName.IsEmpty then
begin
ExceptionLogPath := TPath.GetDirectoryName(aLogFileName);
ExceptionLogFilename := TPath.GetFileName(aLogFileName);
end
else
begin
if ParameterByName('LogPath') <> '' then
ExceptionLogPath := ParameterByName('LogPath')
else
ExceptionLogPath := TPath.GetDirectoryName(Application.ExeName);
ExceptionLogFilename := TPath.GetFileNameWithoutExtension(Application.ExeName) + '.log';
end;
{$IFDEF DUMP_STACKTRACE}
FLogStackTrace := True;
{$ENDIF}
end;
function TRoomerExceptionHandler.AppendToLogfile(const line : string; addDate : boolean = false) : boolean;
var
aText : String;
begin
result := true;
try
aText := line;
if addDate then
aText := format('%s %s | %s', [FormatDateTime('yyyy-mm-dd', now),
FormatDateTime('hh:nn:ss', now),
aText]);
TFile.AppendAllText(FullLogfilePath, ' | ' + aText + #13#10);
OutputDebugString(PChar(aText));
except
result := false;
end;
end;
procedure TRoomerExceptionHandler.ExceptionHandler(Sender: TObject; E: Exception);
begin
if FLogStackTrace then
LogStackTrace(E, ExceptAddr, E is EOSError);
// try
// TSplashFormManager.TryHideForm;
// except
// end;
//
if (E is EDivByZero) or (E is ERangeError) or (E is ERoomerOfflineAssertionException) or
(E is EInvalidPointer) or
(E is EInvalidOp) or (E is EAbstractError) or (E is EIntOverflow) or (E is EAccessViolation) or (E is EControlC) or
(E is EPrivilege) or (E is EInvalidCast)
or (E is EVariantError) or (E is EAssertionFailed) or (E is EIntfCastError) or
(pos('out of bounds', ANSIlowercase(E.message)) > 0) or
(E is ERoomerException and not ERoomerException(E).SHowToUser) then
begin
if ExceptionsLoggingActive then
ExceptionsLoggingActive := AppendToLogfile(E.message, true);
end
else
begin
Application.ShowException(E);
end;
end;
function TRoomerExceptionHandler.GetFullLogFilePath: string;
begin
Result := TPath.Combine(FExceptionLogPath, FLogFileName);
end;
procedure TRoomerExceptionHandler.SetExceptionLogPath(const Value: string);
begin
FExceptionLogPath := Value;
forceDirectories(ExceptionLogPath);
end;
{ ERoomerException }
function ERoomerException.ShowToUSer: boolean;
begin
Result := false;
end;
{ ERoomerUserException }
function ERoomerUserException.ShowToUSer: boolean;
begin
Result := true;
end;
initialization
JclStackTrackingOptions := JclStackTrackingOptions + [stRawMode, stExceptFrame];
JclStartExceptionTracking;
end.