Kelora
Scriptable log processor for the command line. Treats logs as structured events and lets you filter, transform, and analyze them using embedded Rhai scripts with 40+ built-in functions.
[!WARNING] Experimental tool. Vibe-coded. APIs may change without notice.
Table of Contents
Overview
Kelora parses log streams into structured events and runs them through a programmable pipeline powered by Rhai scripting.
- Turns lines into structured events you can access as
e.fieldore["field-name"]. - Embeds 40+ built-in Rhai helpers for parsing, enrichment, metrics, and windowed analysis.
- Speaks JSON, logfmt, syslog, CSV/TSV, column specs, and gzip-compressed inputs out of the box.
- Handles streaming or batch workloads with sequential and
--parallelexecution modes. - Emits metrics and processing stats so you can observe pipelines while they run.
Getting Started
First Commands
# Filter error-level events from the logfmt sample
# Focus on database events and surface slow queries
# Parse Apache/Nginx access logs, keep key fields, and surface stats
# Show login-related events with surrounding context (like grep -A/-B/-C)
More quick commands to copy-paste:
- Stream-level error watch:
tail -f examples/simple_json.jsonl | kelora -j --level warn,error --exec 'track_count(e.service)' --metrics - Fan out nested arrays:
kelora -j examples/json_arrays.jsonl --exec 'emit_each(e.get_path(\"users\", []))' --keys id,name,score - Alias sensitive fields:
kelora -j examples/security_audit.jsonl --exec 'e.user_alias = pseudonym(e.user, \"users\"); e.ip_masked = e.ip.mask_ip(1)' --keys timestamp,event,user_alias,ip_masked
[!TIP] The sample logs in
examples/map to the categories in examples/README.md. Start there before pointing Kelora at production data. Need a fast reminder of the core flags? Runkelora --help-quick.
Installation
Prebuilt binaries (recommended)
- Download the archive for your platform from the GitHub releases page (macOS, Linux, and Windows builds are provided).
- Unpack the archive and move
keloraorkelora.exesomewhere on yourPATH. - Run
kelora --helpto ensure the binary starts up correctly.
If you prefer to manage the build yourself, Kelora targets stable Rust; keep your toolchain fresh (rustup update) for best results.
Install from crates.io or source
# Install from crates.io
# Build from source
Everyday Use
Core Concepts
- Events - Every log line becomes a structured map. Fields are accessible as
e.level,e["user-agent"], or via helper functions likee.get_path("payload.id"). - Pipeline - Logs flow through
Input -> Parse -> Filter -> Transform -> Format -> Output. Mix and match parsers, filters, exec scripts, and formatters freely. - Scripts - Rhai expressions drive filtering (
--filter), transformations (--exec/--exec-file), initialization (--begin), and teardown (--end). - Windows -
--window Nexposes recent events for sequence detection via helpers likewindow_values("field").
| Stage | Key switches | Purpose |
|---|---|---|
| Input | kelora [FILES], --parallel, --file-order |
Select sources and decide sequential vs. parallel ingestion |
| Parse | -f/--input-format, --extract-prefix, -M/--multiline |
Turn raw text into structured events |
| Filter | --filter, --level, --since/--until |
Keep only the events you care about |
| Transform | -e/--exec, --begin, --window |
Enrich, fan out, and compute stateful metrics |
| Format | -F/--output-format, -k/--keys, --stats |
Control output shape and statistics |
CLI Feature Tour
Input & Parsing
-f, --input-format <FORMAT>selects a parser (json,logfmt,syslog,combined,cols:<spec>, ...);-jis shorthand for JSON.--file-order {cli|name|mtime}controls multi-file processing order.--skip-lines,--keep-lines, and--ignore-linesfilter raw input before parsing.-M, --multiline <strategy>enables multi-line reconstruction (see Multiline Strategies).--extract-prefix FIELD+--prefix-sep SEPslices service prefixes before parsing.--cols-sep SEPprovides a custom delimiter when using column specs.
Filtering & Selection
--filter 'expression'runs boolean Rhai expressions; chain multiple occurrences.--leveland--exclude-levelsgate standard log levels.--since,--until, and--taketrim by time range or limit output volume.-A/--after-context,-B/--before-context, and-C/--contextshow surrounding lines around matches (requires filtering).--keep-lines/--ignore-linespair well with--strictto enforce hygiene.--allow-fs-writesenables Rhai file helpers (mkdir,truncate_file,append_file) so scripts can shard or persist results; without it these functions returnfalseand perform no I/O.
Transformations & State
-e/--execand-E/--exec-filemutate events (e), emit new ones (emit_each), or track metrics.--beginseeds global read-only configuration through theconfmap;--endperforms final aggregation or reporting.--window Nexposeswindowhelpers for sliding analyses; combine withwindow_values(...),window_numbers(...), or custom loops.- Default mode is resilient—errors skip the offending event. Use
--strictfor fail-fast pipelines. - Dial verbosity with
-v/-vvvfor debugging or-q/-qqqfor quiet pipelines. -I/--includeprepends Rhai files to define reusable functions for--exec,--begin, and--endstages.
Output & Reporting
-F/--output-formatcontrols formatting (default,json,logfmt,inspect,levelmap, CSV/TSV variants, ornone).-Jis shorthand for JSON.-k/--keysand-K/--exclude-keysshape the output payload;-ckeeps only core fields;-bswitches to brief mode.--convert-tsconverts timestamp fields to RFC3339 format (modifies event data);-z/--show-ts-localand-Z/--show-ts-utcformat display timestamps (default formatter only).--stats,--metrics, and-S/--stats-onlyexpose processing telemetry;--metrics-filewrites JSON metrics to disk.--mark-gapsinserts visual separators when time jumps exceed a duration;--no-emojidisables emoji prefixes.- Context lines are marked with visual prefixes:
*for matches,/for before-context,\for after-context.
Performance & Reliability
--paralleland--threadscontrol concurrency; pair with--batch-size(lines per worker batch, default 1000) and--batch-timeout(max ms to flush a partial batch, default 200) to balance parallel throughput and latency.--unorderedrelaxes output ordering for faster parallel flushes.- Sequential mode (default) shines for streaming sources;
--parallelexcels at log archives. - Combine with
--config-fileor aliases for repeatable pipelines at scale.
Deep Dives
Parsers & Formats
Kelora defaults to -f line, which trims trailing newline/CR characters and exposes the result as e.line. Reach for -f raw when you need a byte-for-byte copy (including trailing newlines or escape markers), and reserve -f 'cols:<spec>' for bespoke formats that the built-in parsers do not cover. All parsers expect UTF-8 text; binary or other encodings will raise input errors.
| Format | Fields Produced | Typical Source |
|---|---|---|
line (default) |
line |
Newline-delimited text where trimming the trailing newline is acceptable |
raw |
raw |
Exact text preservation (newline-sensitive data, continuation markers, binary artifacts) |
json |
Original JSON keys | JSONL or JSON arrays |
logfmt |
Key-value pairs | Logfmt structured logs |
syslog |
timestamp, host, facility, message, ... |
RFC3164/RFC5424 syslog |
cef |
Header fields + extension map | ArcSight/Common Event Format |
csv / tsv |
Column headers as fields (strings by default) | Delimited datasets |
csv:<spec> / tsv:<spec> |
Column headers with type conversions | Typed CSV/TSV data |
combined |
ip, status, method, path, request, request_time, ... |
Apache/Nginx access logs |
cols:<spec> |
Named fields defined by your spec (ts, level, *rest, ...) |
Custom or proprietary log formats |
All parsers auto-detect gzip compression (files and stdin) by magic bytes—no extra flags required.
Format Recipes
Raw vs Line
Choose the right baseline for text pre-processing. -f line is the default: it trims the trailing newline/CR and gives you a tidy e.line field for downstream filters. -f raw keeps every byte (including trailing delimiters and escape markers) in e.raw, which is invaluable when you need to preserve continuation characters, feed the data into another parser verbatim, or re-emit the original payload.
# Preserve every byte (newline-sensitive analyses)
# Treat each line as plain text for simple filtering
Prefix Extraction
Strip infrastructure prefixes before parsing structured payloads.
| \
Type Annotations
Type annotations allow you to convert string fields to specific types during parsing. Supported for CSV, TSV, and cols formats.
# CSV with typed columns (status, bytes, and duration_ms as integers)
# TSV with type conversions - space-separated field specs
# Cols format with multi-column capture
# Cols with count specifiers and custom separator
# Strict mode: fail on conversion errors instead of falling back to strings
# Works in pipes and with compressed data
|
Supported types:
int- Convert to 64-bit integerfloat- Convert to 64-bit floatbool- Convert to boolean (recognizestrue/false,yes/no,1/0, case-insensitive)- (no annotation) - Keep as string (default)
Error handling:
- Resilient mode (default): Invalid conversions fall back to original string value
- Strict mode (
--strict): Invalid conversions abort processing with error
Format availability:
- CSV/TSV: Type annotations work with headers (
csv,tsv). Headerless formats (csvnh,tsvnh) use auto-generated column names (c1, c2, ...) and don't support type annotations. - Cols: Type annotations can be embedded directly in the column spec (e.g.,
status:int,ts(2):string,*msg:bool)
Column Specs (cols:<spec>)
Declarative column parsing with skips, joins, and tail captures. This mode shines when your data has a repeatable column layout but no dedicated parser—think bespoke appliance logs, legacy flat files, or regex capture groups you want to map into fields.
Spec tokens are space-separated:
field— consume one column intofield.field(n)— consumen ≥ 2columns, joined together (whitespace joins in default mode, literal separator joins when you set one).-/-(n)— skip one orncolumns with no output field.*field— capture the remaining text verbatim; must appear once and always at the end.
Whitespace is the default separator; add --cols-sep "|" (or another literal) when your columns are delimited. You can also feed pre-split arrays to parse_cols from Rhai (let caps = e.line.extract_all_re(...); caps.parse_cols("ip user ts *msg");). Missing data fills fields with () in resilient mode, while --strict turns shortages/extras into errors.
| \
Rhai Building Blocks
Kelora exposes the full Rhai language plus domain-specific helpers.
- Text & parsing -
extract_re,parse_logfmt,parse_cols,mask_ip,encode_*/decode_*. - Arrays & maps -
sorted,sorted_by,array.flatten,map.get_path,map.flatten,emit_each. - Hashing & pseudonymization -
bucket(fast sampling),hash(multi-algo),pseudonym(short IDs). - Metrics -
track_count,track_avg,track_bucket,track_uniquepower--metricsand--endreports. - Datetime -
to_datetime,to_duration,now_utc, formatting helpers, arithmetic. - Environment & control -
get_env,read_file,read_lines,exit.
Example pipeline with shared configuration and sliding logic:
See kelora --help-rhai for syntax essentials and kelora --help-functions for the complete catalog.
Multiline Strategies
Kelora now offers four explicit multiline modes:
timestamp— detect leading timestamps using the adaptive parser. Add:format=<chrono>when you need to seed a specific layout (%b %e %H:%M:%S, etc.).indent— treat any line that begins with indentation as a continuation of the current event.regex:match=<REGEX>[:end=<REGEX>]— provide your own record headers (and optional terminators) when you need full control.all— buffer the entire input as a single event when you already have pre-chunked payloads.
The option stays off unless you pass -M/--multiline. Detection always runs before
parsing, so pair the strategy with the input format you expect (for example, -f raw
before handing events to a JSON parser). Buffering continues until the next detected
start (or end regex) arrives; if you run with --parallel, tune --batch-size or
--batch-timeout to keep memory bounded. Remember that --multiline all keeps the
entire stream in memory until it flushes.
Configuration & Defaults
Define repeatable pipelines in ~/.config/kelora/config.ini:
# Defaults applied to every run
defaults = --stats --parallel --input-tz UTC
[aliases]
errors = --level error --since 1h --stats
warnings = --filter 'e.level == "WARN" || e.level == "WARNING"'
slow-queries = --filter 'e.duration > 1000' --exec 'e.slow = true' --keys timestamp,query,duration
Usage:
Pair configs with --ignore-config for hermetic runs or CI pipelines.
Example Pipelines
# Monitor access logs for server/client errors and count them
# Authentication watch with sliding windows and unique counters
# Convert syslog to structured JSON and redact sensitive fields
# Anonymize sensitive fields while keeping sessions linkable
Advanced Pipelines
# Track slow requests and bucket them by severity
# Expand nested arrays into individual events
# Rolling average over windowed metrics
Troubleshooting
- No events printed: run with
--verboseto surface Rhai errors, or temporarily drop filters (--filter) to confirm parsing succeeds. - Timestamp parsing failures: confirm the field name via
-F json, then add--ts-field/--ts-formatfromkelora --help-time. In resilient mode failed timestamps are dropped silently; add--strictto fail fast. - Rhai script panics: wrap risky lookups with helpers like
e.get_path("field", ())or useto_int_orto coerce strings safely.kelora --help-rhaidocuments the available guards. - Performance dips with
--parallel: trim--windowsizes, avoid heavy per-event printing, and tune--batch-size/--batch-timeoutas described in Performance & Reliability. - Unexpected empty fields: inspect raw input using
-F inspector-F logfmtto ensure the parser chosen in-f/--input-formatmatches the data.
Learning Path
- Events - Practice accessing and mutating
e.fieldvalues on JSON or logfmt samples. - Parsing - Try multiple formats (
-f json,-f combined,-f 'cols:...') and experiment with--extract-prefix. - Basic Scripts - Layer
--filter,--exec, and--keysfor simple transformations. - Metrics & Stats - Introduce
track_count,track_avg,--metrics, and--stats. - Pipelines - Chain multiple
--filter/--execstages, add--beginconfiguration, and export results. - Output Control - Switch between
-Fmodes, apply-k/-K, and format timestamps. - Windows - Explore
--window,window_values, andwindow_numbersfor sequence detection. - Multi-stage Workloads - Combine
--parallel, config aliases, and--endsummarization for production-style jobs.
Each milestone builds on the previous one; you can be productive early, then layer in advanced concepts as needed.
[!TIP] See examples/README.md for 37 working examples covering all formats and complexity levels—from basic filtering to advanced pipelines.
Reference
Documentation Shortcuts
When to Reach for Kelora
- Use Kelora when you need programmable filtering, enrichment, aggregation, or custom metrics directly in the terminal.
- Pair with other tools: pipe results into
jq,ripgrep, orlnav—Kelora focuses on transformation, not visualization. - Prefer other tools when you need interactive browsing (
lnav), raw text search (ripgrep), heavy-duty JSON querying (jq), dashboards (Grafana), or centralized log shipping (Fluentd).
See also: angle-grinder, pq, Miller.
License
MIT - see the license file for full details.