ExeWatch in Delphi-Projekte integrieren, die bereits madExcept nutzen
TL;DR: Sie müssen sich nicht entscheiden. Wenn Sie madExcept bereits einsetzen, behalten Sie es. Ziehen Sie die Bridge-Unit in Ihr Projekt — und jede Exception, die madExcept abfängt, landet zusätzlich im ExeWatch-Dashboard — samt dem von madExcept aufgelösten Stack Trace. Ohne SDK-Upgrade und ohne Änderungen an Ihrer bestehenden madExcept-Konfiguration.
Die Sorge, vorgetragen von einem echten Kunden
Vor ein paar Tagen stellte uns ein Kunde — langjähriger Delphi-Entwickler, madExcept-Nutzer seit den frühen 2010ern — folgende Frage:
“Ich benutze madExcept seit Jahren. Der lokale Dialog, die automatische E-Mail, das ZIP mit dem Bug-Report — das ist Teil davon, wie meine Anwendung Probleme meldet. Wenn ich ExeWatch dazunehme, muss ich das alles rausschmeißen?”
Die kurze Antwort lautet nein. Die lange Antwort ist Thema dieses Artikels.
Man könnte meinen, ExeWatch und madExcept seien Alternativen — das sind sie aber nicht. Sie bearbeiten Probleme, die sich oberflächlich überschneiden, aber von entgegengesetzten Seiten kommen, und in der Kombination ergibt sich etwas Besseres als jedes der beiden Werkzeuge allein. Dieser Beitrag erklärt genau, warum, und zeigt die Integration in der Praxis.
Was jedes Werkzeug gut kann
Bevor wir über die Integration sprechen, lohnt es sich, präzise zu benennen, worin jedes Werkzeug wirklich glänzt. Die Verwirrung rund um das Thema “ExeWatch vs. madExcept” entsteht meistens durch die Annahme, beide würden dasselbe tun — das stimmt nicht.
madExcept: die letzte Verteidigungslinie auf dem Anwender-Rechner
madExcept sitzt tief im Prozess. Sobald eine Exception ausgelöst wird, kann madExcept:
- Den Stack Trace mit Unit-Namen und Zeilennummern auflösen, dank der beim Linken eingebetteten Debug-Informationen (sodass Sie keine
.map-Dateien neben der EXE ausliefern müssen) - Dem Anwender einen lokalen Dialog anzeigen, in dem er einen Kommentar hinzufügen kann, bevor der Report versendet wird
- Einen vollständigen Bug-Report auf die Festplatte schreiben — mit Modulliste, Register-Dump, Threadliste, Screenshot — und ihn selbst dann aufbewahren, wenn keine Netzwerkverbindung besteht
- Den Report per E-Mail versenden oder ihn automatisch an einen FTP- bzw. HTTP-Endpunkt hochladen
- Hängende Haupt-Threads und Memory-Leaks erkennen
madExcept ist seit über zwei Jahrzehnten ein Referenzwerkzeug im Delphi-Ökosystem, im Einsatz bei tausenden Entwicklern und ebenso vielen produktiven Desktop-Anwendungen. Es ist solide, ausgereift und eine dieser Bibliotheken, die ihr Metier so gut und so lange beherrschen, dass es schwerfällt, sich eine Delphi-Desktop-Anwendung ohne vorzustellen. Wenn Ihr Workflow darauf aufbaut, Crash-Reports per E-Mail zu empfangen oder Endanwendern über einen Dialog Kontext einsammeln zu lassen, leistet madExcept Arbeit, die kein Cloud-first-APM-Werkzeug ersetzen soll.
ExeWatch: was passiert, nachdem der Crash-Report abgesendet ist
ExeWatch beginnt dort, wo madExcept aufhört. Sobald ein Fehler eingetreten ist, lauten die spannenden Fragen nicht mehr “Wie sah der Stack aus?”, sondern:
- Ist das ein neuer Bug oder ein bekannter? Ist er bereits auf anderen Installationen, in anderen App-Versionen, in den letzten 24 Stunden aufgetreten?
- Was hat der Anwender unmittelbar davor getan? Breadcrumbs — Button-Klicks, Navigation, HTTP-Requests — vom SDK automatisch erfasst.
- Wie oft tritt das in der Produktion auf? Über Kunden, Versionen, Zeit hinweg.
- Trifft es einen einzelnen Kunden oder viele? ExeWatch zeigt Ihnen Geräte, Kunden, Sessions.
- Zeichnet sich ein Trend ab? Health Scores, Alerts, Anomalie-Erkennung.
- Was geschah drumherum? Timing/Profiling langsamer Vorgänge, Custom-Metriken, Info-Logs, die dem Fehler vorausgingen.
ExeWatch aggregiert Logs, Timings, Metriken und Health über alle Installationen Ihrer Anwendung hinweg und bietet ein Dashboard zum Suchen und Korrelieren. Es beantwortet die Frage “Läuft meine App da draußen tatsächlich gut?” — nicht die Frage “Was ist gerade auf dem Rechner dieses einen Anwenders abgestürzt?”.
Und hier ein Punkt, der Betonung verdient: Eine Anwendung, die nie abstürzt, kann dennoch unzufriedene Kunden haben. Ein Vorgang, den der Anwender als langsam empfindet, ohne ihn je zu melden; ein Import, der mit einer generischen Fehlermeldung scheitert; ein HTTP-Aufruf, der nur in bestimmten Ländernetzen ins Timeout läuft; ein Fehlertrend, der über Wochen hinweg leise ansteigt; ein Checkout-Prozess, der sich verlangsamt, sobald die Datenbank unter Last steht — nichts davon taucht in einem Crash-Report auf, und keine “reine Crash”-Integration wird es je sehen. Und doch sind genau das die Punkte, die Tag für Tag an der wahrgenommenen Qualität Ihrer Software nagen. ExeWatch ist für diese Szenarien mindestens genauso gedacht wie für Crashes.
In diesem Rahmen liefert madExcept ein sehr detailliertes Puzzleteil — das Teil, wenn ein Crash passiert. ExeWatch fügt dieses Teil in ein viel größeres Bild ein, das auch Timing, Metriken, Trends, Breadcrumbs und Health umfasst. Eine Anwendung kann problemlos “stabil” sein — null Crashes in sechs Monaten — und gleichzeitig Anwender frustrieren, die unter Verlangsamungen, stillen Fehlern oder Performance-Regressionen leiden, die kein Exception-Handler jemals zu Gesicht bekommen wird.
Warum die beiden auf den ersten Blick zu kollidieren scheinen
Wenn Anwender ExeWatch zum ersten Mal zu einer App hinzufügen, in der bereits madExcept aktiv ist, fällt ihnen meist etwas Eigenartiges auf: Nicht abgefangene Exceptions erreichen das ExeWatch-Dashboard nie, obwohl andere Logs durchkommen.
Der Grund ist eine Frage der Reihenfolge. Die Auto-Erfassung von GUI-Exceptions in ExeWatch klinkt sich bei Application.OnException der VCL ein. Der Hook von madExcept ist dagegen auf einer tieferen Ebene installiert — praktisch zwischen Betriebssystem und RTL — und feuert, bevor der VCL-Handler zum Zug kommt. Sobald madExcept die Exception verarbeitet hat (Dialog, E-Mail, Neustart), wird der VCL-Handler gar nicht mehr aufgerufen. Folglich sieht der ExeWatch-Hook die Exception nie.
Das ist kein Bug eines der beiden Werkzeuge. So ist madExcept konzipiert — und dasselbe passiert, wenn Sie es mit jeder anderen Bibliothek verketten, die ebenfalls unbehandelte Exceptions sehen will (Sentry, EurekaLog, selbstgebaute Logging-Frameworks). Wer zuerst einhakt, gewinnt.
Die Antwort ist nicht, einen der beiden Hooks zu entfernen — beide haben ihren Sinn. Die Antwort lautet: madExcept fängt die Exception zuerst ab, und aus seinem eigenen Callback heraus reicht es eine Kopie explizit an ExeWatch weiter. Das ist ein dokumentierter Erweiterungspunkt in madExcept namens RegisterExceptionHandler.
Die Bridge: eine einzige Unit
Hier ist die komplette Bridge. Legen Sie diese Datei in Ihr Projekt, nehmen Sie sie in die uses-Klausel der .dpr auf — und das war’s. Der initialization-Abschnitt registriert den Callback automatisch:
unit ExeWatchMadExceptBridgeU;
interface
implementation
uses
System.SysUtils,
System.JSON,
madExcept,
ExeWatchSDKv1;
procedure ExeWatchMadExceptHandler(const ExceptIntf: IMEException;
var Handled: Boolean);
var
ExtraData: TJSONObject;
ExClass, ExMsg: string;
E: TObject;
begin
if (ExceptIntf = nil) or (not ExeWatchIsInitialized) then
Exit;
E := ExceptIntf.ExceptObject;
if Assigned(E) and (E is Exception) then
begin
ExClass := E.ClassName;
ExMsg := Exception(E).Message;
end
else
begin
ExClass := ExceptIntf.ExceptClass;
ExMsg := ExceptIntf.ExceptMessage;
end;
ExtraData := TJSONObject.Create;
ExtraData.AddPair('exception_class', ExClass);
ExtraData.AddPair('exception_message', ExMsg);
ExtraData.AddPair('stack_trace', ExceptIntf.BugReport);
EW.Log(llError, ExMsg, 'exception', ExtraData);
// Handled bleibt bewusst unangetastet: Dialog, Bug-Report und
// E-Mail-Flow von madExcept laufen exakt so weiter wie vorher.
end;
initialization
RegisterExceptionHandler(ExeWatchMadExceptHandler, stDontSync);
finalization
UnregisterExceptionHandler(ExeWatchMadExceptHandler);
end.
Das ist das Ganze. Drei Beobachtungen sind hervorzuheben:
1. Der Callback “verbraucht” die Exception nicht. Handled bleibt unverändert, sodass die normale madExcept-Pipeline — Dialog, E-Mail, Bug-Report-Save — exakt so weiterläuft wie vor der Einführung der Bridge. Endanwender erleben dieselbe Benutzeroberfläche.
2. stDontSync erlaubt es dem Callback, auf jedem Thread zu laufen. Die Logging-API von ExeWatch ist thread-sicher, daher muss madExcept den Aufruf nicht auf den Main-Thread marshallen. Das ist wichtig in Diensten oder worker-thread-lastigen Anwendungen, wo ein erzwungenes Synchronisieren blockieren könnte.
3. Der an ExeWatch übergebene Stack Trace ist der von madExcept, nicht der des SDK. Das ist das Detail, das die meisten übersehen. ExceptIntf.BugReport enthält den vollständig aufgelösten Stack — Unit-Namen, Zeilennummern, Modulliste, Register — dank der Debug-Informationen, die madExcept beim Linken eingebettet hat. Wir übergeben diese Zeichenkette an ExeWatch über das Feld extra_data.stack_trace. Die Methode Log des SDK respektiert einen vom Aufrufer bereitgestellten stack_trace und überschreibt ihn nicht, sodass das Dashboard die von madExcept aufgelösten Frames zeigt und nicht rohe Adressen.
Was Sie tatsächlich bekommen
Nach dem Einbau der Bridge sieht der Weg einer Exception so aus:
- Eine Exception fliegt irgendwo in Ihrem Code
- madExcept fängt sie ab — exakt wie zuvor
- Unser Callback läuft, während madExcept noch verarbeitet
- Wir senden an ExeWatch einen ERROR-Log mit dem madExcept-Stack
- Der normale madExcept-Flow läuft unverändert weiter: Dialog, Bug-Report, E-Mail an das Entwicklerteam, optionaler Neustart
Unterm Strich haben Sie für jede Exception nun beides:
- Auf dem lokalen Rechner: alles, was madExcept schon immer getan hat — Dialog, Report-Datei, E-Mail
- Im Cloud-Dashboard von ExeWatch: dieselbe Exception, mit dem von madExcept aufgelösten Stack, zusammen mit Breadcrumbs, Session-ID, Geräteinfos, Customer-ID, App-Version und allen weiteren Logs, die das SDK rundherum erfasst hat
Visuell sieht der Kontrast so aus.
Auf dem PC des Endanwenders: madExcept macht, was es immer gemacht hat — lokaler Fehlerdialog mit den vertrauten Buttons send bug report, continue application, restart, close. Am Nutzererlebnis hat sich nichts geändert.
Auf dem Bildschirm des Entwicklers, im ExeWatch-Dashboard: dieselbe Exception — hier ein EAccessViolation — trifft aggregiert ein, mit dem von madExcept bereits aufgelösten Stack Trace (Unit-Namen, Zeilennummern, Modul-Offsets) und dem gesamten Kontext, den das SDK drumherum erfasst hat (Session, Thread, Gerät, Breadcrumbs, Timing).
Der Mehrwert des Zweiten ist kein Duplikat des Ersten. madExcept erzählt Ihnen einen Crash. ExeWatch erzählt Ihnen:
- Passiert das nur in v2.3.1?
- Sehen es Windows-10-Anwender häufiger als Windows-11-Anwender?
- Fing es nach dem letzten Deploy an?
- Welcher Kunde sah es zuerst?
- Worauf hat der Anwender unmittelbar davor geklickt?
- Haben die betroffenen Geräte einen bestimmten Virenscanner gemeinsam?
Das sind Korrelations- und Trendfragen, für die es eine andere Aggregationsebene braucht — genau jene, die ExeWatch liefert. Das ist keine Limitierung von madExcept: Es sind zwei unterschiedliche Ebenen desselben Problems, und madExcept macht auf seiner Ebene weiterhin hervorragende Arbeit.
Ein konkretes Beispiel
Stellen Sie sich eine Anwendung vor, die seit Jahren madExcept mit seinem eingespielten E-Mail-Report-Workflow nutzt. Jede Exception erzeugt einen Dialog, der Anwender klickt auf “Senden”, das Entwicklerteam erhält ein ausführliches, detailreiches ZIP per E-Mail — hervorragend, um den Einzelfall zu verstehen. Mit wachsender Installationsbasis wird zusätzlich eine zweite, ergänzende Lesart nützlich: Gruppierung nach Version, Zählungen pro Kunde, Trends im Zeitverlauf.
Fügen Sie ExeWatch daneben hinzu. Installieren Sie die Bridge. Deployen Sie.
Ab dem nächsten Tag:
- Der E-Mail-Flow bleibt unverändert — das Team erhält weiterhin genau wie zuvor Bug-Reports per Mail.
- Das ExeWatch-Dashboard zeigt nun jede Exception, gruppiert nach Fingerabdruck (Exception-Klasse + Stack), mit Zählern pro Version und pro Kunde.
- Ein Alert ist eingerichtet: “Wenn mehr als 3 Fehler in 10 Minuten, an Discord senden.” Die erste echte Regression nach einem Deploy wird in Minuten erkannt, bevor die Anwender zum Hörer greifen.
- Eine Anomalie-Erkennungsregel entdeckt einen graduellen Anstieg einer bestimmten Exception in der letzten Woche — einen langsamen Memory-Leak, der sich erst nach mehreren Nutzungsstunden zeigt — der dank der zeitlichen Aggregation über die Installationsbasis sichtbar wird.
madExcept macht weiter seinen Job. ExeWatch macht einen anderen Job. Keines ersetzt das andere.
Voraussetzungen und wo der Code zu finden ist
Das komplette Sample, mit einem Demo-Formular, das absichtlich reguläre Exceptions, Access Violations und Baseline-Info-Logs auslöst, liegt im ExeWatch-Samples-Repository:
github.com/danieleteti/ExeWatchSamples › SpecificScenarios/madExceptIntegration
Das Sample enthält:
ExeWatchMadExceptBridgeU.pas— die einzige Datei, die Sie in Ihr eigenes Projekt kopierenEWMadExceptIntegration.dproj— ein lauffähiges Delphi-12+-Demo-Projekt (Win32 + Win64)MainFormU.pas/.dfm— drei Buttons, um eine reguläre Exception, eine Access Violation und einen einfachen Info-Log zum Vergleich auszulösenEWMadExceptIntegration.mes— die madExcept-Settings-Datei, damit beim Öffnen des Projekts madExcept automatisch verlinkt wirdREADME.md— Schritt-für-Schritt-Anleitung inklusive Varianten (nur den Call Stack statt des gesamten Bug-Reports senden, Nicht-Crash-Exceptions filtern, EurekaLog-Äquivalent)
Voraussetzungen:
- madExcept in der IDE installiert — verfügbar auf madshi.net
- Delphi XE8 oder neuer — die Bridge nutzt ausschließlich Standard-RTL-Features (System.JSON, Scoped Unit Names, try/except mit typisierter Exception)
- ExeWatch-SDK v0.21.0 oder neuer — jede aktuelle Version genügt, kein spezieller Build nötig
- Ein ExeWatch-Account — der Hobby-Plan ist kostenlos, ohne Kreditkarte
Dasselbe Muster lässt sich auch auf EurekaLog übertragen, über dessen Callback RegisterEventExceptionNotify. Die Logik ist identisch: den aufgelösten Stack aus den EurekaLog-Exception-Informationen extrahieren, dasselbe extra_data-Payload aufbauen, EW.Log aufrufen. Ein eigenes EurekaLog-Sample folgt in den kommenden Wochen im Repository.
Der vollständige Integrationsabschnitt mit direktem Link-Anker zum Teilen ist außerdem unter exewatch.com/ui/docs#coexisting-madexcept dokumentiert.
Und ohne madExcept?
Eine naheliegende Anschlussfrage: Bekomme ich auch ohne madExcept einen präzisen Stack Trace?
Ja. Das ExeWatch-Delphi-SDK erfasst Stack Traces nativ bei jedem Aufruf von EW.Error, EW.Fatal und EW.ErrorWithException. Die einzige operative Einschränkung ist derzeit, dass zum Anzeigen lesbarer Unit-Namen und Zeilennummern anstelle roher Speicheradressen die Datei .map zusammen mit der ausführbaren Datei ausgeliefert werden muss — erzeugt durch Aktivieren von “Detailed” als Map file in den Linking Options des Projekts. Das ist ein zusätzlicher Schritt beim Release, löst das Problem aber.
madExcept verlegt diesen Schritt auf Link-Zeit und bettet die Debug-Informationen direkt in die ausführbare Datei ein — deshalb stützen wir uns, wenn madExcept vorhanden ist, auf dessen bereits aufgelösten Stack. Wir prüfen Wege, die Abhängigkeit von der .map auch ohne madExcept zu beseitigen — für Fragen, Feedback oder Anfragen schreiben Sie an exewatch@bittime.it.
Nicht wählen — integrieren
Wenn Sie ExeWatch evaluieren und befürchten, ein Werkzeug aufgeben zu müssen, auf das Sie sich seit Jahren verlassen, seien Sie beruhigt. madExcept und ExeWatch sind keine Duplikate, sondern unterschiedliche Schichten derselben Observability-Geschichte. Die lokale Schicht — Dialoge, Reports, Dumps — ist das, was madExcept am besten kann. Die Cloud-Schicht — Aggregation, Suche, Alerts, Trends — ist das, was ExeWatch am besten kann.
Eine einzige Bridge-Unit genügt, damit sie zusammenarbeiten — und wenn sie es tun, erhalten Sie einen Blick auf die Gesundheit Ihrer Anwendung, den keines der beiden Werkzeuge allein bieten kann.
Links und Ressourcen
- ExeWatch: exewatch.com
- madExcept-Integrations-Sample: github.com/danieleteti/ExeWatchSamples › SpecificScenarios/madExceptIntegration
- Dokumentation — Koexistenz mit madExcept / EurekaLog: exewatch.com/ui/docs#coexisting-madexcept
- madExcept: madshi.net
- Vorheriger Artikel: ExeWatch 1.8: .NET-SDK, Custom Metrics, Health Monitoring und On-Premise
ExeWatch — Monitoring für Server-, Desktop- und Web-Anwendungen. Entwickelt von bit Time Professionals.
Comments
comments powered by Disqus