Autor |
Beitrag |
galagher
      
Beiträge: 2556
Erhaltene Danke: 45
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: Mi 22.01.14 21:12
Hallo!
Mein Programm schreibt Einträge in eine Log-Datei. Kennt jemand eine Möglichkeit, Zeilennummern des Quellcodes zu ermitteln? Die hätte ich nämlich auch gerne in der Log-Datei aufgelistet, ich möchte dazu aber natürlich keine fixen Werte verwenden!
_________________ gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
|
|
Martok
      
Beiträge: 3661
Erhaltene Danke: 604
Win 8.1, Win 10 x64
Pascal: Lazarus Snapshot, Delphi 7,2007; PHP, JS: WebStorm
|
Verfasst: Mi 22.01.14 22:00
Ohne Debuginfo nicht (falls nicht in den letzten Delphis was gekommen ist via RTTI-Erweiterungen). Soweit ich weiß, gibt's aber nicht sowas schönes wie das __LINE__-Macro...
Mit Debuginfo hätte ich das nur für FPC vorrätig...
_________________ "The phoenix's price isn't inevitable. It's not part of some deep balance built into the universe. It's just the parts of the game where you haven't figured out yet how to cheat."
|
|
jaenicke
      
Beiträge: 19312
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Mi 22.01.14 22:00
Einen Stacktrace bekommst du mit der JEDI Code Library. Genauer gesagt mit der JclDebug Unit.
In jedem Fall brauchst du dafür die nötigen Debuginformationen, sprich deine Exe wird relativ groß werden.
Die einzige andere Möglichkeit sind Assertions, die dies direkt beim Kompilieren einbauen.
Beides ist allerdings für ein normales Logging nicht so sinnvoll, es sei denn es geht um aufgetretene Fehler.
|
|
galagher 
      
Beiträge: 2556
Erhaltene Danke: 45
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: Do 23.01.14 22:00
Vielen Dank für eure Antworten!
jaenicke hat folgendes geschrieben : | Die einzige andere Möglichkeit sind Assertions, die dies direkt beim Kompilieren einbauen. |
Kannst du mir dazu ein Beispiel oder einen Tipp geben?
jaenicke hat folgendes geschrieben : | Beides ist allerdings für ein normales Logging nicht so sinnvoll, es sei denn es geht um aufgetretene Fehler. |
Nein, es geht um keine Fehler, möchte das nur zur Info!
_________________ gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
|
|
jaenicke
      
Beiträge: 19312
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Do 23.01.14 23:50
Für diesen Beitrag haben gedankt: galagher
|
|
galagher 
      
Beiträge: 2556
Erhaltene Danke: 45
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: Fr 24.01.14 17:57
jaenicke hat folgendes geschrieben : | Einfach Assert aufrufen. Wenn der angegebene Ausdruck false ergibt, wird eine Exception ausgelöst, in der die Position im Quelltext steht. |
Ich werde das mal testweise einbauen (heute noch oder auch erst am Wochenende, weiss noch nicht) und melde mich, wenn nötig, wieder!
_________________ gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
|
|
Palladin007
      
Beiträge: 1282
Erhaltene Danke: 182
Windows 11 x64 Pro
C# (Visual Studio Preview)
|
Verfasst: Fr 24.01.14 19:46
Ich habe heute etwas von einem CallerMemberNameAttribute gelesen, das ab C# 5.0 dabei sein soll.
Damit kannst du dir genau das auslesen lassen.
Außerdem kann man aktuell schon über ein kostenloses AddIn und später vielleicht auch vollständig implementiert, einen Compiler nutzen, der es erlaubt, über Code die einzelnen Arbeitsschritte zu analysieren und zu manipulieren.
Den Genauen Namen weiß ich aber nicht mehr...
|
|
galagher 
      
Beiträge: 2556
Erhaltene Danke: 45
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: Fr 24.01.14 20:02
_________________ gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
|
|
jaenicke
      
