{"id":51334524,"url":"https://github.com/uselessgoddess/syren","last_synced_at":"2026-07-02T01:32:12.948Z","repository":{"id":366689586,"uuid":"1277425062","full_name":"uselessgoddess/syren","owner":"uselessgoddess","description":"modern eBPF-ready observability tool for syscalls","archived":false,"fork":false,"pushed_at":"2026-06-22T22:16:19.000Z","size":62,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-23T00:13:26.687Z","etag":null,"topics":["ebpf","linux","strace"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/uselessgoddess.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE-APACHE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":"ROADMAP.md","authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-22T22:13:20.000Z","updated_at":"2026-06-22T22:16:23.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/uselessgoddess/syren","commit_stats":null,"previous_names":["uselessgoddess/syren"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/uselessgoddess/syren","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uselessgoddess%2Fsyren","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uselessgoddess%2Fsyren/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uselessgoddess%2Fsyren/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uselessgoddess%2Fsyren/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/uselessgoddess","download_url":"https://codeload.github.com/uselessgoddess/syren/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uselessgoddess%2Fsyren/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35029796,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-01T02:00:05.325Z","response_time":130,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ebpf","linux","strace"],"created_at":"2026-07-02T01:32:12.354Z","updated_at":"2026-07-02T01:32:12.925Z","avatar_url":"https://github.com/uselessgoddess.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# syren\n\n**A modern, eBPF-ready observability tool for syscalls — a friendly `strace` alternative, written in Rust.**\n\n[![CI](https://github.com/uselessgoddess/syren/actions/workflows/ci.yml/badge.svg)](https://github.com/uselessgoddess/syren/actions/workflows/ci.yml)\n[![License: MIT OR Apache-2.0](https://img.shields.io/badge/license-MIT%20OR%20Apache--2.0-blue.svg)](#license)\n[![MSRV](https://img.shields.io/badge/MSRV-1.85-orange.svg)](#building-from-source)\n\nsyren runs a program (or attaches to a running one), watches the system calls it\nmakes, decodes their arguments into something a human can read, and prints them —\nas classic strace-style text, as machine-readable NDJSON, or as an aggregate\nsummary table.\n\n```console\n$ syren echo hi\nbrk(NULL) = 0x55a3c321b000\nmmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x768b2d49c000\naccess(\"/etc/ld.so.preload\", 4) = -1 ENOENT (No such file or directory)\nopenat(AT_FDCWD, \"/etc/ld.so.cache\", O_RDONLY|O_CLOEXEC, 0) = 3\n...\nwrite(1, \"hi\\n\", 3) = 3\n+++ exited with 0 +++\n```\n\n\u003e [!NOTE]\n\u003e **Project status.** syren ships a complete, tested tracing pipeline on an\n\u003e **unprivileged `ptrace(2)` backend** that needs no root and runs anywhere Linux\n\u003e does (including CI). A **low-overhead eBPF backend** (aya, `raw_syscalls`\n\u003e tracepoints) is implemented behind the off-by-default `ebpf` feature and emits\n\u003e the very same event stream, so it slots in under `--backend ebpf` without\n\u003e touching the decode/output layers — and syren falls back to ptrace when eBPF is\n\u003e unavailable. See [the roadmap](ROADMAP.md) for what's next (richer decoders, a\n\u003e live TUI, more export formats).\n\n## Why syren\n\n- **Autogenerated syscall coverage, not hand-maintained tables.** The syscall\n  table (number ↔ name ↔ category ↔ argument shapes) is generated at build time\n  from the kernel's own `syscall_64.tbl` plus a metadata layer. Adding a syscall\n  is editing data, not code.\n- **strace-compatible output.** Trace lines look like strace's, and — like\n  strace — go to **stderr**, so the traced program's own stdout/stderr pass\n  through untouched and stay pipeable.\n- **Symbolic, colourised arguments.** Raw numbers become names: `socket(10, 2,0)` \n  prints as `socket(AF_INET6, SOCK_DGRAM, IPPROTO_IP)`, flag words decode to\n  `O_RDONLY|O_CLOEXEC`, and pointed-to values render as `[1]` — the shorthand\n  strace uses. Output is coloured on a terminal (`--color`, honours `NO_COLOR`).\n- **Structured output for tooling.** `--json` emits one NDJSON record per\n  syscall, ready for `jq`, a log pipeline, or a notebook.\n- **An aggregate view.** `-c` prints a `strace -c`-style table: call counts,\n  time, and errors per syscall.\n- **A low-overhead eBPF backend.** Backends sit behind one trait, selectable\n  with `--backend`; the eBPF engine (aya, `raw_syscalls` tracepoints) emits the\n  same event stream as ptrace — no change to the decode/output layers — and lives\n  behind the off-by-default `ebpf` feature so the standard build needs no BPF\n  toolchain. See [The eBPF backend](#the-ebpf-backend).\n\n## Building from source\n\n```console\n$ git clone https://github.com/uselessgoddess/syren\n$ cd syren\n$ cargo build --release\n# the binary is target/release/syren\n```\n\nOr install it onto your `PATH`:\n\n```console\n$ cargo install --path crates/syren-cli\n```\n\nsyren is **Linux/x86-64** only — it traces the Linux syscall ABI directly.\n\n## Usage\n\n```console\n$ syren [OPTIONS] COMMAND [ARGS...]      # spawn and trace a program\n$ syren -p PID [OPTIONS]                 # attach to a running process\n```\n\n| Flag | Meaning |\n| --- | --- |\n| `-p, --pid \u003cPID\u003e` | Attach to a running process (repeatable). |\n| `-f, --follow` | Follow `fork`/`vfork`/`clone` into children and new threads. |\n| `-e, --expr \u003cEXPR\u003e` | Restrict to a set of syscalls — see [Filtering](#filtering). |\n| `-c, --summary` | Print an aggregate summary table instead of every call. |\n| `--json` | Emit newline-delimited JSON instead of text. |\n| `-T, --timing` | Annotate each call with its duration. |\n| `-o, --output \u003cFILE\u003e` | Write the trace to a file instead of stderr; `-` means stdout. |\n| `--color \u003cauto\\|always\\|never\u003e` | Colourise the trace (default `auto`; `auto`/`never` honour `NO_COLOR`). |\n| `--backend \u003cptrace\\|ebpf\u003e` | Choose the tracing backend (default `ptrace`). |\n| `--list-syscalls` | Print the known syscall table and exit. |\n\nsyren exits with the traced program's own exit status, just like strace:\n\n```console\n$ syren false; echo \"syren exited $?\"\n...\n+++ exited with 1 +++\nsyren exited 1\n```\n\n### Output formats\n\n**Text (default)** — strace-compatible, to stderr:\n\n```console\n$ syren -e trace=write echo 'hello, syren'\nwrite(1, \"hello, syren\\n\", 13) = 13\n+++ exited with 0 +++\n```\n\n**NDJSON** (`--json`) — one structured record per line, decoded arguments and the\nraw register value side by side:\n\n```console\n$ syren --json -o trace.ndjson echo hi\nhi\n$ jq -c 'select(.type == \"syscall\") | {name, retval}' trace.ndjson\n{\"name\":\"write\",\"retval\":3}\n```\n\n`-o -` sends the stream to **stdout** instead, for a direct pipe when you don't\nalso need the program's own stdout: `syren --json -o - PROG | jq`. To pipe the\ntrace through `jq` *and* keep the program's own output, hand `-o` a process\nsubstitution: `syren --json -o \u003e(jq .) PROG`.\n\nA single record, pretty-printed here — the real output is one object per line:\n\n```console\n{\"type\":\"syscall\",\"pid\":727257,\"tid\":727257,\"nr\":1,\"name\":\"write\",\n \"args\":[{\"name\":\"fd\",\"value\":\"1\",\"raw\":1},\n         {\"name\":\"buf\",\"value\":\"\\\"hi\\\\n\\\"\",\"raw\":105374297248496},\n         {\"name\":\"count\",\"value\":\"3\",\"raw\":3}],\n \"retval\":3,\"duration_ns\":17897,\"ts_enter_ns\":3376720}\n{\"type\":\"exit\",\"pid\":727257,\"code\":0}\n```\n\n**Summary** (`-c`) — aggregate like `strace -c`:\n\n```console\n$ syren -c ls\n% time     seconds  usecs/call     calls    errors syscall\n------ ----------- ----------- --------- --------- ----------------\n 63.80    0.011418        1427         8           mmap\n 16.31    0.002919         729         4           close\n 15.97    0.002858        1428         2           openat\n  3.06    0.000547         547         1           write\n  0.86    0.000155         154         1           read\n------ ----------- ----------- --------- --------- ----------------\n100.00    0.017897                    16           total\n```\n\n### Filtering\n\n`-e` restricts which syscalls are reported. It accepts comma-separated syscall\nnames, `%category` groups, or the keyword `all`, with an optional `trace=`\nprefix (strace-compatible). Repeat `-e` to union several sets:\n\n```console\n$ syren -e trace=openat,read,write cat /etc/hostname    # by name\n$ syren -e %fs ls                                       # a whole category\n$ syren -e read -e write -e %net curl example.com       # unioned\n```\n\nCategories come from the generated table (`fs`, `net`, `memory`, `process`,\n`signal`, `ipc`, `time`, `security`, `system`, …). List the full table — number,\nname and category — with:\n\n```console\n$ syren --list-syscalls\n  nr  name                     category\n   0  read                     fs\n   1  write                    fs\n   2  open                     fs\n ...\n```\n\n## The eBPF backend\n\nFor low-overhead tracing on a capable kernel, syren can drive the stream from\n**eBPF** instead of ptrace. It attaches to the architecture-independent\n`raw_syscalls` tracepoints, pairs each `sys_enter` with its `sys_exit` and\ncaptures path arguments **in-kernel**, then streams one record per syscall to\nuserspace over a ring buffer — producing the **same event stream** as ptrace, so\nthe decode and output layers are reused unchanged.\n\nWhy bother: ptrace stops the tracee twice per syscall (two context switches every\ntime); eBPF runs in the kernel and avoids those stops entirely, which is decisive\nunder syscall-heavy load. Measure it on your own machine with `just bench`.\n\nThe backend is gated behind an **off-by-default `ebpf` feature** — the standard\nbuild stays std-only and needs no BPF toolchain — and requires `CAP_BPF` (or\nroot) plus a BTF-enabled kernel (`/sys/kernel/btf/vmlinux`). When either is\nmissing, syren prints a notice and falls back to ptrace, so `--backend ebpf` is\nalways safe to ask for:\n\n```console\n$ cargo build --release --features ebpf -p syren-cli\n$ sudo target/release/syren --backend ebpf -e trace=openat cat /etc/hostname\nopenat(AT_FDCWD, \"/etc/hostname\", O_RDONLY|O_CLOEXEC) = 3\n+++ exited with 0 +++\n```\n\nThe in-kernel program lives in the workspace-excluded `syren-ebpf` crate; its\ncompiled object is checked in at `crates/syren-trace/src/bpf/syren.bpf.o` and\nrebuilt with `just bpf` (needs a nightly toolchain and `bpf-linker`).\n\n## Comparison with strace\n\n|                         | `strace`            | `syren`                         |\n| ----------------------- | ------------------- | ------------------------------- |\n| Backend                 | ptrace              | ptrace + eBPF (feature-gated)   |\n| Syscall table           | hand-maintained     | **autogenerated** from the kernel table |\n| Text output             | ✅                  | ✅ (strace-compatible)          |\n| Structured output       | `-y`/JSON (limited) | ✅ NDJSON, one record per call  |\n| Summary (`-c`)          | ✅                  | ✅                              |\n| Categories (`%fs`, …)   | ✅                  | ✅ (from generated metadata)    |\n| Written in              | C                   | Rust                            |\n\nsyren is young: strace remains the feature-complete reference. syren's bet is\nthat an autogenerated core plus structured output plus an eBPF backend is a\nbetter foundation to grow from.\n\n## Contributing\n\nContributions are welcome — see [`CONTRIBUTING.md`](CONTRIBUTING.md) for the dev\nloop, the local CI checklist, and how the syscall table is generated.\n\n## Roadmap\n\nThe short version: richer decoders -\u003e a live `ratatui` TUI -\u003e more export formats\n(Chrome trace, Parquet, Prometheus) -\u003e strace drop-in mode. The full, staged plan\nlives in [`ROADMAP.md`](ROADMAP.md).\n\n## License\n\nLicensed under either of [Apache License, Version 2.0](LICENSE-APACHE) or\n[MIT license](LICENSE-MIT) at your option. Unless you explicitly state otherwise,\nany contribution intentionally submitted for inclusion in this project, as\ndefined in the Apache-2.0 license, shall be dual licensed as above, without any\nadditional terms or conditions.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fuselessgoddess%2Fsyren","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fuselessgoddess%2Fsyren","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fuselessgoddess%2Fsyren/lists"}