Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Optimales Logging: Assert-basiert oder NULL-Logger: Ja oder besser nicht ? (https://www.delphipraxis.net/202872-optimales-logging-assert-basiert-oder-null-logger-ja-oder-besser-nicht.html)

Rollo62 17. Dez 2019 14:32

Optimales Logging: Assert-basiert oder NULL-Logger: Ja oder besser nicht ?
 
Hallo zusammen,

ich bin wieder dabei ziemlich tief in fremde Codes per Logging abzutauchen und große Log-Sitzungen auszuwerten.
Was mich stört ist das sehr schlechte Handling des Loggings unter Delphi.
Leider habe ich noch nicht die perfekte oder zumindest akzeptable Log-Lösung für mich gefunden.

Unter C++ habe ich sehr vielseitige Logger als Makros, was aber unter Delphi leider nicht funktioniert..
Ich müsste unter Delphi dann NULL-Logger anlegen, der Messages in Leere laufen lässt,
aber letztendlich würde der ganze Code doch in der App bleiben, oder nicht ?
Vielleicht ist der Delphi Compiler/Linker clever genug um das rauszurechnen, vielleicht gibt es auch Tricks mit NULL-Logger und Inline Funktionen, ich bin da für Ideen und Vorschläge offen.

Den C++ Makros am nächsten käme eventuell eine Assert-basierte Logging Lösung
  • welche Assert nutzt um Log Meldungen abzusetzen (ohne Exception natürlich)
  • welche eine Assert-Umleitung einrichtet, um auf den eigentlichen Logger zu zeigen
  • welche global Assertions ein/ausschalten kann
  • welche in einem Unit, im Header, Assertions individuell ein/ausschalten kann
  • welche ohne massive Defines-Frickelei das Logging einfach zentral oder modulweise verwalten,
    um den eigentlichen Log-Code immer unangetastet in den Units belassen zu können.
  • welche im RELEASE garantiert alle Log-Codes rauswerfen kann


Es gibt sicher für und wider für eine solche Assert-basierte Lösung, z.B.
  • das RELEASE ist doch ein anderes wenn man die Log's wieder rausnimmt.
    Aber das hat man doch bei IFDEF basierten Logger-Lösung, das wäre doch keine Argument dagegen, oder etwa doch ?
  • die "normalen" Asserts werfen dann keine Exceptions mehr (ist das gut oder schlecht ?).
    Es könnten sich 3rd Party Libraries seltsam verhalten.
  • ein Vorteil wäre man die Logs bequem aktivieren/deaktivieren/eventuell gruppieren könnte (auch ohne zuviele IFDEFs)
  • Weil das aber ein ziemlicher Einschnitt in die Delphi-Seele ist, und die Asserts etwas "misbraucht" bin ich mir nicht sicher ob man das so machen sollte, oder besser nicht.

Meine Ziele dafür wären möglichst eine zentrale Verwaltung, möglichst gruppierbar (in den Units oder nach Gruppennamen), es sollte sich natürlich auch unter CrossPlatform gleich verhalten.

Vielleicht könnt Ihr mir da noch etwas auf die Sprünge helfen, um eine optimalere Lösung hinzubekommen ?

mkinzler 17. Dez 2019 15:06

AW: Optimales Logging: Assert-basiert oder NULL-Logger: Ja oder besser nicht ?
 
https://github.com/grijjy/GrijjyCloudLogger

Rollo62 17. Dez 2019 16:01

AW: Optimales Logging: Assert-basiert oder NULL-Logger: Ja oder besser nicht ?
 
Ja dankesehr, Grijjy kenne ich auch.
Der ist schon nahe an Perfekt, weil es eine ganze Infrastruktur bietet.
Ich denke aber das alle Logger die ich bis jetzt gesehen habe im Prinzip ähnlich funktionieren.

Was ich meine ist, das Senden einer Message:
Delphi-Quellcode:
XyzLog.Send('Sample Info Message', TgoLogLevel.Info);
wir mehr oder weniger immer so gemacht.

Ich möchte aber genau diesen Code mal aktive, und mal inaktiv schalten können.
Delphi-Quellcode:
Uses XyzLog;

// Globales abschalten möglich, z.B. über .inc Datei, wenn _X_LOG undefiniert ist
// Globales Abschalten bei RELEASE
{$IF DEFINED( _X_LOG) and DEFINED(DEBUG) } 
{$UNDEF _X_LOG}  // remove the global, and handle the local scope
{$DEFINE _X_LOG}  // Lokales, Unit-scope Abschalten hier möglich
{$ENDIF}


// Das ginge z.B. so
// Spezielles Abschalten ist hier möglich
{$IFDEF _X_LOG} XyzLog.Send('Sample Info Message', TgoLogLevel.Info); {$ENDIF}
Das würde wohl funktinieren, ist aber rein optisch nicht so mein Favorit :stupid:
Ich suche da eigentlich nach einer eleganteren Version ohne zu viele ifdefs (falls es die gibt)

TiGü 17. Dez 2019 16:16

AW: Optimales Logging: Assert-basiert oder NULL-Logger: Ja oder besser nicht ?
 
Und wenn du die IFDEFS innerhalb der Send/Log-Methoden machst (ggf. den Logger der Wahl einfach wrappen)?

Rollo62 17. Dez 2019 16:51

AW: Optimales Logging: Assert-basiert oder NULL-Logger: Ja oder besser nicht ?
 
Ja die LogFunktionen liegen in einer anderen Unit.
Da kann ich globale Features gruppieren, etc., muss aber immer mit .inc Dateien hantieren.
Schöner fände ich das im Kopf einer Unit.

Was dann aber trotzdem passiert, ist das Aufrufen evtl. leerer Funtionen,
den Funktion-Call würde ich natürlich auch gerne im RELEASE wegbekommen.

Man könnte evtl. auch was mit Mocks machen, aber ich meine die sind dafür auch nicht optimal.

Es geht z.B. um Folgende Situation:
Ich muss ein Problem debuggen, und baue dafür an zig Stellen in einer/mehreren Units Logs ein.
Wenn das läuft müsste ich
1. entweder alle Logs wieder rausbauen
2. oder die Logs einfach "ausschalten" (und möglichst NUR diese)

Ich möchte halt 2tes Erreichen, auch weil ich die Logs für spätere Tests noch drinbehalten möchte.

Mit Asserts wäre das z.B. möglich, denn man kann im Kopf einer Unit Assertions ein/ausschalten
Delphi-Quellcode:
$ASSERTIONS ON/OFF
und damit wäre der Aufruf der Asserts weg (keine leere Funktion wird benötigt)

dummzeuch 17. Dez 2019 17:05

AW: Optimales Logging: Assert-basiert oder NULL-Logger: Ja oder besser nicht ?
 
Ich nehme an, Du meinst bei der Assertion-basierten Lösung sowas wie:

https://stackoverflow.com/a/16459891/49925

Delphi-Quellcode:
Assert(False, 'Dies ist eine Logmeldung');

Ich habe das mal ausprobiert und bin da nicht so der Fan:

Vorteil Assertion:
* Man kann das Logging recht einfach komplett ausschalten
* Man kommt einfach an die Zeilennummer der Assertion, in der die Log-Message geschrieben wird.

Nachteil Assertion:
* Wer es nicht kennt, den verwirrt diese Verwendung von Assert.
* Assertions sind ziemlich CPU-Intensiv, d.h bei eingeschaltetem Logging ändert sich das Zeitverhalten stark.
* Man kann Assertions nicht mehr anderweitig verwenden.

Persönlich bevorzuge ich die NULL-Logger-Lösung. Es ist einfach sauberer.

freimatz 17. Dez 2019 17:27

AW: Optimales Logging: Assert-basiert oder NULL-Logger: Ja oder besser nicht ?
 
Zitat:

Zitat von Rollo62 (Beitrag 1453625)
Das würde wohl funktinieren, ist aber rein optisch nicht so mein Favorit :stupid:
Ich suche da eigentlich nach einer eleganteren Version ohne zu viele ifdefs (falls es die gibt)

Und wenn Du die ifdef im aufgerufenen logging code machst?
Ich meine wenn Du dort per ifdef den logging code ausklammerst und die Methode noch als inline deklarierst - würde der Compiler die dann nicht wegoptimieren?

Uwe Raabe 17. Dez 2019 17:36

AW: Optimales Logging: Assert-basiert oder NULL-Logger: Ja oder besser nicht ?
 
Zitat:

Zitat von Rollo62 (Beitrag 1453640)
Was dann aber trotzdem passiert, ist das Aufrufen evtl. leerer Funtionen,
den Funktion-Call würde ich natürlich auch gerne im RELEASE wegbekommen.

Ich glaube, das hatten wir schon mal irgendwo an anderer Stelle (eventuell auch bei DP-EN oder SO). Wenn du die Methoden inline deklarierst, sollte gar kein Call mehr gemacht werden. In diesem Beispiel erzeugen die T.Init und T.Log Aufrufe keinen Code, wenn in uLogging nicht Log definiert ist.

Delphi-Quellcode:
procedure Main;
var
  T: TLog;
begin
  T.Init('TLogConsole');
  T.Log('Hallo Welt');
  Writeln('Wie geht''s?');
  Readln;
end;
Delphi-Quellcode:
unit uLogging;

interface

{.$DEFINE Log}

type
  ILog = interface
  ['{76BA1F8A-D171-4817-BB3D-337295B03CE0}']
    procedure Log(AText: string);
  end;

  TLog = record
  private
    {$IFDEF Log}
    FLog: ILog;
    {$ENDIF}
  public
    procedure Init(const AName: string); inline;
    procedure Log(AText: string); inline;
  end;

implementation

type
  TLogConsole = class(TInterfacedObject, ILog)
  public
    procedure Log(AText: string);
  end;

procedure TLogConsole.Log(AText: string);
begin
  Writeln(AText);
end;

procedure TLog.Init(const AName: string);
begin
  {$IFDEF Log}
  // der Einfachheit halber
  FLog := TLogConsole.Create;
  {$ENDIF}
end;

procedure TLog.Log(AText: string);
begin
  {$IFDEF Log}
  if FLog <> nil then begin
    FLog.Log(AText);
  end;
  {$ENDIF}
end;

end.

Stevie 17. Dez 2019 17:44

AW: Optimales Logging: Assert-basiert oder NULL-Logger: Ja oder besser nicht ?
 
Ich persönlich bin ja Fan von dem Ansatz, den CodeSite, SmartInspect o.ä. verfolgen. Da bleibt der Aufruf grundsätzlich auch in nem Release Build drin, ist aber so geschrieben, dass er wenigstmöglich weh tut, wenn das Logging ausgeschaltet ist. Da hat den Vorteil (tun wir bei unserem Produkt täglich), dass man dem Kunden das mal kurz anschalten lassen kann, er schickt die Logdateien und der Support und/oder Entwicklung kann das auswerten.

Asserts gehören mMn ebenso wie Range und Overflow Checking im Release ausgeschaltet.

Eine wirklich gute Lösung für Logging hat man mMn sowieso nur, wenn die Sprache nativ AOP kann oder so Dinge wie PostSharp möglich sind.

philipp.hofmann 17. Dez 2019 20:48

AW: Optimales Logging: Assert-basiert oder NULL-Logger: Ja oder besser nicht ?
 
Ich bin auch immer für ein zur Laufzeit aktivierbares Logging. Erleichert die Arbeit beim Kunden. Um es möglichst ressourcen-schonend umzusetzen ist dann wichtig, dass man zumindest für den Level INFO und DEBUG zuerst per boolean prüft, ob geloggt werden soll, bevor der zu loggende String angelegt wird. Generell nutze ich TMSLogging und je nach OS (z.B. Android) zusätzlich Log.d(''), damit es in den Prelaunch-Reports auftaucht.

Code:
if (myLog.isInfoEnabled()) then
begin
  {$IFDEF ANDROID}
     Log.d('INFO: XXXXXXX');
  {$ENDIF}
  myLog.info('XXXXXXXX');
end;


Alle Zeitangaben in WEZ +1. Es ist jetzt 18:45 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz