Quick Start
FastForward is a research project exploring how to build a fast log forwarder with Rust. This guide gets you from zero to a working pipeline in about 15 minutes.
Install
Section titled “Install”Requires the Rust stable toolchain (1.89+).
git clone https://github.com/strawgate/fastforward.gitcd fastforwardcargo build --release -p ffwdsudo cp target/release/ff /usr/local/bin/docker run --rm \ -v /var/log:/var/log:ro \ -v $(pwd)/config.yaml:/etc/ffwd/config.yaml:ro \ ghcr.io/strawgate/fastforward:latest run --config /etc/ffwd/config.yamlImages are published to ghcr.io/strawgate/fastforward for linux/amd64 and linux/arm64. See Docker deployment for compose files and volume configuration.
kubectl apply -f deploy/daemonset.ymlSee the Kubernetes deployment guide for resource sizing and collector integration.
Verify it works:
ff --versionff --helpOr start from a generated config:
ff init # creates ffwd.yaml with a basic file → stdout pipelineff wizard # interactive: choose a use-case preset or build your ownStage 1: See log output
Section titled “Stage 1: See log output”Generate synthetic JSON log lines and print them to your terminal.
ff generate-json 10000 logs.jsonThis creates 10,000 JSON log lines with fields like level, message, status, duration_ms, and service.
pipelines: default: inputs: - type: file path: logs.json format: json outputs: - type: stdout format: consoleff run --config config.yamlYou’ll see colored output for every log line:
ff v0.x.x (abc1234 2026-04-01, release)
ready: defaultff running (1 pipeline(s))
10:30:00.000Z INFO request handled GET /api/v1/users/10000 duration_ms=1 request_id=... service=myapp status=20010:30:00.000Z ERROR request handled GET /health/10021 duration_ms=40 request_id=... service=myapp status=503...FastForward parsed every JSON line, detected field types automatically, built Arrow RecordBatches, and printed them in a human-readable format. All 10,000 lines stream through in under a second.
Send piped data
Section titled “Send piped data”For one-off command-line use, keep a destination-only config and pipe data into ff.
ff send reads stdin, drains the configured output or outputs, and exits.
output: type: stdout format: consolecat logs.json | ff send --config destination.yaml --format json --service checkoutBare ff also enters send mode when stdin is piped, using the normal config
search order. Set FFWD_CONFIG when you want an explicit destination config:
cat logs.json | FFWD_CONFIG=destination.yaml ff --format json --service checkoutStage 2: Filter with SQL
Section titled “Stage 2: Filter with SQL”Add a SQL transform to keep only what matters. Every batch of parsed records becomes a DataFusion SQL table named logs.
ff generate-json 10000 logs.json # regenerate — FastForward tracks file positionspipelines: default: inputs: - type: file path: logs.json format: json transform: | SELECT level, message, status, duration_ms FROM logs WHERE level = 'ERROR' AND duration_ms > 50 outputs: - type: stdout format: consoleff run --config config.yamlNow you see only errors with slow durations. Only the columns from the SELECT appear — everything else was filtered before reaching the output. In production, this means you only ship the logs you care about.
Full SQL works: JOIN, GROUP BY, HAVING, subqueries, window functions. Built-in UDFs: regexp_extract(), grok(), json(), json_int(), json_float(), geo_lookup(). See SQL Transforms for the complete reference.
Stage 3: Ship to a collector
Section titled “Stage 3: Ship to a collector”FastForward sends OTLP protobuf to an OpenTelemetry Collector, Grafana Alloy, or any OTLP-compatible backend.
Test locally with FastForward’s built-in devour receiver:
ff devour --mode otlp --listen 127.0.0.1:4318 &You can also blast generated data into a destination sink to test throughput:
ff blast --destination otlp --endpoint http://127.0.0.1:4318/v1/logspipelines: default: inputs: - type: file path: logs.json format: json transform: | SELECT level, message, status, duration_ms FROM logs WHERE level IN ('ERROR', 'WARN') outputs: - type: otlp endpoint: http://127.0.0.1:4318/v1/logs compression: zstdff generate-json 10000 logs.jsonff run --config config.yamlTo ship to a real collector:
output: type: otlp endpoint: https://otel-collector:4318/v1/logs compression: zstdWorks out of the box with OpenTelemetry Collector, Grafana Alloy, or any OTLP-compatible backend.
Stage 4: Production config
Section titled “Stage 4: Production config”This config tails Kubernetes pod logs in CRI format, filters by severity, and ships to OTLP with monitoring enabled.
pipelines: default: inputs: - type: file path: /var/log/pods/**/*.log format: cri transform: | SELECT * FROM logs WHERE level IN ('ERROR', 'WARN') outputs: - type: otlp endpoint: https://otel-collector:4318/v1/logs compression: zstd
server: diagnostics: 0.0.0.0:9090 log_level: infoWhat’s different from the earlier stages:
format: cri— Kubernetes container runtime format. FastForward strips the CRI prefix and reassembles multi-line logs via thePpartial flag.path: /var/log/pods/**/*.log— Recursive glob. FastForward discovers new files automatically and handles rotation.server.diagnostics— Exposes health checks, metrics, and pipeline status.
Validate before deploying
Section titled “Validate before deploying”ff validate --config pipeline.yamlff dry-run --config pipeline.yamlvalidate catches YAML errors. dry-run goes further and compiles the SQL against the Arrow schema, catching column name typos and type mismatches.
Monitor the pipeline
Section titled “Monitor the pipeline”curl -s http://localhost:9090/live # liveness probecurl -s http://localhost:9090/ready # readiness probecurl -s http://localhost:9090/admin/v1/status | jq . # full statusSee Monitoring & Diagnostics for the complete endpoint reference and alerting guidance.
Multiple pipelines
Section titled “Multiple pipelines”pipelines: errors: inputs: - type: file path: /var/log/pods/**/*.log format: cri transform: | SELECT * FROM logs WHERE level IN ('ERROR', 'WARN') outputs: - type: otlp endpoint: https://otel-collector:4318/v1/logs compression: zstd
all-logs: inputs: - type: file path: /var/log/pods/**/*.log format: cri outputs: - type: stdout format: json
server: diagnostics: 0.0.0.0:9090What’s next
Section titled “What’s next”| Topic | Where to go |
|---|---|
| Understand the pipeline internals | Pipeline Explorer (interactive) |
| Learn the full SQL transform syntax | SQL Transforms |
| See all YAML config options | YAML Reference |
| Deploy to Kubernetes | Kubernetes DaemonSet |
| Debug a problem | Troubleshooting |