QueueHawk behandelt Job-Payloads bereits konservativ: die tatsächlichen Argumentwerte eines Hangfire-Jobs werden nie gesendet, ausser man aktiviert das explizit über IncludeJobPayloads. Aber ein fehlgeschlagener Job trägt nicht nur seine Argumente in sich — er trägt auch, was die Exception selbst sagt, und eine Exception-Message ist Freitext, geschrieben von welchem Code auch immer (eigenem, einer Library, einem Datenbank-Treiber) sie geworfen hat. Gelegentlich steht dort etwas, das dort nicht stehen sollte.
Eine Validierungs-Exception, die den abgelehnten Wert zitiert ("Invalid email: jane.doe@client.com"). Eine Unique-Constraint-Verletzung des Datenbank-Treibers, die den kollidierenden Schlüssel der Zeile wiedergibt. Ein Third-Party-SDK, das eine Request-URL samt Query-String in seiner Exception-Message mitliefert. Nichts davon ist ein Bug in QueueHawk oder Hangfire — so funktionieren Exceptions einfach: die Message ist, was der werfende Code dort hineingeschrieben hat, und die meisten Codes wurden nicht mit dem Gedanken "dieser Text könnte den Prozess verlassen" geschrieben.
Job-Payloads und Exception-Inhalte sind zwei unterschiedliche Probleme mit zwei unterschiedlichen Defaults, bewusst so: Payloads sind Opt-in, weil es selten einen Diagnosegrund gibt, sie überhaupt zu sehen. Exception-Messages und Stacktraces werden standardmässig gesendet (nur längen-gekürzt via MaxStackTraceLength), weil sie meist der eigentliche Grund sind, warum man überhaupt monitort — ein Alert ohne Exception-Detail ist kaum ein Alert.
OnBeforeSendFür die Fälle, in denen der Exception-Text selbst bereinigt werden muss, bietet QueueHawk.Agent einen OnBeforeSend-Callback auf QueueHawkOptions. Er läuft für jedes erfasste State-Change-Event, bevor dieses Event überhaupt in den lokalen In-Memory-Puffer des Agenten geschrieben wird — ein zensiertes Feld liegt dadurch nie unzensiert im Speicher des eigenen Prozesses, geschweige denn geht es je über das Netzwerk raus.
builder.Services.AddQueueHawk(options =>
{
options.ApiKey = builder.Configuration["QueueHawk:ApiKey"];
options.Environment = "Production";
options.OnBeforeSend = jobEvent =>
{
// Nur Failed-Events tragen Exception-Inhalte - alle anderen laufen unverändert durch.
if (jobEvent.ExceptionMessage is null)
{
return jobEvent;
}
return jobEvent with
{
ExceptionMessage = Regex.Replace(
jobEvent.ExceptionMessage,
@"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}",
"[REDACTED-EMAIL]"),
};
};
});
Ein paar Dinge, die man dazu wissen sollte:
jobEvent.ExceptionMessage/jobEvent.State prüfen, wenn nur fehlgeschlagene Jobs betroffen sein sollen.null zurückgeben, um ein Event komplett zu verwerfen — für diesen State-Change wird dann nichts gepuffert oder gesendet, falls Zensur nicht reicht und man es lieber gar nicht senden möchte.Technisch ist es möglich, einen eigenen IElectStateFilter zu schreiben, der FailedState.Exception direkt umschreibt, registriert mit einer niedrigeren Filter-Order als der eigene Filter von QueueHawk.Agent, damit er zuerst läuft. Der Unterschied: das schreibt um, was Hangfire selbst als Exception für diesen Job betrachtet — inklusive dessen, was das eigene Team im lokalen Hangfire-Dashboard und in den eigenen Applikationslogs sieht, nicht nur, was bei QueueHawk ankommt. OnBeforeSend zensiert nur die Kopie, die QueueHawk sieht, und lässt die eigene lokale Diagnose unangetastet. Für die meisten Teams ist das der nützlichere Default — die eigenen Entwickler sollen die echte Exception sehen, solange sie frisch ist, und nur das, was den Prozess verlässt, soll von sensiblen Details befreit werden.
Wenn die Exception-Messages eines Jobs regelmässig Kundendaten referenzieren, ist das oft ein Zeichen, dass das zugrunde liegende Job-Design mehr preisgibt als nötig — ein Blick lohnt sich unabhängig vom eingesetzten Monitoring-Tool. Aber für die Fälle, in denen das unvermeidbar ist oder von einer Abhängigkeit stammt, die man nicht kontrolliert, ist Zensur an der Agent-Grenze der praktische Fix. Zusammen mit standardmässig deaktiviertem IncludeJobPayloads decken die beiden Optionen beide Stellen ab, an denen sensible Daten in einem Job-Event landen können: die Argumente und der Fehlertext.
Vollständige Options-Referenz inklusive aller Defaults: Agent-Konfigurationsreferenz.
Kostenlos für eine Application, keine Kreditkarte nötig.