Erweiterte Debugging-Techniken
Ueber die grundlegenden Debug-Funktionen hinaus bietet Node-RED zahlreiche Moeglichkeiten, komplexe Fehler systematisch aufzuspueren. Diese Seite beschreibt fortgeschrittene Techniken, die in Produktivumgebungen besonders wertvoll sind.
Catch-All-Error-Handler
Ein globaler Catch Node faengt alle Fehler ab, die nicht von spezifischen Catch Nodes behandelt werden. Platzieren Sie ihn auf einem separaten Tab (z.B. “Error Handling”).
// Function Node: Fehlermeldung aufbereiten
const errorInfo = {
timestamp: new Date().toISOString(),
flowName: msg.error.source.name || "unbekannt",
nodeId: msg.error.source.id,
nodeType: msg.error.source.type,
message: msg.error.message
};
msg.payload = errorInfo;
msg.topic = "error/global";
return msg;Flow-Aufbau:
[catch (alle Nodes)] → [function: Fehler aufbereiten] → [debug: Fehler-Log]
→ [http request: Fehler an Monitoring senden]Wichtig: Setzen Sie die Catch Node auf “Catch errors from all nodes” und aktivieren Sie “Include errors handled by other Catch nodes” nur, wenn Sie eine zentrale Protokollierung wuenschen.
Message-Tracing mit Debug Nodes
Bei komplexen Flows ist es hilfreich, den Nachrichtenfluss an jedem Schritt zu verfolgen. Platzieren Sie Debug Nodes an strategischen Stellen und versehen Sie diese mit eindeutigen Namen.
// Function Node: Trace-Information hinzufuegen
if (!msg._trace) {
msg._trace = [];
}
msg._trace.push({
node: "Validierung",
timestamp: Date.now(),
payload: JSON.stringify(msg.payload).substring(0, 200)
});
return msg;Systematisches Tracing einrichten
- Einstiegspunkt markieren: Am Anfang jedes Flows eine
_trace-Property initialisieren - Checkpoints setzen: Nach jeder wichtigen Transformation einen Trace-Eintrag hinzufuegen
- Ausgangspunkt protokollieren: Am Ende des Flows die gesamte Trace-History ausgeben
// Function Node: Trace-Zusammenfassung am Ende des Flows
const trace = msg._trace || [];
const duration = trace.length > 1
? trace[trace.length - 1].timestamp - trace[0].timestamp
: 0;
node.warn(`Flow abgeschlossen in ${duration}ms mit ${trace.length} Schritten`);
return msg;History-Logging ueber den Context
Nutzen Sie den Flow-Context, um eine Historie der letzten Ausfuehrungen zu speichern. Das ist besonders nuetzlich fuer intermittierende Fehler.
// Function Node: Ausfuehrungshistorie im Context speichern
const maxEntries = 50;
let history = flow.get("executionHistory") || [];
history.unshift({
timestamp: new Date().toISOString(),
msgId: msg._msgid,
input: JSON.stringify(msg.payload).substring(0, 500),
success: true
});
// Nur die letzten Eintraege behalten
if (history.length > maxEntries) {
history = history.slice(0, maxEntries);
}
flow.set("executionHistory", history);
return msg;Historie abfragen
Erstellen Sie einen separaten HTTP-Endpunkt, um die Historie jederzeit abfragen zu koennen:
// Function Node: Historie ausgeben (verbunden mit http-in GET /debug/history)
msg.payload = flow.get("executionHistory") || [];
msg.headers = { "Content-Type": "application/json" };
return msg;Performance-Profiling mit Zeitstempeln
Messen Sie die Ausfuehrungszeit einzelner Abschnitte, um Engpaesse zu finden.
// Function Node: Timer starten (am Anfang eines kritischen Abschnitts)
msg._profiling = {
start: process.hrtime.bigint(),
section: "Datenbankabfrage"
};
return msg;// Function Node: Timer stoppen (am Ende des Abschnitts)
if (msg._profiling) {
const elapsed = Number(process.hrtime.bigint() - msg._profiling.start) / 1e6;
node.warn(`[Profiling] ${msg._profiling.section}: ${elapsed.toFixed(2)}ms`);
// Ergebnis im Context sammeln
let metrics = flow.get("profilingMetrics") || {};
const section = msg._profiling.section;
if (!metrics[section]) {
metrics[section] = { count: 0, totalMs: 0, maxMs: 0 };
}
metrics[section].count++;
metrics[section].totalMs += elapsed;
metrics[section].maxMs = Math.max(metrics[section].maxMs, elapsed);
flow.set("profilingMetrics", metrics);
delete msg._profiling;
}
return msg;Bedingte Debug-Ausgabe
Statt Debug Nodes zu aktivieren und deaktivieren, koennen Sie eine Umgebungsvariable nutzen:
// Function Node: Nur bei aktiviertem Debug-Modus ausgeben
const debugEnabled = env.get("DEBUG_FLOWS") === "true";
if (debugEnabled) {
node.warn(`[DEBUG] Payload: ${JSON.stringify(msg.payload)}`);
node.warn(`[DEBUG] Headers: ${JSON.stringify(msg.headers)}`);
}
return msg;docker-compose.yaml:
environment:
- DEBUG_FLOWS=true # Auf "false" setzen fuer ProduktionFehler in asynchronem Code finden
Function Nodes mit asynchronem Code erfordern besondere Aufmerksamkeit:
// Function Node: Asynchronen Fehler korrekt abfangen
try {
const response = await fetch(env.get("API_URL") + "/data");
if (!response.ok) {
node.error(`API-Fehler: HTTP ${response.status}`, msg);
return null;
}
msg.payload = await response.json();
return msg;
} catch (err) {
node.error(`Netzwerkfehler: ${err.message}`, msg);
msg.payload = { error: err.message };
msg.statusCode = 500;
return msg;
}Zusammenfassung
| Technik | Einsatzgebiet | Aufwand |
|---|---|---|
| Catch-All-Handler | Unbehandelte Fehler auffangen | Gering |
| Message-Tracing | Nachrichtenfluss nachvollziehen | Mittel |
| History-Logging | Intermittierende Fehler finden | Mittel |
| Performance-Profiling | Engpaesse identifizieren | Mittel |
| Bedingte Debug-Ausgabe | Produktion vs. Entwicklung | Gering |
| Async-Fehlerbehandlung | API-Aufrufe absichern | Gering |
Weiterführende Informationen
- Grundlagen-Debugging — Einstieg in das Debugging mit Node-RED
- Performance-Optimierung — Engpaesse beheben
- Logs analysieren — Serverseite Log-Analyse