TIP: Parameterlogging

03/03/2009 - 19:09 von Olaf Doschke | Report spam
Hallo Leute,

mit folgendem lassen sich die Parameterwerte, die
an Methoden von Objekten gehen loggen, was beim
debuggen zum reproduzieren von Fehlern sehr interessant
sein kann.

In dieser Variante ermittelt der Logger dabei sogar
per AMEMBERS(...,3) die Methodensignatur, d.h. dessen
Parameternamen, was zum restaurieren der Variablen unter
ihren korrekten Namen hilfreich ist, aber so innerhalb
einer EXE nicht funktioniert. Stattdessen könnte man
die Methodensignaturen auch zur Entwicklungszeit in
eine Tabelle mit Metadaten einfüttern und in der EXE
so nutzen, oder das loggen der feststehenden Namen
einfach ganz weglassen.

Die Klasse làßt sich wie folgt nutzen:

-Folgendes als parameterlogger.prg speichern
-die Eigenschaft cLogDirectory anpassen.
-SET PROCEDURE TO parameterlogger.prg
-loParameterlogger = CreateObject("ParameterLogger")
-Irgendein zu loggendes Objekt erstellen (oObject)
-loParameterlogger.WatchObject(oObject)
-Methoden von oObject aufrufen
-loParameterlogger = .NULL.
-Nun in der Parameterlog.dbf die geloggten Aufrufe
sichten und bei Interesse an den Parameterwerten
RESTORE FROM Memo mParameter [Additive]
=> Die WErte finden sich wieder in tcPar1 bis tcPar10.

Die Klasse basiert auf Session, um keine ansonsten
bestehende Datasession zu stören.

Weiteres Inline in Kommentaren. Viel Erfolg damit!

Tschüß, Olaf.



Define Class ParameterLogger As Session
cLogDirectory = 'D:\logs'

* Debugginghilfe: Logging von Parameterwerten
* Je nach Bedarf können zu übewrwachende Objekte dieses Loggers
* über WatchObject() bekannt gegeben werden, um zu loggen,
* welche Werte an Methoden dieses Objekts übergeben wurden.

Procedure Init()
* Bei Erststart im Log-Verzeichnis eine Logtabelle erstellen

If !Directory(This.cLogDirectory)
This.cLogDirectory = GetEnv('TEMP')
EndIf
If !File(Addbs(This.cLogDirectory)+'Parameterlog.dbf')
* Logtabelle mit mParameter als wichtigstes Feld für die
Parameterwerte
* und Nebeninfos wie Klasse, Instanzname, Methodenname,
Parameternamen,
* Zeit des Aufrufs und Anzahl der Parameter
Create Table (Addbs(This.cLogDirectory)+'Parameterlog.dbf') FREE;
(cClass C(128), cName C(128), ;
cMethod C(128), cSignature C(128), ;
tDateTime T, iParaCount I, mParameter M NOCPTRAN)
EndIf

Try
Use (Addbs(This.cLogDirectory)+'Parameterlog') In 0 Exclusive
Catch
*
Endtry

* Instanziierung verweigern, wenn keine Logtabelle bereit steht.
Return Used('Parameterlog')
Endproc

Procedure WatchObject()
* Überwachung eines Objektes per Bindevent-Anbindung (aller) Methoden
* des Objekts an die LogParameters()-Methode dieses Loggers
Lparameters toObject

Local lnCount
* nur Benutzerdefinierte Methoden überwachen
For lnCount = 1 To Amembers(laMethods,toObject,1,'U')
Bindevent(toObject,laMethods(lnCount),This,'LogParameters',1)
Endfor
Endproc

Procedure LogParameters()
* Bis zu 10 Parameter sollten reichen, bei Bedarf erweitern
Lparameters tcPar1,tcPar2,tcPar3,tcPar4,tcPar5,;
tcPar6,tcPar7,tcPar8,tcPar9,tcPar10

Local loObject, lnRow, lcSignatur, lnSession
Local Array laEvent[1]
Local Array laMembers[1]

