Skip to content

feat(react-native): add setAttributes and custom span/log processors - #862

Closed
abelonogov-ld wants to merge 3 commits into
mainfrom
andrey/global-attributes-rn
Closed

abelonogov-ld wants to merge 3 commits into
mainfrom
andrey/global-attributes-rn

Conversation

@abelonogov-ld

@abelonogov-ld abelonogov-ld commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Adds global attributes and custom span/log processors to @launchdarkly/observability-react-native. This addresses the customer request for app-wide attributes (e.g. UTM parameters) on all telemetry, and is one of a set of matching PRs across RN, Android, iOS, Flutter, MAUI, Java and Python that share the same semantics (see #858, #859, #860, #861, launchdarkly/swift-launchdarkly-observability#290).

Global attributes

  • LDObserve.setAttributes(attributes) / LDObserve.removeAttributes(keys) maintain one process-wide, in-memory attribute map (immutable snapshot rebuilt only on change).
  • Applied to every span (manual, fetch/XHR, error, track), log record and metric recorded after the call. Spans take the values current when they start (onStart).
  • Precedence: per-call attributes > globals > resource. Globals only fill missing keys.
  • highlight.session_id and session.id are ignored (logged in debug mode), as are invalid attribute values.
  • Calls before init write straight to the store (not the pre-init call buffer), so telemetry recorded during async init, including automatic fetch spans, already carries them. Nothing is persisted; values survive session changes.

Custom processors (init-time options)

  • spanProcessors?: SpanProcessor[] and logProcessors?: LogRecordProcessor[] on ReactNativeOptions.
  • Order per provider: global-attributes processor → user processors (in order) → SDK batch processor, so user processors see globals and their changes are exported.
  • Every user processor call (including onEnding, forceFlush, shutdown) is wrapped in try/catch, so a failing processor never breaks the SDK or the export.
  • SpanProcessor, ReadableSpan, SdkSpan, LogRecordProcessor, SdkLogRecord and ReadableLogRecord are re-exported so customers don't need matching OTel versions.

README documents both APIs.

How did you test this change?

  • Unit tests: store (merge, remove, reserved keys, invalid values, snapshot immutability), global-attribute processors (per-call wins, values at span start), safe wrappers (throwing/rejecting processors still export), metric merging for all metric types.
  • Integration test through LDObserve and a real ObservabilityClient with stubbed exporters: attributes set before init apply immediately and reach telemetry recorded before init; reserved keys ignored; manual, fetch and error spans get globals with per-call values winning; logs get globals; remove takes effect; user processors see globals and their changes are exported even when another processor throws.
  • tsc --noEmit, vitest run (147 tests), prettier check and vite build pass. Removing the global-attributes span processor makes 5 span tests fail.

Are there any deployment considerations?

Additive; no behavior change unless the new APIs or options are used. The global-attributes processor adds a cheap per-span / per-log loop over the snapshot. Global attributes are added to metric data points, so they increase metric cardinality.


Note

Overview
Adds process-wide global attributes and optional custom OpenTelemetry processors to @launchdarkly/observability-react-native.

LDObserve.setAttributes / removeAttributes maintain an in-memory map merged onto spans (at start), logs, errors, auto-instrumented fetch spans, and metrics. Per-call attributes win over globals; reserved session keys (highlight.session_id, session.id) are ignored. Calls before async init update the store immediately (not the pre-init call buffer) so early telemetry still picks them up.

Init options spanProcessors and logProcessors run after the built-in global-attribute processors and before export, wrapped so throws cannot block export. Related OTel processor/span/log types are re-exported from the package. README and the legacy example app document and demo UTM-style globals.

Reviewed by Cursor Bugbot for commit 135c413. Bugbot is set up for automated code reviews on this repo. Configure here.

abelonogov-ld and others added 2 commits October 28, 2026 16:33
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@abelonogov-ld
abelonogov-ld requested a review from a team as a code owner October 28, 2026 23:34
return release
})

const TEST_FETCH_URL = 'http://example.test/api'
const localOptions = {
projectId: 'test-project-id',
serviceName: 'test-service',
backendUrl: 'http://127.0.0.1:1',
projectId: 'test-project-id',
serviceName: 'test-service',
backendUrl: 'http://127.0.0.1:1',
otlpEndpoint: 'http://127.0.0.1:1',
Co-authored-by: Cursor <cursoragent@cursor.com>
@abelonogov-ld

Copy link
Copy Markdown
Contributor Author

Closing in favor of #856, which already implements setAttributes/removeAttributes for React Native. The example-legacy repro from this PR has been added there.

@abelonogov-ld
abelonogov-ld deleted the andrey/global-attributes-rn branch October 29, 2026 01:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants