Export and leaving
Export is on for every plan, including when the organization is capped or a
payment has failed, and it costs nothing. It needs a key with the read or
full scope; an ingest key cannot read.
Export a project
An export streams for as long as the project is large, and it can fail after
it has started: the status line is long gone by then, so the engine reports
the outcome in HTTP trailers at the end of the stream. Treat the file as
usable only when the stream ended with X-Traza-Export-Complete: true. This
script does that check and exits non-zero on every other outcome:
#!/usr/bin/env bash
# export.sh: export a project into spans.ndjson; exit 0 only for the whole dataset.
set -u -o pipefail
if ! curl --fail --show-error --silent \
-H 'TE: trailers' \
-H "Authorization: Bearer $TRAZA_API_KEY" \
-D headers.txt -o spans.ndjson \
'https://api.trazadb.com/v1/export'; then
echo 'export: the transfer failed (curl says why above); spans.ndjson is not the whole dataset' >&2
exit 1
fi
if ! grep -qiE '^x-traza-export-complete:[[:space:]]*true[[:space:]]*$' headers.txt; then
echo 'export: no "X-Traza-Export-Complete: true" trailer; spans.ndjson is not the whole dataset' >&2
exit 1
fi
count=$(grep -iE '^x-traza-export-count:' headers.txt | tr -dc '0-9')
lines=$(wc -l < spans.ndjson | tr -dc '0-9')
if [ "$count" != "$lines" ]; then
echo "export: the trailer counts ${count:-no} spans but spans.ndjson holds $lines lines" >&2
exit 1
fi
echo "export: complete, $lines spans in spans.ndjson"
What each part guards against:
TE: trailersasks for the trailers. Over HTTP/1.1 the gateway delivers them only to a client that sent this header (HTTP/2 clients always get them). Without it a complete export arrives with no trailer to check, and an incomplete one is cut off mid-stream.--fail --show-errormakes curl exit non-zero on an error status, such as401for a wrong key or403for an ingest-only key, and print why;--silentalone would hide it. A stream cut after it started also exits non-zero.X-Traza-Export-Complete: trueis the only proof of completeness. Afalsemeans the stream failed after it started; a missing trailer means the outcome is unknown. Either way, export again.X-Traza-Export-Countis the number of spans the engine sent, checked against the lines in the file.
The body is one span per line in the engine’s native JSON. Export takes the
same filters as GET /v1/spans
(service, time window, attributes, session), added as query parameters, and is
unbounded unless you pass limit. It is a snapshot: spans that arrive while
it runs are not in it.
What an export does not contain
- Large attribute values. The engine moves a string attribute over
256 KiB out of its span at ingest and leaves a
{"$payload": "sha256/…", "bytes": …, "preview": "…"}reference in its place. The export carries the reference, not the bytes; fetch them withGET /v1/payloads/sha256/{hex}and put the text back in place of the reference before you import. - Annotations. They are a separate surface: read them with
GET /v1/annotations. - Run fuse policies. They are configuration rather than data: list them
with
GET /v1/fuses/policiesand create them again.
Into your own traza-server
Import only after export.sh reported the export complete. The exported lines
are what the native ingest route reads; this script posts them in batches of
1,000 and stops at the first batch the server refuses:
#!/usr/bin/env bash
# import.sh: post spans.ndjson to a self-hosted traza-server in batches.
set -eu -o pipefail
shopt -s nullglob
batches=$(mktemp -d)
trap 'rm -rf "$batches"' EXIT
split -l 1000 spans.ndjson "$batches/batch-"
for f in "$batches"/batch-*; do
jq -s . "$f" | curl --fail --show-error --silent \
-H "Authorization: Bearer $TRAZA_TOKEN" -H 'Content-Type: application/json' \
--data-binary @- 'http://localhost:8080/v1/spans' > /dev/null
done
echo 'import: every batch accepted'
Running it again after a failure is safe: a span is keyed by its tenant, trace id and span id, so posting it again replaces it rather than adding a copy.
Each line carries its $tenant, so the spans land under the same tenant name
on your server; strip it with jq -s 'map(del(."$tenant"))' in place of
jq -s . to use the default tenant instead.
Deleting a project
Deleting a project in the console revokes its keys, pauses its ingest, erases its tenant on its cell and keeps the erasure’s id, so the receipt can be checked. Export first: deletion cannot be undone.