80 lines
3.8 KiB
Markdown
80 lines
3.8 KiB
Markdown
# Application Error Logging
|
|
|
|
Das Backend speichert technische Fehler zentral in `application_error_logs`. Die Tabelle ist fuer Fehleranalyse gedacht, nicht fuer fachliches Audit-Logging; bestehende Audit-Events bleiben unveraendert.
|
|
|
|
## Felder
|
|
|
|
- `level`: technischer Schweregrad, aktuell `error` oder `warning`.
|
|
- `category`: grobe Fehlergruppe, z. B. `EMAIL`, `EXTERNAL_API`, `DATABASE`, `BACKGROUND_JOB`, `FILE`, `UNHANDLED`.
|
|
- `code`: stabiler maschinenlesbarer Fehlercode, z. B. `PASSWORD_RESET_EMAIL_SEND_FAILED`.
|
|
- `message`, `stackTrace`, `errorType`: technische Fehlerdaten aus `Error`, `HttpException` oder unbekannten Fehlerwerten.
|
|
- `backendModule`, `service`, `operation`: fachliche Herkunft im Backend.
|
|
- `httpMethod`, `apiPath`, `httpStatusCode`: HTTP-Kontext, sofern vorhanden.
|
|
- `correlationId`: Request-ID aus `X-Correlation-ID` oder eine pro Request erzeugte UUID.
|
|
- `userId`, `tenantId`: Benutzer- und Mandantenkontext, sofern vorhanden.
|
|
- `environment`, `host`: Laufzeitumgebung und Instanz.
|
|
- `context`: bereinigte strukturierte Zusatzdaten.
|
|
- `handled`: `true`, wenn der Fehler gezielt behandelt und protokolliert wurde; `false` fuer unerwartete globale Exceptions.
|
|
|
|
## Erfassung
|
|
|
|
Der globale NestJS-Exception-Filter protokolliert unerwartete Exceptions und technische HTTP-Fehler ab Status 500. Erwartete fachliche Fehler wie Validierung, fehlende Berechtigungen, bewusstes 404 oder Konflikte werden nicht automatisch als Systemfehler gespeichert.
|
|
|
|
Explizit protokolliert werden derzeit:
|
|
|
|
- Passwort-Reset-Mailfehler mit `PASSWORD_RESET_EMAIL_SEND_FAILED`.
|
|
- Registrierungs-Bestaetigungs-Mailfehler mit `REGISTRATION_VERIFICATION_EMAIL_SEND_FAILED`.
|
|
- Benachrichtigung an User-Manager mit `REGISTRATION_APPROVAL_NOTIFICATION_FAILED`.
|
|
- LLDAP/GraphQL- und LDAP-Integrationsfehler mit `EXTERNAL_API_REQUEST_FAILED`.
|
|
|
|
Asynchrone Prozesse ohne HTTP-Request sollen den `ApplicationErrorLoggerService` direkt verwenden und `handled: true` setzen.
|
|
|
|
## Datenschutz
|
|
|
|
Der Logger entfernt sensible Schluessel rekursiv und case-insensitive, darunter `password`, `currentPassword`, `newPassword`, `token`, `accessToken`, `refreshToken`, `idToken`, `authorization`, `cookie`, `secret`, `apiKey`, `clientSecret`, `resetToken` und `sessionId`.
|
|
|
|
Kontextdaten werden in Tiefe, Array-Laenge, Schluesselanzahl und String-Laenge begrenzt. Zirkulaere Objekte werden sicher ersetzt. E-Mail-Adressen in freien Texten werden maskiert, z. B. `m***@example.com`.
|
|
|
|
## Fehlersuche
|
|
|
|
1. Korrelations-ID aus Response-Header `X-Correlation-ID` oder Backend-Log notieren.
|
|
2. In `application_error_logs` nach `correlationId`, `code`, `category`, `userId` oder Zeitraum suchen.
|
|
3. `handled` pruefen: `false` weist auf einen unerwarteten globalen Fehler hin, `true` auf einen gezielt behandelten technischen Fehler.
|
|
4. `context` fuer Provider-Status, maskierte Empfaenger oder Integrationsdetails verwenden.
|
|
|
|
## Beispiel
|
|
|
|
```typescript
|
|
try {
|
|
await this.mail.sendPasswordResetMail({
|
|
recipient: user.email,
|
|
token,
|
|
expiresAt: resetToken.expiresAt,
|
|
});
|
|
} catch (error) {
|
|
await this.applicationErrorLogger.log({
|
|
error,
|
|
category: ApplicationErrorCategory.EMAIL,
|
|
code: ApplicationErrorCode.PASSWORD_RESET_EMAIL_SEND_FAILED,
|
|
module: 'PasswordModule',
|
|
service: PasswordService.name,
|
|
operation: 'sendPasswordResetEmail',
|
|
requestContext: {
|
|
correlationId,
|
|
userId: user.id,
|
|
},
|
|
context: {
|
|
maskedRecipient: maskEmail(user.email),
|
|
mailProvider,
|
|
},
|
|
handled: true,
|
|
});
|
|
|
|
throw error;
|
|
}
|
|
```
|
|
|
|
## Aufbewahrung
|
|
|
|
Es gibt im Projekt derzeit keinen Scheduler oder Queue-Mechanismus. Empfohlen ist ein spaeterer, begrenzter Cleanup-Job, der Fehler aelter als 180 Tage in Batches loescht und kritische Kategorien bei Bedarf laenger aufbewahrt. Die Tabelle besitzt Indizes auf `createdAt`, `code`, `category`, `correlationId`, `userId`, `tenantId` und `httpStatusCode`.
|