
Live-Kernel-Signal-Beobachtungswerkzeug, das eBPF-Tracepoints verwendet, um jedes auf einem Linux-Host ausgelöste Signal zu streamen und in Echtzeit Sender, Ziel, Disposition, Handler-Latenz und Syscall-Unterbrechungen anzuzeigen.
sigwire
tail -ffür Signale. Jedes Signal, das irgendein Prozess auf dem Rechner auslöst – wer es gesendet hat, wen es getroffen hat, welches Signal, wie es ausgelöst wurde (kill(2), der Kernel, ein POSIX-Timer), ob das Ziel es abgefangen hat und wie lange sein Handler lief, ob es einen blockierten Syscall mitEINTRzerrissen hat – dekodiert von den Signal-Tracepoints des Kernels und live an dein Terminal gestreamt. Keinstrace -fauf einer PID, keinptrace, keine Kooperation der beteiligten Prozesse.
sigwire verwandelt die Signalmaschinerie des Kernels in ein live Patchbay: Jede Zeile ist Sender ──SIGNAL──▶ Ziel, farblich nach Schweregrad, getaggt damit, wie es ausgelöst wurde, ob das Ziel es abgefangen hat (und wie lange sein Handler lief), ob es einen blockierten Syscall unterbrochen hat (↯ EINTR read), auf ×N zusammengefasst, wenn etwas spammt, und mit ☠ markiert, wenn es ein echter Todesstoß ist. Eine Seitenleiste zählt, was über die Leitung fliegt; pausiere und wähle eine Zeile, um das vollständige Bild zu inspizieren – Disposition, Handler-Adresse, sigaction-Flags und die Signale, die das Ziel in diesem Moment blockiert hat.
Da es die Tracepoints des Kernels anzapft und nicht einen einzelnen Prozess, beobachtet ein einziger Durchlauf jedes Signal auf dem Host gleichzeitig – deine App, ein Supervisor, die eigene Fehlermechanik des Kernels – ohne dass einer von ihnen merkt, dass er getraced wird.
[!TIP] Zwei Seiten jedes Signals. sigwire beobachtet sowohl
signal:signal_generate(die Sicht des Senders – wer was ausgelöst hat, die Leitungsverbindung) als auchsignal:signal_deliver(die Sicht des Ziels – hat es das Signal abgefangen, mit welchem Handler und welchen Flags, was hat es blockiert, und hat es einen Syscall unterbrochen). Zwei weitere Hooks –rt_sigreturn(2)und der Syscall-Exit-Tracepoint – messen die Zeit des Handlers und fangen EINTR ab. Alles wird wieder zu einer Zeile zusammengeführt. Diese Aufteilung ist auch der Grund, warum die☠ fatal-Zählung bewusst konservativ ist (siehe What counts as fatal): Die Erzeugung findet vor der Zustellung statt, daher kann die Senderseite das Schicksal eines Signals nicht kennen – nur die Zustellseite kann es, und auch nur für die Fälle, die sie beobachtet.
curl -fsSL https://yeet.cx | sh # install the yeet daemon (one time) yeet run github:yeet-src/sigwire # run the dashboard (the daemon does the privileged BPF load)
[Installationsanleitung für manuelle Installation](https://yeet.cx/docs/manual-installation) | Nur Linux
Nichts zu konfigurieren — Signale sind ständiger Hintergrundverkehr auf jeder Kiste, also landen Zeilen sofort oben. Möchtest du selbst welche erzeugen? `kill -USR1 <pid>`, `Ctrl-C` für einen Vordergrundjob, oder starte eine verwaltete Laufzeitumgebung und beobachte, wie der GC/Scheduler seine eigenen Threads pingt (`↯ EINTR futex` scrollt vorbei).
## Steuerung
Der Feed folgt standardmäßig dem neuesten Signal; wähle eine Zeile aus oder pausiere, dann bleibt sie stehen, während Daten darunter weiterfließen.
| Taste | Aktion |
| ----- | ------ |
| `p` · `Leertaste` | Feed pausieren / fortsetzen (einfrieren zum Lesen) |
| `↑`/`↓`, `k`/`j` | pausieren und eine Zeile inspizieren — öffnet das Detailfeld |
| `/` | unscharfer Filter — durchsucht Prozess, PID, Signal, Quelle und Disposition; übereinstimmende Zeichen werden live hervorgehoben |
| `e` | filtere auf **unterbrochene Syscalls** (`↯ EINTR` / `↺ neu gestartet`) |
| `s` | öffne die **Signalauswahl** — blende ein Signal stumm oder zeige es live an |
| `Esc` | eine Ebene zurück — Filter löschen / Auswahl schließen / Selektion aufheben, dann beenden |
| `q` | beenden |
## Was du siehst
Jede Zeile ist ein generiertes Signal, das neueste oben:```
WHEN SENDER SIGNAL TARGET NOTE
now bash·4402──SIGINT───▶ node·8813 kill(2) ↯ EINTR read caught 41µs
1.2s systemd·1──────SIGTERM──▶ nginx·1291 kill(2) caught 1.2ms
3.4s kernel·8813──SIGSEGV──▶ chrome·8813 fault default ☠
4.1s postgres·507──SIGUSR1───▶ postgres·509 ×6 kill(2) caught 9µs
Jede Zeile ist ein Block: der Absender → Ziel sind comm·pid (der Absender ist derjenige, der das Signal ausgelöst hat, current; das Ziel ist der, an den es adressiert ist), der Draht in der Mitte trägt den nach Schweregrad farbigen Signalnamen, ×N fasst einen Burst identischer Signale in eine Zeile zusammen, und die Notiz rechts gibt die Quelle, dann eine eventuelle Syscall-Unterbrechung, dann die Disposition an.
Jede Zeile wird in dem Moment eingefroren, in dem ihre Zustellung aufgelöst wird, und ändert sich nie wieder – ein Burst rollt also als stabiles Log vorbei, nicht als flackernder Aggregat.
Der Draht ist nach Schweregrad gefärbt auf derselben 256-Farbpalette wie der Rest der UI:
| Schweregrad | Signale | Farbe |
|---|---|---|
| tödlich | SIGKILL | heißrot |
| fatal (mit Kernspeicherauszug) | SEGV BUS ABRT ILL FPE TRAP SYS QUIT | rot |
| terminierend | TERM INT HUP PIPE ALRM … | bernsteinfarben |
| Jobkontrolle | STOP TSTP TTIN TTOU | gelb |
| fortsetzen | CONT | grün |
| benutzerdefiniert | USR1 USR2 | cyan |
| Echtzeit | SIGRTMIN+n | violett |
| Haushalt | CHLD URG WINCH … | grau |
Die Notiz ist die Quelle (kill(2), tgkill, sigqueue, timer, kernel, fault); dann, falls ein blockierter Syscall unterbrochen wurde, ↯ EINTR read (oder ↺ restarted read, wenn SA_RESTART ihn automatisch wieder aufgenommen hat); dann die Disposition — caught 41µs (ein Handler lief, und wie lange er dauerte), default (kein Handler, die Standardaktion angewendet) oder ⊘ ignored. Ein ☠ markiert einen echten Todesstoß (siehe Was als tödlich zählt).
[!NOTE]
↯ EINTRist das, worauf man achten sollte. Ein Signal, das eintrifft, während ein Thread in einem langsamen Syscall (z. B.read,poll,accept,futex,nanosleep, ...) blockiert ist, reißt ihn heraus: Der Syscall gibt-1/EINTRzurück und, sofern der Handler nichtSA_RESTARTgesetzt hat, wird er nicht fortgesetzt — die Anwendung muss es erneut versuchen. Dies zu vergessen ist ein klassischer, frustrierender, zeitabhängiger Fehler („Warum ist meinread()einmal fehlgeschlagen?“). sigwire zeigt es live und zeigt, welcher Syscall betroffen war. Drücken Siee, um alles andere auszublenden und nur die Unterbrechungen zu beobachten.
Die Leiste auf der rechten Seite ist die Aggregatansicht: Top-Signale nach Volumen, eine Aufschlüsselung nach Quelle und eine Zustellungs-Zählung — wie viele Signale abgefangen wurden, wie viele ihr Standard auslösten und wie viele ignoriert wurden.