Beiträge: 19312
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Fr 24.01.14 20:55
Unitname und Zeilennummer stehen doch im Exceptiontext drin.
Für diesen Beitrag haben gedankt: galagher
|
|
galagher 
      
Beiträge: 2556
Erhaltene Danke: 45
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: Fr 24.01.14 21:30
jaenicke hat folgendes geschrieben : | Unitname und Zeilennummer stehen doch im Exceptiontext drin. |
Ich habe eine Prozedur ApplicationEvents1Exception, die wird dann natürlich aufgerufen, ja, und dann wird dort auch der Fehlertext samt Zeilennummer in die Logdatei geschrieben. Es werden aber an vielen Stellen Logeinträge vorgenommen, die keinen Fehler betreffen.
Ausserdem gefällt mir der Gedanke nicht, einen Fehler zu produzieren(!), nur um an die Zeilennummer zu kommen. Das ist ja so, wie mit seinem Auto gegen die Wand zu fahren, weil man den Airbag sehen will.
Ich will den Airbag aber ohne Crash sehen!
Geht wohl mit Delphi nicht...
_________________ gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
|
|
galagher 
      
Beiträge: 2556
Erhaltene Danke: 45
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: Sa 25.01.14 21:41
Es gibt ein Beispiel in der Hilfe von Delphi 6, damit habe ich mir etwas gebastelt, das für meine Zwecke ausreicht. Und jetzt die Preisfrage: Ich muss dazu rund 150 Mal Assert aufrufen, um an die jeweilige Zeilennummer zu kommen. Gibt es einen Weg, Assert in einer Prozedur nur 1 Mal zu haben, und trotzdem an die Zeile zu kommen, von der diese Prozedur aufgerufen wurde? In anderen Fällen würde man das so machen:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9:
| if i <> 0 then MeineProzedur; procedure TForm1.MeineProzedur; begin Assert(0=1); end; |
_________________ gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
|
|
jaenicke
      
Beiträge: 19312
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Sa 25.01.14 21:50
Das wäre wiederum ein Fall für einen Stacktrace. Das geht nicht, nein.
Eigentlich frage ich mich halt wofür du das eigentlich brauchst. Wenn es bei einem Log darum geht, einen unbekannten Fehler abzufangen, dann fange ich die Exception zentral ab und logge diese zentral automatisch mit Stacktrace, letzten Anwendungsaktionen, usw.
Wenn ich Logeinträge schreibe um einen Ablauf nachzuvollziehen, muss ich die aber ohnehin an konkrete Stellen schreiben. Da muss ich ja, damit es sinnvoll ist, ohnehin Informationen zum Ablauf hinzufügen. Und dann brauche ich die Quelltextstelle nicht mehr, weil es ohnehin eindeutig ist wo das auftritt.
Wenn du einfach nur einen kopierten Befehl überall als Log einstreuen willst ohne den zu ändern (halte ich für wenig sinnvoll, aber deine Sache), dann bleibt dir nur ein Stacktrace. Der ist zwar nicht ganz so schnell erstellt, aber ein ungezieltes Logging ist ja auch nicht gerade ressourcenschonend, insofern ist das ja für dich vielleicht ok...
Für diesen Beitrag haben gedankt: galagher
|
|
galagher 
      
Beiträge: 2556
Erhaltene Danke: 45
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: Sa 25.01.14 21:57
jaenicke hat folgendes geschrieben : | Das geht nicht, nein. |
Dachte ich mir. Dann lasse ich das. Immerhin habe ich nun eine Datei, mit der das prinzipiell geht!
_________________ gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
|
|
galagher 
      
