Error Reporting mit Sentry
Was ist Sentry?
Sentry ist eine Software zur Überwachung deiner Frontend und Backend-Anwendungen. Mit Sentry lassen sich Fehler und Abstürze in deinem Quellcode erkennen, verfolgen und auch die Performance kann ausgewertet werden, so dass du Geschwindigkeitsbremsen ausfindig machen kannst. Die Software wird in deinen (Micro)-Service, deine Anwendung oder dein Projekt integriert und ist dadurch in der Lage Meta-Daten zu sammeln und dir in einem Dashboard darzustellen.
Die Integration ist recht simpel gelöst. Zum einen implementierst du die Sentry JavaScript SDK <script src="https://browser.sentry-cdn.com/<VERSION>/bundle.min.js"></script> und zum anderen erstellst du im Dashboard ein Projekt. Für dieses bekommst du einen Data Source Name (DSN), der in deiner Anwendung hinterlegt werden muss Sentry.init({ dsn: "https://examplePublicKeyo0.ingest.sentry.io/0",...}. Von diesem Zeitpunkt an, sammelt Sentry fleißig allerlei hilfreiche Meta-Daten zu deinem Projekt, die dir dabei helfen können auftretende Fehler schneller zu beheben. Zum Beispiel bekommst du auf einem Blick zu sehen, auf welchem Server, welcher Infrastruktur, welchem Betriebssystem, in welcher Release-Version und welcher Programmiersprache dein Service betrieben wird.
Am wichtigsten ist jedoch der Stack-Trace, durch den die Devs nachvollziehen können, was für eine Art von Fehler in welcher Zeile einer Datei genau aufgetreten ist. Sentry weiß, zu wann ein Fehler das erste Mal in Erscheinung trat, wie oft insgesamt und auch wann er zuletzt aufgetreten ist. Richtig cool ist, dass es auch eine GitLab Integration gibt. Dadurch lässt sich direkt sehen, welcher Entwickler zuletzt eine Änderung am Code durchgeführt hat. Das könnte ein Indiz dafür sein, warum plötzlich ein erhöhtes Aufkommen an Fehlern zu verzeichnen ist.
Error-Handling in der Produktentwicklung
Beim Entwickeln von Software bleibt es nicht aus, dass man auch Fehler produziert. Es ist nahezu unmöglich komplett fehlerfreie Software zu schreiben, also heißt es eher, die Fehlerquote möglichst gering zu halten. Laut Wikipedia hat kommerzielle Software eine durchschnittliche Fehlerdichte von 15 bis 50 Fehlern pro 1.000 Zeilen geschriebenem Code. Im Blog-Artikel Warum nutzen wir welche Programmiersprache bin ich ein wenig auf Typisierung eingegangen, die beim Entwickeln zwar für Mehrarbeit beim Programmierer sorgt, aber im Großen und Ganzen die Fehleranfälligkeit reduziert. Der Einsatz typisierter Sprachen (GO und Node.js mit Typescript) sind dementsprechend ein Ansatz, die Fehlerrate bereits beim Entwickeln zu senken. Des Weiteren versuchen unsere Devs natürlich an allen Stellen Fehler abzufangen und diese zu behandeln, so dass die Laufzeit nicht beeinträchtigt wird. Bestenfalls spürt der Kunde dadurch gar nicht, dass die Datenbankverbindung kurz unterbrochen wurde. Darüber hinaus werden Unit- und Integrationtests pro Service implementiert, welche die Code-Qualität weiter steigern sollen.
Was sind Unit-Tests?
Unit-Tests oder auch Modultests genannt, untersuchen die kleinste, prüfbare, relevante Einheit einer Anwendung (z. B. eine Methode). Die einzelnen Units werden unabhängig voneinander getestet. Es soll sichergestellt werden, dass die Logik dieser einen Funktion richtig funktioniert und sich entsprechend verhält.
Was sind Integration-Tests?
Beim Integration-Test werden ganze Vorgänge getestet, die unter Umständen auch Abhängigkeiten haben. Das können z. B. andere Services, Datenbanken oder APIs sein, die zusätzlich zum eigentlichen Test mit hochgefahren werden müssen. Gerade bei der Arbeit mit Micro-Services, kann es für einen Integration-Test eine ganz Hand voll Abhängigkeiten benötigen. Um beispielsweise den Login-Vorgang automatisiert zu testen, benötigt es mindestens den Signup-Service, den Messaging Service und den GEO-IP-Service.
Besonders hilfreich sind Integration Tests dann, wenn ein Entwickler in einem Service eine Funktion ergänzt, aber nicht im Detail über diesen Service Bescheid weiß. Das kann durchaus vorkommen, da wir in Teams arbeiten und die Fachkompetenz und Verantwortung ab und an in einem anderen Team liegt. Durch die Integration der Tests, kann ein Entwickler sich darauf konzentrieren, eine neue Funktion hinzuzufügen und sich im Anschluss auf die hinterlegten Tests verlassen, die das gesamte Konstrukt durchtesten. Wenn der Test erfolgreich abgeschlossen werden kann, muss man nur noch die ergänzten Funktion absichern und reduziert das Risiko, dass Fehler erst im Nachhinein auffallen.
Wofür benötigen wir Sentry?
Trotz der o. g. Methoden und Vorkehrungen, sind Fehlerfälle nicht ausgeschlossen. Es kann immer noch dazu kommen, dass vergessen wurde, Code-Stellen mit einem Try / Catch Block o. ä. zu versehen. Vielleicht wurden Fehler-Szenarien auch einfach nicht bedacht. In diesem Fall greift Sentry ein und loggt diese Fehler mit, versieht sie mit Meta-Daten und summiert sie im Dashboard auf.
Beispiel:
function addValues ($value1, $value2){
return $value1 + $value2;
}
In diesem einfachen Beispiel nimmt die Funktion addValues zwei Werte entgegen und gibt das addierte Ergebnis zurück. Innerhalb der Funktion findet allerdings keinerlei Validierung der Werte statt, so dass man z. B. einen String der Funktion übergeben könnte und es folglich zu einem Error kommen würde. Dieses sehr vereinfachte Beispiel würde einen Stack-Trace im Sentry hervorrufen und unter dem Service gelistet werden.
Integration von Sentry ins Daily Doing
Sehr praktisch ist, dass man in Sentry benutzerdefinierte Alarmierungs-Regeln festlegen und diese Alarme einfach in einen vordefinierten Slack-Channel posten kann. So werden Fehler in Echtzeit abgefangen und unsere Entwickler bekommen direkt bei Fehlereintritt eine Notification. Slack ist intern unser primäres Kommunikationsinstrument, wodurch die Meldung im Channel automatisch für ein gewisses Bewusstsein sorgt und kein Fehler unter dem Radar bleibt, weil jemand vergessen hat, ins Dashboard zu schauen.
Wir möchten Sentry in unserem Arbeitsalltag jedenfalls nicht mehr missen und können es euch nur wärmstens empfehlen!