BatchSpanProcessor
BatchSpanProcessor is the built-in SpanProcessor. It receives span lifecycle events from ProcessingTracer, assembles each event into a complete TraceEvent, applies Redaction, and ships batches to a TraceExporter.
It is wired automatically when you use ProcessingTracer’s convenience init. Use the processor: init on ProcessingTracer only when you need a custom batching strategy — see Custom Tracing.
public actor BatchSpanProcessor: SpanProcessor { public init( exporter: any TraceExporter, batchSize: Int = 64, redaction: any Redactor = Redaction.default )}exporter— theTraceExporterthat receives finished batches.batchSize— number of completed spans that triggers an automatic export. Must be>= 1.redaction— applied to everyTraceEventbefore export. Defaults toRedaction.default(hash user ids, clip strings at 4096 chars).
Key behaviours
Section titled “Key behaviours”- Single ordered consumer — all messages (
onOpen,onUsage,onSetInput,onSetMetadata,onEnd,flush,shutdown) flow through oneAsyncStream. A span’sonOpen→ … →onEndsequence can never reorder, so token attribution and parent linkage are always correct. - No timer — a batch ships when
pending.count >= batchSizeor on an explicitflush(). There is no scheduled-delay flush. Size yourbatchSizeto match your typical request volume. - Unbounded buffer — the pending queue has no max size. Silent drops would be worse than memory pressure for small chat traces. If you need backpressure, implement a custom
SpanProcessor. - Error handling — failures on the automatic batch path are swallowed (a tracer must never crash the app).
flush()surfaces them — call it when you can handle the error. - Second
endis a no-op —BatchSpanProcessorignores a secondonEndfor the same span id, so each span exports exactly once.
Lifecycle
Section titled “Lifecycle”// Manual lifecycle in an app delegate / scene delegate:try await tracer.flush() // on sceneWillResignActive — surfaces errorsawait tracer.shutdown() // on applicationWillTerminate — final drain + releaseshutdown() is the only call that stops the consumer task. Until it is called, the BatchSpanProcessor (and by extension ProcessingTracer) retains the consumer and the exporter.
Redaction
Section titled “Redaction”BatchSpanProcessor applies the Redactor to every finalized TraceEvent before appending it to the pending batch. The built-in Redaction hashes user ids and clips strings:
public struct Redaction: Redactor { public var hashUserIds: Bool // default: true public var maxStringLength: Int? // default: 4096; nil disables clipping
public init(hashUserIds: Bool = true, maxStringLength: Int? = 4096) public static let `default` = Redaction()}hashUserIds: true— replaces raw user ids with a 16-hex-char SHA-256 prefix. Stable across sessions so you can still correlate a user’s traces without shipping the raw id.maxStringLength— clips strings ininput,output,error, andmetadata.id,traceId,parentId,model, and token counts pass through untouched.
Pass a custom Redactor to the BatchSpanProcessor (or the ProcessingTracer convenience init) to implement a different privacy policy. See Custom Tracing for a full conformance example.
Related pages
Section titled “Related pages”- Tracing Overview — the full pipeline and all protocols.
- ProcessingTracer — the
Tracerthat feedsBatchSpanProcessor. - OTLPExporter — the default
TraceExporterwired behindBatchSpanProcessor. - Custom Tracing — implement
SpanProcessordirectly for custom batching, fan-out, or sampling.