
Un trazador de syscalls moderno construido sobre eBPF. Piensa en strace, pero con una TUI real, filtros inteligentes, descifrado TLS y una salida que realmente se puede leer.
Un rastreador de llamadas al sistema para Linux, construido sobre eBPF. Como strace pero con una TUI en vivo, filtros inteligentes y decodificación de argumentos que realmente puedes leer.

$ 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>
O ejecútalo sin --raw y obtén una TUI a pantalla completa:
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 usa ptrace, lo que detiene tu proceso en cada llamada al sistema. snoop usa tracepoints de eBPF en su lugar — tu proceso sigue ejecutándose a máxima velocidad con el rastreo ocurriendo dentro del kernel. Más allá del rendimiento, snoop decodifica argumentos en algo que realmente puedes leer, tiene una TUI en tiempo real, y puede guardar/reproducir/diferenciar trazas.
--raw (compatible con strace), --json (JSON Lines para jq), --explain (agrupa llamadas en resúmenes de actividad de alto nivel)--files, --net, --slow 10, --syscall openat-p PID) o lanzar uno (snoop <comando>)--follow también rastrea procesos hijo bifurcados--docker <nombre> y rastrean todo dentro de un contenedorSin módulos del kernel, sin cadena de herramientas C. Los programas eBPF son Rust puro (aya) y se envían embebidos en el binario.
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
Para aarch64, reemplaza x86_64 por aarch64.
cargo install --git https://github.com/pandaadir05/snoop snoop
Esto compila los programas eBPF automáticamente. No se necesita cadena de herramientas C ni cabeceras del kernel, solo Rust.
# Trace a command
sudo snoop ls /etc
sudo snoop -- nginx -g 'daemon off;'
# Attach to a running process
sudo snoop -p $(pidof postgres)
sudo snoop -p 1234 --follow # trace forked children too
# Containers
sudo snoop --docker my-nginx
sudo snoop --pod my-app-pod --namespace production
# Filtering
sudo snoop -p 1234 --files # only file-system calls
sudo snoop -p 1234 --net # only network calls
sudo snoop -p 1234 --slow 5 # only calls slower than 5ms
sudo snoop -p 1234 --syscall openat --syscall read
--explain agrupa las llamadas al sistema en resúmenes de alto nivel en lugar de mostrar cada llamada individualmente:
sudo snoop -p 1234 --explain
READ /etc/passwd ↓1.2 KB (2 calls, 0.80ms)
NET 127.0.0.1:5432 ↑512 B ↓4.0 KB (18.20ms)
EXEC /usr/bin/python3
Engancha SSL_write/SSL_read en OpenSSL para capturar texto plano:
sudo snoop -p 1234 --tls
sudo snoop -p 1234 --ltrace
Graba una traza, luego reprodúcela más tarde sin 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")'
Útil para detectar regresiones después de un despliegue:
sudo snoop record -p 1234 -o before.snoop
# ... deploy change ...
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%)
ONLY IN after
statx (4x)
sudo snoop -p 1234 --json | jq 'select(.name == "connect")'
sudo snoop -p 1234 --flamegraph syscalls.svg
-p, --pid <PID> Attach to a running process
--follow Trace forked children (requires --pid)
--docker <NAME|ID> Trace all processes in a Docker container
--pod <POD> Trace all processes in a Kubernetes pod
-n, --namespace <NS> Kubernetes namespace (default: default)
--raw One-line strace-compatible output
--json JSON Lines — one object per syscall
--explain Semantic activity summaries
--files File-system syscalls only
--net Network syscalls only
--slow <MILLIS> Only calls slower than threshold
--syscall <NAME> Only this syscall (repeatable)
--no-decode Raw hex arguments, no decoding
--tls Capture TLS plaintext via SSL_write/SSL_read uprobes
--ltrace Trace malloc/free/calloc/realloc
--flamegraph <PATH> Write flamegraph SVG on exit
--ebpf-obj <PATH> Override embedded eBPF object [$SNOOP_EBPF_OBJ]
Dos programas eBPF se adjuntan a raw_syscalls/sys_enter y sys_exit. Al entrar, el número de syscall y los argumentos se guardan en un mapa temporal por hilo. Al salir, el valor de retorno se empareja con los datos de entrada y se envía a un buffer circular. El espacio de usuario lee el buffer circular a través de un fd asíncrono y pasa todo por el pipeline de filtro/decodificación.
kernel userspace
────── ─────────
raw_syscalls/sys_enter ──► SYSCALL_ENTER map (per-tid scratch)
raw_syscalls/sys_exit ──► EVENTS ring buffer (4 MiB)
│
poll consumer (tokio::spawn)
│
┌──────────┴──────────┐
RawOutput TuiApp
(one line/syscall) (ratatui TUI)
Los programas eBPF están escritos en Rust con aya, compilados a bytecode BPF en tiempo de compilación, y embebidos en el binario. Sin dependencias en tiempo de ejecución, sin cabeceras del kernel.
git clone https://github.com/pandaadir05/snoop
cd snoop
# Nightly is only needed for the BPF target
rustup toolchain install nightly
rustup component add rust-src --toolchain nightly
# bpf-linker links the eBPF object (no system LLVM needed)
cargo install bpf-linker --no-default-features
cargo build --release
sudo ./target/release/snoop -p $$
El script de compilación compila los programas eBPF automáticamente. No se necesita un paso separado.
Durante el desarrollo también puedes usar xtask:
cargo xtask run -- -p $$
MIT o Apache-2.0, a tu elección.
--pod <nombre>--tls engancha SSL_write/SSL_read mediante uprobes para mostrar texto plano--ltrace sigue malloc/free/calloc/reallocsnoop record guarda en disco, snoop view reproduce sin conexión (sin necesidad de root)snoop diff before.snoop after.snoop muestra lo que cambió entre dos ejecuciones--flamegraph out.svg| Tecla | Acción |
|---|
q | Salir |
Space | Pausar / reanudar |
/ | Búsqueda incremental |
f | Alternar filtro de sistema de archivos |
n | Alternar filtro de red |
c | Limpiar lista de eventos |
Enter | Mostrar ventana emergente de detalles para el evento seleccionado |
↑ / k | Desplazar hacia arriba |
↓ / j | Desplazar hacia abajo |
G / End | Ir al evento más reciente |
g / Home | Ir al evento más antiguo |
| Capa | Crate |
|---|
| Programas eBPF | aya-ebpf |
| Cargador eBPF | aya |
| TUI | ratatui + crossterm |
| CLI | clap (derive) |
| Entorno asíncrono | tokio |
| Flamegraph | inferno |