Beiträge: 2556
Erhaltene Danke: 45
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: So 26.01.14 19:19
Letzter Anlauf:
Ich dachte daran, Assert an eine Prozedur als Parameter zu übergeben. Habe auch gegoogelt, es gibt einiges zu dem Thema, aber nichts, was für meine Zwecke geeignet ist.
Ich denke mir das so:
Delphi-Quelltext 1: 2: 3: 4: 5: 6:
| procedure TForm1.MeineProzedur(... ); begin end;
MeineProzedur(Assert(0=1), ); |
Ich schaffe es einfach nicht! Geht das überhaupt?
_________________ gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
|
|
Thom
      
Beiträge: 70
Erhaltene Danke: 5
Delphi 10 Seattle Prof.
|
Verfasst: So 26.01.14 22:57
Die globale Variable AssertErrorProc kann mit einer eigenen Prozedur initialisiert werden:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14:
| procedure MyAssertErrorProc(const Message, Filename: String; LineNumber: Integer; ErrorAddr: Pointer); begin ShowMessage(IntToStr(LineNumber)); end;
procedure TForm1.FormCreate(Sender: TObject); begin AssertErrorProc:=MyAssertErrorProc; end;
procedure TForm1.Button1Click(Sender: TObject); begin Assert(false); end; |
Zusätzliche Parameter könntest Du dabei als String im Parameter Message von Assert übergeben:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18:
| procedure MyAssertErrorProc(const Message, Filename: String; LineNumber: Integer; ErrorAddr: Pointer); var Params: TStringList; begin Params:=TStringList.Create; try Params.CommaText:=Message; Params.Add('Zeile: '+IntToStr(LineNumber)); ShowMessage(Params.Text); finally Params.Free; end; end;
procedure TForm1.Button1Click(Sender: TObject); begin Assert(false,Format('%s,%d',['Parameter_1',10])); end; |
|
|
galagher 
      
Beiträge: 2556
Erhaltene Danke: 45
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: Mo 27.01.14 18:47
_________________ gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
|
|
Thom
      
Beiträge: 70
Erhaltene Danke: 5
Delphi 10 Seattle Prof.
|
Verfasst: Mo 27.01.14 19:27
Selbstverständlich kann man Methoden, Prozeduren und Funktionen als Parameter übergeben. Aber
Delphi-Quelltext 1: 2: 3: 4:
| procedure TForm1.Button1Click(Sender: TObject); begin MyProc(Assert(0=1), ...); end; |
funktioniert in dieser Form nicht, da hier nicht die Prozedur Assert selbst übergeben wird, sondern das Ergebnis des Aufrufs. Das geht aber nicht, da Assert eine Prozedur und keine Funktion ist. Um also auf Deine Frage klar zu antworten: Nein - so geht das nicht. Weder mit Assert noch mit irgend einer anderen Delphi-Prozedur.
Erschwerend kommt noch hinzu, daß bei Assert "Kompilermagie" im Spiel ist. Beim Kompilieren werden nämlich der Aufruf und die Parameter so umgeformt, daß im Endeffekt die Prozedur System._Assert ausgeführt wird.
Für Dich ist es kein Problem MyProc(Assert(0=1), ...); zu schreiben, willst aber Assert nicht aufrufen:
galagher hat folgendes geschrieben : | Nur muss ich da eben Assert immer noch extra aufrufen! |
Tut mir Leid, aber ich verstehe Dein Problem nicht.
Leitest Du den Assert-Aufruf in eine eigene Prozedur um, erhältst Du die von Dir gewünschten Angaben ohne Exception frei Haus. Aber offensichtlich willst Du das doch nicht... 
|
|
galagher 
      
