
Un traceur d'appels système moderne construit sur eBPF. Pensez à strace, mais avec une véritable IUT, des filtres intelligents, le déchiffrement TLS et une sortie réellement lisible.
Un traceur d'appels système pour Linux, construit sur eBPF. Comme strace, mais avec une TUI en direct, des filtres intelligents et un décodage d'arguments que vous pouvez réellement lire.

$ sudo snoop curl https://example.com
[ 0.001] curl(1234/1234) openat(AT_FDCWD, "/etc/ssl/certs/ca-certificates.crt", O_RDONLY) = 4 <0.031ms>
[ 0.002] curl(1234/1234) read(4, 0x7f3a1c000b20, 4096) = 4096 <0.012ms>
[ 0.003] curl(1234/1234) socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) = 5 <0.008ms>
[ 0.004] curl(1234/1234) connect(5, 93.184.216.34:443) = 0 <42.187ms>
[ 0.046] curl(1234/1234) sendto(5, 0x55a3bc001b40, 78, MSG_NOSIGNAL) = 78 <0.011ms>
Ou exécutez-le sans --raw pour obtenir une interface TUI plein écran :
snoop pid:1234 comm:curl events:142 elapsed:0.341s
┌── syscall stream ─────────────────────────────────────┐┌── top syscalls ─────────┐
│ [ 0.001] curl openat("/etc/ssl/…") = 4 <0.031ms> ││ syscall count pct│
│ [ 0.002] curl read(4, …) = 4096 ││ read 38 26.8%│
│ [ 0.003] curl socket(AF_INET, …) = 5 ││ write 21 14.8%│
│ [ 0.004] curl connect(5, 93.184.216.34:443) = 0 ││ openat 18 12.7%│
│ [ 0.046] curl sendto(5, …) = 78 ││ mmap 14 9.9%│
└───────────────────────────────────────────────────────┘└─────────────────────────┘
[q]uit [Space]pause [/]search [f]iles [n]et [c]lear [↑↓]scroll [G]bottom
strace utilise ptrace, ce qui stoppe votre processus à chaque appel système. snoop utilise plutôt des points de trace eBPF — votre processus continue à s'exécuter à pleine vitesse tandis que le traçage se fait dans le noyau. Au-delà des performances, snoop décode les arguments en quelque chose de lisible, possède une TUI en temps réel et peut sauvegarder/rejouer/comparer des traces.
--raw (compatible strace), --json (JSON Lines pour jq), --explain (regroupe les appels système en résumés d'activité de haut niveau)--files, --net, --slow 10, --syscall openat-p PID) ou lancer une commande (snoop <cmd>)--follow trace également les processus fils forké--docker <nom> et tracent tout ce qui se trouve dans un conteneurPas de modules noyau, pas de chaîne d'outils C. Les programmes eBPF sont en Rust pur (aya) et sont embarqués dans le binaire.
CAP_BPF + CAP_PERFMONcurl -L https://github.com/pandaadir05/snoop/releases/latest/download/snoop-x86_64-linux.tar.gz \
| tar -xz
sudo install -m755 snoop /usr/local/bin/snoop
Pour aarch64, remplacez x86_64 par aarch64.
cargo install --git https://github.com/pandaadir05/snoop snoop
Ceci compile automatiquement les programmes eBPF. Pas besoin de chaîne d'outils C ni d'en-têtes noyau, seulement Rust.
# Tracer une commande
sudo snoop ls /etc
sudo snoop -- nginx -g 'daemon off;'
# Attacher à un processus en cours
sudo snoop -p $(pidof postgres)
sudo snoop -p 1234 --follow # tracer aussi les processus fils forké
# Conteneurs
sudo snoop --docker my-nginx
sudo snoop --pod my-app-pod --namespace production
# Filtrage
sudo snoop -p 1234 --files # uniquement les appels système de fichiers
sudo snoop -p 1234 --net # uniquement les appels réseau
sudo snoop -p 1234 --slow 5 # uniquement les appels plus lents que 5ms
sudo snoop -p 1234 --syscall openat --syscall read
--explain regroupe les appels système bruts en résumés de haut niveau au lieu d'afficher chaque appel individuellement :
sudo snoop -p 1234 --explain
READ /etc/passwd ↓1.2 Ko (2 appels, 0.80ms)
NET 127.0.0.1:5432 ↑512 B ↓4.0 Ko (18.20ms)
EXEC /usr/bin/python3
Accroche SSL_write/SSL_read dans OpenSSL pour capturer le texte clair :
sudo snoop -p 1234 --tls
sudo snoop -p 1234 --ltrace
Enregistrez une trace, puis rejouez-la plus tard sans root :
sudo snoop record -p 1234 -o trace.snoop
snoop view trace.snoop
snoop view trace.snoop --files --slow 5 --json | jq 'select(.name=="read")'
Utile pour repérer des régressions après un déploiement :
sudo snoop record -p 1234 -o before.snoop
# ... déployer le changement ...
sudo snoop record -p 1234 -o after.snoop
snoop diff before.snoop after.snoop
SYSCALL COUNTS
read 1200 → 1800 (+50.0%) ▲
openat 340 → 210 (-38.2%) ▼
DURATION REGRESSIONS (median)
read 0.02ms → 0.08ms (+300%)
UNIQUEMENT DANS after
statx (4x)
sudo snoop -p 1234 --json | jq 'select(.name == "connect")'
sudo snoop -p 1234 --flamegraph syscalls.svg
-p, --pid <PID> Attacher à un processus en cours
--follow Tracer les processus fils forké (nécessite --pid)
--docker <NOM|ID> Tracer tous les processus d'un conteneur Docker
--pod <POD> Tracer tous les processus d'un pod Kubernetes
-n, --namespace <NS> Espace de noms Kubernetes (par défaut : default)
--raw Sortie compatible strace sur une seule ligne
--json JSON Lines — un objet par appel système
--explain Résumés d'activité sémantiques
--files Appels système de fichiers uniquement
--net Appels système réseau uniquement
--slow <MILLIS> Uniquement les appels plus lents que le seuil
--syscall <NOM> Uniquement cet appel système (répétable)
--no-decode Arguments hexadécimaux bruts, pas de décodage
--tls Capturer le texte clair TLS via des uprobes SSL_write/SSL_read
--ltrace Tracer malloc/free/calloc/realloc
--flamegraph <CHEMIN> Écrire un SVG de flamegraph à la sortie
--ebpf-obj <CHEMIN> Remplacer l'objet eBPF embarqué [$SNOOP_EBPF_OBJ]
Deux programmes eBPF se fixent sur raw_syscalls/sys_enter et sys_exit. À l'entrée, le numéro d'appel système et les arguments sont placés dans une zone mémoire de travail par thread. À la sortie, la valeur de retour est associée aux données d'entrée et poussée dans un tampon circulaire. L'espace utilisateur vide le tampon via un fd asynchrone et fait passer le tout dans le pipeline de filtrage/décodage.
noyau espace utilisateur
────── ─────────────────
raw_syscalls/sys_enter ──► CARTE SYSCALL_ENTER (zone par tid)
raw_syscalls/sys_exit ──► TAMPON CIRCULAIRE EVENTS (4 Mio)
│
consommateur poll (tokio::spawn)
│
┌──────────┴──────────┐
RawOutput TuiApp
(une ligne/appel) (ratatui TUI)
Les programmes eBPF sont écrits en Rust avec aya, compilés en bytecode BPF à la compilation et embarqués dans le binaire. Pas de dépendances d'exécution, pas d'en-têtes noyau.
git clone https://github.com/pandaadir05/snoop
cd snoop
# Nightly n'est nécessaire que pour la cible BPF
rustup toolchain install nightly
rustup component add rust-src --toolchain nightly
# bpf-linker lie l'objet eBPF (pas besoin de LLVM système)
cargo install bpf-linker --no-default-features
cargo build --release
sudo ./target/release/snoop -p $$
Le script de compilation compile automatiquement les programmes eBPF. Aucune étape séparée n'est nécessaire.
Pendant le développement, vous pouvez également utiliser xtask :
cargo xtask run -- -p $$
MIT ou Apache-2.0, à votre choix.
--pod <nom>--tls accroche SSL_write/SSL_read via des uprobes pour afficher le texte clair--ltrace suit malloc/free/calloc/reallocsnoop record sauvegarde sur disque, snoop view rejoue hors ligne (pas besoin de root)snoop diff avant.snoop apres.snoop montre ce qui a changé entre deux exécutions--flamegraph out.svg| Touche | Action |
|---|
q | Quitter |
Space | Pause / reprise |
/ | Recherche incrémentale |
f | Activer/désactiver le filtre système de fichiers |
n | Activer/désactiver le filtre réseau |
c | Effacer la liste des événements |
Enter | Afficher les détails de l'événement sélectionné |
↑ / k | Défiler vers le haut |
↓ / j | Défiler vers le bas |
G / End | Aller au dernier événement |
g / Home | Aller au premier événement |
| Couche | Crate |
|---|
| Programmes eBPF | aya-ebpf |
| Chargeur eBPF | aya |
| TUI | ratatui + crossterm |
| CLI | clap (derive) |
| Runtime asynchrone | tokio |
| Flamegraph | inferno |