Command-line interface¶
Installing epigrep puts an epigrep command on your PATH — grep, but for
event sequences rather than lines. The same thing is available as
python -m epigrep if you prefer.
epigrep --version
The CLI has three subcommands that mirror the Python entrypoints, so it teaches the same model:
| Command | Does |
|---|---|
epigrep match |
print the spans that match a pattern |
epigrep explain |
print near-miss explanations for starts that did not match |
epigrep schema |
summarise the event types, attributes, and partitions in a stream |
Input: JSONL events¶
Events are read as JSONL — one JSON object per line, in the same shape as the event model:
{"partition": "api-0", "ts": 0, "typ": "config_reload"}
{"partition": "api-0", "ts": 30, "typ": "readiness_success"}
{"partition": "api-0", "ts": 70, "typ": "oom_killed"}
{"partition": "api-1", "ts": 0, "typ": "config_reload"}
{"partition": "api-1", "ts": 90, "typ": "oom_killed", "attrs": {"pod": "api-1"}}
attrs is optional. Pass a file path, -, or nothing at all to read from
standard input, so the CLI drops into pipelines:
cat events.jsonl | epigrep schema -
CSV and parquet¶
CSV and parquet inputs are also supported. Their rows are flat records — one
column each for the partition, timestamp, and type, and the rest become event
attributes. The format is inferred from the file extension (.csv, .parquet /
.pq), or set it explicitly with --input-format:
epigrep match --pattern-json pattern.json events.csv
epigrep schema events.parquet
By default the columns are partition, ts, and typ; map other names with
--partition-col / --ts-col / --type-col, and restrict which remaining
columns become attributes with --attr-cols a,b,c:
epigrep match --pattern-json pattern.json \
--partition-col pod --ts-col t --type-col event app.csv
These reuse the same eventise ingestion primitive as the
Python API, so behaviour matches. Two notes: CSV values arrive
as strings (timestamps are parsed to integers; numeric attributes stay strings,
where parquet preserves real types), and parquet must be a file path — it cannot
be read from stdin.
Patterns¶
A pattern comes from one of two flags:
--pattern-json FILE— a JSON pattern AST, the stable construction surface. Produce one from the builder withPattern(...).to_json().--pattern TEXT— the text DSL. This is experimental and outside the 0.1 stability guarantee; prefer the JSON form for anything you want to keep.
epigrep match --pattern-json pattern.json events.jsonl
Output¶
The default output is JSON, which is easy to pipe into jq or another tool. Pass
--format table for a compact human view.
$ epigrep match --pattern-json pattern.json --format table events.jsonl
api-1 [0..90] config_reload -> oom_killed
$ epigrep explain --pattern-json pattern.json --format table events.jsonl
api-0 reached [0]; would match if readiness_success at 1 were absent (before oom_killed at 2)
$ epigrep schema --format table events.jsonl
events: 5
partitions: 2 ['api-0', 'api-1']
time range: [0, 90]
event types:
config_reload (x2)
pod: string
...
In JSON mode, match emits one object per span (partition, start, end,
indices, types, captures) and explain emits one per near-miss, including
a ready-made summary string.
Exit codes¶
match follows grep's exit-code contract, so it composes in shell logic:
| Code | Meaning |
|---|---|
0 |
at least one match |
1 |
no match |
2 |
error (bad pattern, unreadable file, malformed JSONL) |
# Only deploy if no pod has the config-reload → OOM sequence.
if ! epigrep match --pattern-json pattern.json events.jsonl >/dev/null; then
./deploy.sh
fi
explain and schema return 0 on success and 2 on error.
Other flags¶
--exhaustive(onmatch) — emit every satisfying successor per start instead of committing to the first one. See semantics.--assume-sorted— declare that the input is already grouped by partition and sorted by(ts, input order), skipping the internal sort. With this set, theindicesin the output line up with input line order.
Next¶
- Loading data — the Python ingestion helpers behind the CLI.
- Patterns — build the patterns you feed it.