You are not logged in.
Pages: 1
I'm wanting to put in code like the following:
ILog := TSynLog.Enter(self,'param1'+param1+'param2'+param2);
However it won't compile in D2007.
Any ideas what I can do to make something like it work?
AB: Pleasure. Feel free to include the code into synlog and advise if you think I've missed anything in my formatting.
I'm also looking to improve the logview program based on this change for myself, perhaps with a diagram interface and/or automated log checking.
Any ideas where to start looking for existing code that does this?
I've looked at the data available for logging and come up with my own enter line format, which I think is reasonably parseable:
code address, ['-', instance address,] {' ', [ounitname, '.',] [instance class name, '@',] osymname, ' (', oline, ')',} [' ', extra text]
Where:
[] and {} delimit sections which will hide/show depending on data availability or WithUnitName setting.
Instance is always assumed to be self and the methodname parameter I'd regard as extra text.
Not sure if I've made a mess of the MethodNameLocal item in my code though.
Two spaces before extra text to indicate free form text follows.
There are two sources for unit, which if produce different text would show both separated with '/'.
Instance class name is only shown if different from osymname class.
I don't know how involved it is changing the logviewer, but from what I've seen there aren't any changes necessary there.
Added in TSynMapFile = class:
private
class procedure GetLog(aAddressAbsolute: PtrUInt; out ounitname,
osymname: rawutf8; out oline: integer); static;
Added before implementation - this allows lazy programmer to use self parameter in non-class procedure/function to no ill effect:
const self = nil;
This is a fix of class procedure TSynMapFile.Log to return data instead of logging it:
class procedure TSynMapFile.GetLog(aAddressAbsolute: PtrUInt; out ounitname, osymname : rawutf8;out oline : integer);
var u, s, Line, offset: integer;
begin
ounitname := '';
osymname := '';
oline := -1;
if (aAddressAbsolute=0) or (InstanceMapFile=nil) then
exit;
with InstanceMapFile do
begin
if not HasDebugInfo then exit;
offset := AbsoluteToOffset(aAddressAbsolute);
s := FindSymbol(offset);
u := FindUnit(offset,Line);
if s<0 then begin
if u<0 then begin
exit;
end;
end else
if (u>=0) and (s>=0) then
if u=fUnitSynLogIndex then
exit else // don't log stack trace internal to SynLog.pas :)
if (u=fUnitSystemIndex) and (PosEx('Except',Symbols[s].Name)>0) then
exit; // do not log stack trace of System.SysRaiseException
if u>=0 then begin
ounitname := Units[u].Symbol.Name;
if s>=0 then
if Symbols[s].Name=Units[u].Symbol.Name then
s := -1;
end;
if s>=0 then
osymname := Symbols[s].Name;
if Line>0 then
oline := Line;
end;
end;
And changed procedure TSynLog.AddRecursion:
procedure TSynLog.AddRecursion(aIndex: integer; aLevel: TSynLogInfo);
type
{$ifdef FPC}{$PACKRECORDS 1}{$endif}
TTypeInfo = {$ifndef FPC}packed{$endif} record
Kind: byte;
Name: ShortString;
end;
{$ifdef FPC}{$PACKRECORDS C}{$endif}
TClassType =
{$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}
packed
{$endif FPC_REQUIRES_PROPER_ALIGNMENT}
record
ClassType: TClass;
ParentInfo: pointer;
PropCount: SmallInt;
UnitName: ShortString;
end;
PTypeInfo = ^TTypeInfo;
PClassType = ^TClassType;
var Info: PTypeInfo;
MS: cardinal;
cunitname,csymname:string;
ounitname,osymname:rawutf8;
dotpos,oline : integer;
label DoEnt;
// normal procedure or function:
// Details: code address, {' ', [ounitname, '.',] osymname, ' (', oline, ')',} [' ', extra text].
// method:
// Details: code address, ['-', instance address,] {' ', [ounitname, '.',] [instance class name, '@',] osymname, ' (', oline, ')',} [' ', extra text].
begin
with fThreadContext^ do
if cardinal(aIndex)<cardinal(RecursionCount) then
with Recursion[aIndex] do begin
if aLevel<>sllLeave then begin
TSynMapFile.GetLog(Caller,ounitname,osymname,oline);
fWriter.AddPointer(Caller);
if Instance<>nil then begin
fWriter.Add('-');
fWriter.AddPointer(PtrUInt(Instance));
end;
if ClassType<>nil then begin
if fFamily.WithUnitName then begin
Info := PPointer(PtrInt(ClassType)+vmtTypeInfo)^;
if Info<>nil then begin
{$ifdef FPC}
cunitname := PClassType(GetFPCTypeData(pointer(Info)))^.UnitName;
{$else}
cunitname := PClassType(@Info^.Name[ord(Info^.Name[0])+1])^.UnitName;
{$endif}
if cunitname = '' then
else
if (ounitname <> cunitname) and (ounitname <> '') then
ounitname := cunitname + '/' + ounitname;
end;
end;
// classname:
csymname := PShortString(PPointer(PtrInt(ClassType)+vmtClassName)^)^;
if (osymname = '') then begin
if (csymname <> '') then
osymname := csymname + '@';
end else begin
if (csymname <> '') then
if (csymname <> osymname) then begin
dotpos := pos('.',osymname);
if dotpos <> 0 then
if csymname <> copy(osymname,1,dotpos-1) then
osymname := csymname + '@' + osymname
end;
end;
end;
if (fFamily.WithUnitName and (ounitname <> ''))
or (osymname <> '') then begin
fWriter.Add(' ');
if (fFamily.WithUnitName and (ounitname <> '')) then begin
fWriter.AddShort(ounitname);
fWriter.Add('.');
end;
if (osymname <> '') then
fWriter.AddShort(osymname);
if (oline <> -1) then begin
fWriter.Add(' ');
fWriter.Add('(');
fWriter.Add(oline);
fWriter.Add(')');
end;
end;
if MethodName<>nil then begin // extra text!
fWriter.Add(' ');
fWriter.Add(' ');
// if MethodNameLocal<>mnLeave then begin
fWriter.AddNoJSONEscape(MethodName);
// if MethodNameLocal=mnEnter then
// MethodNameLocal := mnLeave;
// end;
end;
end;
// Timestamp - start and stop.
if fFamily.HighResolutionTimeStamp and (fFrequencyTimeStamp<>0) then
DoEnt:case aLevel of
sllEnter: EnterTimeStamp := fCurrentTimeStamp;
sllLeave: begin
if fFrequencyTimeStamp=0 then
MS := 0 else // avoid div per 0 exception
MS := ((fCurrentTimeStamp-EnterTimeStamp)*(1000*1000))div fFrequencyTimeStamp;
fWriter.AddMicroSec(MS);
end;
end
else
if aLevel in [sllEnter,sllLeave] then
begin
QueryPerformanceCounter(fCurrentTimeStamp);
dec(fCurrentTimeStamp,fStartTimeStamp);
goto DoEnt;
end;
end;
fWriter.AddEndOfLine(aLevel);
end;
Hope it is helpful to someone.
Found it, installed it and seems the problem has gone. Thanks.
I see there are a bunch of IDE fixes there on Andy's website.
So I installed the others too. My c:\installs\fixesforDelphi directory is getting full.
Not sure now about the vclfixpack.pas whether it conflicts with syncommons.pas and whether it should go before or after it in uses clause.
Yes, that's true. Sorry, I didn't state in my original post that it compiles fine. It's just the IDE gives that error and as a result some of the IDE assist features do not work so I had to figure out some sort of workaround or I'm stuck with a lot of asynchronous event driven code to debug and no help from the IDE. I will most likely forget to uncomment the line when compiling for test or live. I'm guessing if I moved that {$STACKFRAMES ON} section to the end of the unit just before the initialization section, it would be less of an issue.
In Delphi 2007 (Version 11.0.2902.10471) IDE, I'm getting an IDE error when using relatively new (1 day old download of) synlog.pas from mORMot_and_Open_Source_friends_2015-06-16_112651_4986fea04f.
If I comment out the {$STACKFRAMES OFF} with '//', then it doesn't keep repeating '[Pascal Fatal Error] SynLog.pas(2745): F2084 Internal Error: AV06419F0F-W0000001C-1' in the build messages view.
Not sure if this causes issues I don't know about.
I'm enjoying the logging simplicity:
var ILog: ISynLog;
begin
ILog := TSynLog.Enter;
But I have a rather messy user defined hierarchy of classes and cross-unit-inherited methods and when it is used for class methods, I'm wanting to also store the self value (and perhaps class type) also.
I've tried using:
ILog := TSynLog.Enter(self,'something');
and
ILog := TSynLog.Enter(self);
However these remove the unit name (and the .mab method name) from the log file line, which I want to keep there.
Any pointers as to how I can do this?
TIA
Existing AddCSV code:
for i := 0 to high(Integers) do begin
Add(Integers[i]);
Add(',');
end;
CancelLastComma;
faster code?:
Add(Integers[0]);
for i := 1 to high(Integers) do begin
Add(',');
Add(Integers[i]);
end;
// for works same as a while loop.
Curious why the log PerformRotation procedure renames all the log files in sequence; instead of just making the new log file the next number up. (like Delphi history files). Could be either way I think - boolean property driven feature.
Pages: 1