* Quelle des Events ermitteln (überwachtes Objekt)
Aevents(laEvent,0)
loObject = laEvent(1)

* zur Ermittlung der Methodensignatur
Amembers(laMembers,loObject,3)
lnRow = Ascan(laMembers,laEvent(2),1,-1,1,15)
lcSignatur = Iif(lnRow>0,laMembers(lnRow,3),"")
* Für Betrieb in einer EXE die vorigen drei Zeilen
* ersetzen durch lcSignatur = ""

* Bindevent làßt den Eventhandler in derselben Session laufen
* wie das überwachte Objekt, daher ist trotz Session-Klasse
* hier ein Wechsel in die eigene Session nötig
Set Datasession To This.DataSessionId

* Log der Parameter
Insert Into Parameterlog Values ;
(loObject.Class, loObject.Name,;
laEvent(2), lcSignatur, Datetime(), Pcount(), '')

* Und nun das entscheidende:
* Speichern der Parametervalues im mParameter Memo.
Save To Memo mParameter All Like tcPar*
* Wiederherstellen der Parameter mit RESTORE FROM Memo mParameter
* als tcPar1, tcPar2 etc.

* Hier könnte es noch individuell weiter gehen, z.B. mit dem
* Speichern von Cursorinhalten, wenn Parameter Aliasnamen sind, o.à.
* Dabei sind die echten Parameternamen laut lcSignatur u.U.
* interessant, auch spàter für das Umkopieren von tcPar1 etc.
* in die echten Parameter einer zu debuggenden Methode.
EndProc

Procedure Destroy()
UnBindEvents(This)
Use In Select('Parameterlog')
EndProc
Enddefine
 

Lesen sie die antworten

#1 ms
04/03/2009 - 10:42 | Warnen spam
Hallo Olaf,

sieht interessant aus.

Ein winzig kleiner Schönheitsfehler:

Procedure LogParameters()
* Bis zu 10 Parameter sollten reichen, bei Bedarf erweitern
Lparameters tcPar1,tcPar2,tcPar3,tcPar4,tcPar5,;
tcPar6,tcPar7,tcPar8,tcPar9,tcPar10


Die Parameter sollten txPar1, txPar2, txPar3, txPar4, txPar5,;
txPar6, txPar7, txPar8, txPar9, txPar10

Local loObject, lnRow, lcSignatur, lnSession
Local Array laEvent[1]
Local Array laMembers[1]

* Quelle des Events ermitteln (überwachtes Objekt)
Aevents(laEvent,0)
loObject = laEvent(1)

* zur Ermittlung der Methodensignatur
Amembers(laMembers,loObject,3)
lnRow = Ascan(laMembers,laEvent(2),1,-1,1,15)
lcSignatur = Iif(lnRow>0,laMembers(lnRow,3),"")
* Für Betrieb in einer EXE die vorigen drei Zeilen
* ersetzen durch lcSignatur = ""

* Bindevent làßt den Eventhandler in derselben Session laufen
* wie das überwachte Objekt, daher ist trotz Session-Klasse
* hier ein Wechsel in die eigene Session nötig
Set Datasession To This.DataSessionId

* Log der Parameter
Insert Into Parameterlog Values ;
(loObject.Class, loObject.Name,;
laEvent(2), lcSignatur, Datetime(), Pcount(), '')

* Und nun das entscheidende:
* Speichern der Parametervalues im mParameter Memo.
Save To Memo mParameter All Like tcPar*
* Wiederherstellen der Parameter mit RESTORE FROM Memo mParameter
* als tcPar1, tcPar2 etc.

* Hier könnte es noch individuell weiter gehen, z.B. mit dem
* Speichern von Cursorinhalten, wenn Parameter Aliasnamen sind, o.à.
* Dabei sind die echten Parameternamen laut lcSignatur u.U.
* interessant, auch spàter für das Umkopieren von tcPar1 etc.
* in die echten Parameter einer zu debuggenden Methode.
EndProc

Procedure Destroy()
UnBindEvents(This)
Use In Select('Parameterlog')
EndProc
Enddefine



Ähnliche fragen