@sophonz/span-processors
v0.0.6
Published
Readme
@sophonz/span-processors
Span and log record processors for the Sophonz browser agents.
Two things the OpenTelemetry defaults leave to you in a browser: getting a batch flushed before the page goes away, and stamping every span with attributes that are global to the session rather than to one call site. These processors do both.
Part of the Sophonz OpenTelemetry suite.
Install
bun add @sophonz/span-processors
# or
pnpm add @sophonz/span-processors
# or
npm install @sophonz/span-processors@sophonz/browser-sdk and @sophonz/otel-web already install these. Reach for
the package directly only when you assemble the SDK yourself.
Usage
import {
SophonzBatchSpanProcessor,
SophonzSpanAttributesProcessor,
SophonzLogAttributesProcessor,
} from '@sophonz/span-processors';
const globalAttributes = { 'user.id': 'u-123' };
provider.addSpanProcessor(new SophonzSpanAttributesProcessor(globalAttributes));
provider.addSpanProcessor(new SophonzBatchSpanProcessor(exporter));API
SophonzBatchSpanProcessor
Extends OpenTelemetry's BatchSpanProcessor.
new SophonzBatchSpanProcessor(exporter, config?, meter?)exporter(SpanExporter) — where batches go.config(BatchSpanProcessorBrowserConfig, optional) — the upstream batch options.meter(Meter, optional) — when given, every span also records its duration in milliseconds to adurationInMsgauge, tagged with the span's attributes plusspan.idandtrace.id.
It flushes on visibilitychange (when the document becomes hidden) and on
pagehide, which is the Safari fallback since visibility change is unreliable
there. Upstream does the same but lets a rejected forceFlush escape as an
unhandled rejection; this one routes it to globalErrorHandler. Set
disableAutoFlushOnDocumentHide: true in the config to turn the listeners off.
SophonzSpanAttributesProcessor
Implements SpanProcessor. On every span start it sets location.href, applies
the current global attributes, and adds the resource attributes from
@sophonz/meta.
new SophonzSpanAttributesProcessor(globalAttributes)setGlobalAttributes(attributes?)— merges into the current set. Called with no argument, it clears them.getGlobalAttributes()— returns the live object.
Attributes are applied at onStart, so a change takes effect for spans started
afterwards and leaves spans already in flight alone.
SophonzLogAttributesProcessor
Implements LogRecordProcessor with the same setGlobalAttributes /
getGlobalAttributes pair, so logs carry the same global attributes as spans.
SophonzSpanAttributeScrubbingProcessor
Implements SpanProcessor. Applies the customer's attributeScrubbers rules —
per-key redaction from @sophonz/redaction — to every span
before it is exported.
new SophonzSpanAttributeScrubbingProcessor(scrubbers?)Constructed with no rules (or an empty array) it is a no-op: spans are not
iterated, not copied and not touched. Rules are documented in the
@sophonz/redaction README; the SDK exposes them as the attributeScrubbers
option.
The work happens in onEnd, not onStart. Almost every attribute an
instrumentation sets — http.response.status_code, exception.message, the
console instrumentation's object spread — is written during the span's life, so
a scrubber running at start would see an essentially empty bag. onEnd is the
last synchronous point at which every attribute exists and the span has not yet
been queued for export.
It mutates span.attributes directly, which is what the SDK actually
permits here. onEnd receives a ReadableSpan, whose attributes is a
readonly property holding an ordinary mutable object — the reference cannot
be reassigned, the contents can. span.setAttribute() is not an alternative
even where the type allows it: SpanImpl.setAttribute returns early once the
span has ended, and cannot express deletion. One documented cost: SpanImpl
keeps a private _attributesCount that cannot be updated from outside, so
removing an attribute leaves it one too high. It is only read when adding an
attribute against attributeCountLimit, and the span has already ended.
Span event attributes are scrubbed too, which is where exception.message
and exception.stacktrace live.
Place it after the attribute-writing processors and before any exporting
processor. MultiSpanProcessor calls onEnd in array order, so array position
is the ordering.
A customer's scrubber never throws into the page; failures are reported through
diag.warn (visible only under debug: true, matching the rest of this SDK)
and the attribute fails closed. See the @sophonz/redaction README for the
exact semantics.
Dependencies
@opentelemetry/api,@opentelemetry/core,@opentelemetry/sdk-trace-base,@opentelemetry/sdk-logs@sophonz/meta— resource attributes applied on span start@sophonz/redaction— the compiled attribute scrubber@sophonz/semantic-conventions
License
See LICENSE in this package.
Part of sophonz-js.
