mirror of
https://github.com/keymanapp/keyman.git
synced 2026-08-06 08:55:34 +00:00
271 lines
7.3 KiB
ObjectPascal
271 lines
7.3 KiB
ObjectPascal
(*
|
|
Name: klog
|
|
Copyright: Copyright (C) SIL International.
|
|
Documentation:
|
|
Description:
|
|
Create Date: 1 Aug 2006
|
|
|
|
Modified Date: 8 Jun 2012
|
|
Authors: mcdurdin
|
|
Related Files:
|
|
Dependencies:
|
|
|
|
Bugs:
|
|
Todo:
|
|
Notes:
|
|
History: 01 Aug 2006 - mcdurdin - Disable logging with KLOGGING define
|
|
14 Sep 2006 - mcdurdin - Add Current Tick Count to logs (for correlation with system.log)
|
|
04 May 2012 - mcdurdin - I3309 - V9.0 - Migrate to Delphi XE2, VS2010, svn 1.7
|
|
04 May 2012 - mcdurdin - I3310 - V9.0 - Unicode in Delphi fixes
|
|
08 Jun 2012 - mcdurdin - I3310 - V9.0 - Unicode in Delphi fixes
|
|
*)
|
|
unit klog; // I3309
|
|
|
|
interface
|
|
|
|
{DEFINE KLOGGING}
|
|
|
|
{$IFDEF KLOGGING}
|
|
uses
|
|
Classes;
|
|
{$ENDIF}
|
|
|
|
type
|
|
TKLog = class
|
|
private
|
|
{$IFDEF KLOGGING}
|
|
FAppName: string;
|
|
FLogFileName: string;
|
|
FLogFile: TextFile;
|
|
FMethodStack: TStringList;
|
|
FFileOpen: Boolean;
|
|
function VarRecToString(const vr: TVarRec): string;
|
|
{$ENDIF}
|
|
public
|
|
constructor Create;
|
|
destructor Destroy; override;
|
|
procedure Log(const msg: string); overload;
|
|
procedure Log(const msg: string; const fmt: array of const); overload;
|
|
procedure LogError(const msg: string); overload;
|
|
procedure LogError(const msg: string; const fmt: array of const); overload;
|
|
procedure MethodEnter(instance: TObject; const name: string; const parameters: array of const);
|
|
procedure MethodExit(instance: TObject; const name: string); overload;
|
|
procedure MethodExit(instance: TObject; const name: string; const result: array of const); overload;
|
|
end;
|
|
|
|
function KL: TKLog;
|
|
function KLEnabled: Boolean;
|
|
|
|
implementation
|
|
|
|
{$IFDEF KLOGGING}
|
|
uses
|
|
Variants, Windows, SysUtils, ErrorControlledRegistry, KeymanPaths, VersionInfo, Unicode;
|
|
{$ENDIF}
|
|
|
|
var
|
|
FKLog: TKLog = nil;
|
|
|
|
function KL: TKLog;
|
|
begin
|
|
if not Assigned(FKLog) then FKlog := TKLog.Create;
|
|
Result := FKlog;
|
|
end;
|
|
|
|
{ TKLog }
|
|
|
|
{$WARN SYMBOL_PLATFORM OFF}
|
|
constructor TKLog.Create;
|
|
{$IFDEF KLOGGING}
|
|
|
|
function DirectoryExists(const Name: string): Boolean;
|
|
var
|
|
Code: Dword;
|
|
begin
|
|
Code := GetFileAttributes(PChar(Name));
|
|
Result := (Code <> $FFFFFFFF) and (FILE_ATTRIBUTE_DIRECTORY and Code <> 0);
|
|
end;
|
|
|
|
var
|
|
buf: array[0..260] of char;
|
|
begin
|
|
inherited Create;
|
|
|
|
FMethodStack := TStringList.Create;
|
|
GetModuleFileName(hInstance, buf, 260); FAppName := ChangeFileExt(ExtractFileName(buf),'');
|
|
FLogFileName := TKeymanPaths.ErrorLogPath(FAppName);
|
|
Log(StringOfChar('=', 160));
|
|
Log('Starting application %s, version %s', [FAppName, GetFileVersionString(FAppName)]);
|
|
Log('Command line: %s', [String(CmdLine)]);
|
|
{$ELSE}
|
|
begin
|
|
inherited Create;
|
|
{$ENDIF}
|
|
end;
|
|
{$WARN SYMBOL_PLATFORM DEFAULT}
|
|
|
|
destructor TKLog.Destroy;
|
|
{$IFDEF KLOGGING}
|
|
var
|
|
i: Integer;
|
|
begin
|
|
for i := 0 to FMethodStack.Count - 1 do
|
|
Log('Unterminated method '+FMethodStack[i]);
|
|
FMethodStack.Clear;
|
|
Log('Stopping application '+FAppName);
|
|
Log(StringOfChar('=', 160));
|
|
FMethodStack.Free;
|
|
if FFileOpen then CloseFile(FLogFile);
|
|
{$ELSE}
|
|
begin
|
|
{$ENDIF}
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TKLog.Log(const msg: string);
|
|
begin
|
|
{$IFDEF KLOGGING}
|
|
if not FFileOpen then
|
|
begin
|
|
AssignFile(FLogFile, FLogFileName);
|
|
if FileExists(FLogFileName) then Append(FLogFile) else Rewrite(FLogFile);
|
|
FFileOpen := True;
|
|
end;
|
|
writeln(FLogFile, Format('%12.12d ', [GetTickCount()])+FormatDateTime('yyyy-mm-dd hh:nn:ss.zzz', Now) + ': ' + StringOfChar(' ', FMethodStack.Count*2) + msg);
|
|
flush(FLogFile);
|
|
OutputDebugString(PChar('KLog:' + msg + #13#10));
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TKLog.LogError(const msg: string);
|
|
begin
|
|
{$IFDEF KLOGGING}
|
|
Log('###ERROR###: '+msg);
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TKLog.LogError(const msg: string; const fmt: array of const);
|
|
begin
|
|
{$IFDEF KLOGGING}
|
|
LogError(Format(msg, fmt));
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TKLog.MethodEnter(instance: TObject; const name: string; const parameters: array of const);
|
|
{$IFDEF KLOGGING}
|
|
var
|
|
s: string;
|
|
vr: TVarRec;
|
|
i: Integer;
|
|
begin
|
|
s := '';
|
|
for i := Low(parameters) to High(parameters) do
|
|
begin
|
|
vr := TVarRec(parameters[i]);
|
|
if i > Low(parameters) then s := s + ', ';
|
|
s := s + VarRecToString(vr);
|
|
end;
|
|
if Assigned(instance) then
|
|
begin
|
|
Log(instance.ClassName+'.'+name+'('+s+') enter');
|
|
FMethodStack.Add(instance.ClassName+'.'+name);
|
|
end
|
|
else
|
|
begin
|
|
Log(name+'('+s+') enter');
|
|
FMethodStack.Add(name);
|
|
end;
|
|
{$ELSE}
|
|
begin
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TKLog.MethodExit(instance: TObject; const name: string; const result: array of const);
|
|
{$IFDEF KLOGGING}
|
|
var
|
|
s: string;
|
|
begin
|
|
if Assigned(instance)
|
|
then s := instance.ClassName+'.'+name
|
|
else s := name;
|
|
while (FMethodStack.Count > 0) and (FMethodStack[FMethodStack.Count-1] <> s) do
|
|
begin
|
|
Log(FMethodStack[FMethodStack.Count-1] + ' not exiting properly!');
|
|
FMethodStack.Delete(FMethodStack.Count-1);
|
|
end;
|
|
if FMethodStack.Count > 0 then FMethodStack.Delete(FMethodStack.Count-1);
|
|
Log(s+'() exit('+VarRecToString(TVarRec(result[0]))+')');
|
|
{$ELSE}
|
|
begin
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TKLog.MethodExit(instance: TObject; const name: string);
|
|
{$IFDEF KLOGGING}
|
|
var
|
|
s: string;
|
|
begin
|
|
if Assigned(instance)
|
|
then s := instance.ClassName+'.'+name
|
|
else s := name;
|
|
while (FMethodStack.Count > 0) and (FMethodStack[FMethodStack.Count-1] <> s) do
|
|
begin
|
|
Log(FMethodStack[FMethodStack.Count-1] + ' not exiting properly!');
|
|
FMethodStack.Delete(FMethodStack.Count-1);
|
|
end;
|
|
if FMethodStack.Count > 0 then FMethodStack.Delete(FMethodStack.Count-1);
|
|
Log(s+'() exit');
|
|
{$ELSE}
|
|
begin
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TKLog.Log(const msg: string; const fmt: array of const);
|
|
begin
|
|
{$IFDEF KLOGGING}
|
|
Log(Format(msg, fmt));
|
|
{$ENDIF}
|
|
end;
|
|
|
|
{$IFDEF KLOGGING}
|
|
function TKLog.VarRecToString(const vr: TVarRec): string;
|
|
begin
|
|
case vr.VType of
|
|
vtInteger: Result := IntToStr(vr.VInteger);
|
|
vtBoolean: if vr.VBoolean then Result := 'True' else Result := 'False';
|
|
vtChar: Result := ''''+Char(vr.VChar)+''''; // I3310
|
|
vtExtended: Result := FloatToStr(vr.VExtended^);
|
|
vtString: Result := ''''+String_AtoU(vr.VString^)+''''; // I3310 // I3310
|
|
vtPointer: Result := '$'+IntToHex(Integer(vr.VPointer), 8);
|
|
vtPChar: Result := ''''+String_AtoU(vr.VPChar)+''''; // I3310
|
|
vtObject: if vr.VObject = nil then Result := 'object <nil>' else Result := 'object '+vr.VObject.ClassName+' [$'+IntToHex(Integer(Pointer(vr.VObject)), 8)+']';
|
|
vtClass: if vr.VClass = nil then Result := 'class <nil>' else Result := 'class '+vr.VClass.ClassName;
|
|
vtWideChar: Result := ''''+vr.VWideChar+'''';
|
|
vtPWideChar: Result := ''''+vr.VPWideChar+'''';
|
|
vtAnsiString: Result := ''''+string(vr.VAnsiString)+'''';
|
|
vtCurrency: Result := CurrToStr(vr.VCurrency^);
|
|
vtVariant: try Result := VarToStr(vr.VVariant^); except Result := '<error reading variant>'; end;
|
|
vtInterface: Result := 'interface $'+IntToHex(Integer(vr.VInterface), 8);
|
|
vtWideString: Result := ''''+widestring(vr.VWideString)+'''';
|
|
vtInt64: Result := IntToStr(vr.VInt64^);
|
|
vtUnicodeString: Result := ''''+UnicodeString(vr.VUnicodeString)+''''; // I3309
|
|
else Result := '???';
|
|
end;
|
|
end;
|
|
{$ENDIF}
|
|
|
|
function KLEnabled: Boolean;
|
|
begin
|
|
{$IFDEF KLOGGING}
|
|
Result := True;
|
|
{$ELSE}
|
|
Result := False;
|
|
{$ENDIF}
|
|
end;
|
|
|
|
initialization
|
|
KL;
|
|
finalization
|
|
FKLog.Free;
|
|
FKLog := nil;
|
|
end.
|