Transformers Come to Logpush: Filter, Redact, and Reshape Logs with SQL Before Export
Hi everyone, it's Shii-chan!
Cloudflare BlogYou can now shape your logs with SQL before they're delivered, and the architecture story is really fun!
What was announced?
The Cloudflare Blog introduced Transformers for Logpush. They let you filter, redact, and reshape logs with SQL before export. Logpush applies the query to each batch, so every destination gets data in the format it needs.
- Records that don't match the
WHEREclause are dropped - The
SELECToutput becomes the exported record - Output is NDJSON
The story so far
To transform logs, you needed a separate processing service in the middle. Transformers remove the need for that, and filtering early can reduce storage and ingestion costs!
What changes
Here's what you can write in SQL (simplified from the post's examples).
SELECT ClientIP, EdgeResponseStatus, RayID
FROM http_requests
WHERE EdgeResponseStatus >= 500
AND ClientRequestPath NOT LIKE '/healthz%'
This keeps only server errors and drops health-check traffic.
You can also redact part of an IP and add a provider field.
SELECT
regexp_replace(ClientIP, '\.\d+\.\d+$', '.XXX.XXX') AS redacted_ip,
'cloudflare' AS provider,
EdgeResponseStatus AS status
FROM http_requests
The post also has a longer example that converts timestamps to Unix epoch, uppercases the HTTP method, nests host and path into a request object, and adds an is_server_error boolean.
Dive Deep
Usage and limits
- Create, preview, and manage Transformers in Transformer Studio in the dashboard, or through the API
- Each Transformer targets one Logpush dataset, selected by the table name in
FROM - Attach a saved Transformer to a compatible NDJSON Logpush job using the same dataset
- Each update creates a new version
- Records are reshaped, but serialization formats are not converted
- If a transform fails, untransformed data is not sent; the delivery offset doesn't advance and it retries
- Retries back off progressively, errors show on the job, and jobs failing for an extended period are disabled automatically
The post gives no numeric limits on query size or row counts, no per-plan quotas, and no pricing; see the Logpush pricing docs. Transformers are generally available on Free, Pro, Business, and Enterprise plans.
Under the hood
This is my favorite part!
- The delivery service is Bufstream, running across hundreds of Kubernetes pods and reading from Buftee, Cloudflare's internal log broker
- An early prototype ran WebAssembly Transformers in Workers, but network calls could add timeouts, retries, and latency, so execution moved in-process
- The engine is Apache DataFusion, a Rust SQL query engine built on Apache Arrow
- Bufstream decompresses each batch, parses records, builds typed Arrow batches, and passes them to Rust over Arrow IPC through a C ABI called via cgo
- For memory ownership, Go owns the input buffer only during the call, and Rust owns the output buffer; Go copies it and then releases the Rust allocation
- Queries are stored in R2 and cached; each query is compiled into a logical plan once per time slice and reused on every batch
- Results become NDJSON, are gzip-compressed, and uploaded, with upload concurrency adjusted to destination limits
In one benchmark, a 5,000-row batch took about 3 ms from a single Go goroutine, roughly 1.6 million rows per second.
For monitoring, the Transformer Health view in the Logpush Health tab shows successful and failed transforms, data volume before and after, and transform duration.
Wrap-up
- Transformers filter, redact, and reshape logs with SQL before export
- Create them in Transformer Studio or the API and attach them to NDJSON jobs on the same dataset
- On failure they send nothing untransformed and retry (fail closed)
- DataFusion and Arrow run in-process for speed
- Generally available on all plans
If your logs carry sensitive fields and every destination wants a different shape, this one's for you!