Beiträge: 2556
Erhaltene Danke: 45
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: Mo 27.01.14 19:49
Thom hat folgendes geschrieben : |
Für Dich ist es kein Problem MyProc(Assert(0=1), ...); zu schreiben, willst aber Assert nicht aufrufen:
galagher hat folgendes geschrieben : | Nur muss ich da eben Assert immer noch extra aufrufen! |
Tut mir Leid, aber ich verstehe Dein Problem nicht.
Leitest Du den Assert-Aufruf in eine eigene Prozedur um, erhältst Du die von Dir gewünschten Angaben ohne Exception frei Haus. Aber offensichtlich willst Du das doch nicht...  |
Ok, ich habe mich wohl unklar ausgedrückt! Ich rufe in meiner Unit an 150 verschiedenen Stellen eine Prozedur auf, die unter anderem etwas in eine TStringList schreibt, welche ich bei Programmende dann als Datei mit der Endung .log speichere.
Vor jeden dieser über 150 Prozeduraufrufe müsste ich Assert setzen. Also konkret so:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16:
| Assert(0=1); TextOutPut(s, ...); begin if ... then begin Assert(0=1); TextOutPut(s, ...); end; begin Assert(0=1); TextOutPut(s, ...); end; end; |
Da wäre es doch so viel einfacher:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| TextOutPut(Assert(0=1), s, ...); begin if ... then TextOutPut(Assert(0=1), s, ...); begin TextOutPut(Assert(0=1), s, ...); end; end; |
Weisst du, was ich meine? Assert einfach als Parameter übergeben und:
Delphi-Quelltext 1: 2: 3: 4:
| procedure MyAssertErrorProc(const Message, Filename: String; LineNumber: Integer; ErrorAddr: Pointer); begin ShowMessage(IntToStr(LineNumber)); end; |
... kann ich dann auch verwenden, da das ja, wie du richtig sagst, genau das tut, was ich möchte: Mir die LineNumber geben!
Aber wenn's nunmal nicht geht, ok!
_________________ gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
|
|
GuaAck
      
Beiträge: 378
Erhaltene Danke: 32
Windows 8.1
Delphi 10.4 Comm. Edition
|
Verfasst: Mo 27.01.14 19:57
Mal ein anderer Ansatz, so wie ich es mache:
Ich definiere einfach eigene Kennnummern hard-coded im Quelltext, also z. B.:
writeln(logfile, '100 Hier dies...');
...
writeln(logfile, '110 hier das...');
...
writeln(logfile, '120 und das hier...');
Gegenüber Zeilennumern hat das den wesentlichen Vorteil, dass meine Kennnummern unabhängig davon sind, ob ich irgendwo anders Code einfüge, ich kann sie also in meine Dokumentation übernehmen.
Logisch, statt 100, 110,120 kann man auch noch den Modulnamen usw. einbauen und bei Klassen evtl. den Namen der jeweiligen Instanz. Da man ein Logging dieser Art ja eigentlich nur für eine Fehlersuche nutzt, reichen auch die Nummern, mit denen man ganz schnell im Editor die entsprechende Stelle suchen kann.
Oder habe ich da im Prinzip was nicht richtig verstanden?
(Bevor sich einer über writeln aufregt: Steht sinngemäß für jede Art, etwas in den Logfile zu schreiben.)
Grüße
GuaAck
|
|
galagher 
      
Beiträge: 2556
Erhaltene Danke: 45
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: Mo 27.01.14 20:11
GuaAck hat folgendes geschrieben : | Ich definiere einfach eigene Kennnummern hard-coded im Quelltext, |
Ja, so mache ich das jetzt auch. Alerdings verwende ich mehrere Strings zusammen mit diesen Kennnummern, ach, was red ich - so:
Delphi-Quelltext 1: 2: 3: 4: 5:
| TextOutPut(s, sHuman, '01 '+sSonstige, True); TextOutPut(s, sHuman, '02 '+sSonstige, False); TextOutPut(s, sHuman, '01 '+sUserName, True); | Also kommt 01 an mehreren Stellen vor, das geht zum Teil bis 70. Das zu verwalten und korrekt fortzuführen, wenn an Code etwas dazukommt oder wegfällt, ist nicht einfach. Und das im Moment über 150 Mal! Es wäre besser mit Zeilennummern!
Nun interessiert mich einfach, ob eine Parameterübergabe so überhaupt möglich ist. Naja, wohl nicht. 
_________________ gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
|
|
|