Skip to main content

Telemetry

The SDK exposes vendor-neutral helpers for OpenTelemetry traces, metrics, and logs. Import them from @ovok/native/helpers or the package root @ovok/native. The SDK does not configure an exporter or choose a telemetry backend; the host app owns provider registration, export, retention, and access policy.

import {
configureOvokTelemetry,
withOvokSpan,
recordOvokMetric,
} from "@ovok/native/helpers";

Configure providers​

If the app has registered OpenTelemetry providers globally, the SDK uses those providers when the optional API packages are installed. Otherwise, pass the providers explicitly:

configureOvokTelemetry({
tracerProvider: appTracerProvider,
meterProvider: appMeterProvider,
loggerProvider: appLoggerProvider,
});

Each provider is optional. @opentelemetry/api and @opentelemetry/api-logs are optional peer dependencies; an app that does not use OpenTelemetry can omit them. With no provider available, telemetry helpers are no-ops and SDK operations continue. Configure providers during startup before SDK features run.

OvokTelemetryOptions accepts three provider adapters:

OptionProvider methodUsed for
tracerProvidergetTracer(name, version?) and optional getActiveSpan()Spans and span events
meterProvidergetMeter(name, version?)Counters and histograms
loggerProvidergetLogger(name, version?)OpenTelemetry log records

The provider interfaces accept the SDK's minimal OpenTelemetry-compatible surface; the app still chooses the concrete SDK, processors, exporters, and destinations.

Public helpers​

ExportSignatureBehavior
configureOvokTelemetry(options?: OvokTelemetryOptions) => voidSet explicit providers; an empty options object clears explicit providers.
sanitizeOvokTelemetryAttributes(attributes?: Record<string, unknown>) => OvokTelemetryAttributesKeep allowlisted keys with string, number, or boolean values.
startOvokSpan(name: string, attributes?: Record<string, unknown>) => OvokSpan | undefinedStart a span when a tracer exists; end it with span.end() in finally.
withOvokSpan<T>(name, attributes, operation) => Promise<T>Run an operation in a span when available, preserving its return value or error.
recordOvokMetric(name: string, value: number, attributes?: Record<string, unknown>) => voidAdd a value to a named counter.
recordOvokDuration(name: string, durationMs: number, attributes?: Record<string, unknown>) => voidRecord milliseconds in a named histogram.
addOvokSpanEvent(name: string, attributes?: Record<string, unknown>, span?: OvokSpan) => voidAdd an event to the supplied span or current active span.
emitOvokLog(severityText: string, body: string, attributes?: Record<string, unknown>) => voidEmit an OpenTelemetry log record when a logger provider exists.

The public telemetry types are OvokTelemetryAttribute (string | number | boolean), OvokTelemetryAttributes (a string-keyed record of those values), OvokSpan, OvokTracerProvider, OvokMeterProvider, OvokLoggerProvider, and OvokTelemetryOptions. OvokSpan exposes optional methods for setting attributes, adding events, recording exceptions, and setting status; end() is required.

type OvokTelemetryAttribute = string | number | boolean;
type OvokTelemetryAttributes = Record<string, OvokTelemetryAttribute>;

interface OvokSpan {
setAttribute?: (name: string, value: OvokTelemetryAttribute) => void;
setAttributes?: (attributes: OvokTelemetryAttributes) => void;
addEvent?: (name: string, attributes?: OvokTelemetryAttributes) => void;
recordException?: (error: Error | string) => void;
setStatus?: (status: { code: number; message?: string }) => void;
end: () => void;
}

interface OvokTelemetryOptions {
tracerProvider?: OvokTracerProvider;
meterProvider?: OvokMeterProvider;
loggerProvider?: OvokLoggerProvider;
}

When a span is available, withOvokSpan sets success or error status, records exceptions, ends the span, and adds one to ovok.errors when the operation throws. It rethrows the original error. If no tracer is available, it still invokes and awaits the operation. Provider failures do not change SDK control flow.

For direct span management, always end the returned span:

const span = startOvokSpan("app.measurement.persist", {
provider: "bluetooth",
measurementTypeKey: "body-weight",
});

try {
await persistMeasurement(measurement);
} finally {
span?.end();
}

Prefer withOvokSpan for app operations because it handles lifecycle and errors.

Attribute allowlist​

The SDK filters attributes passed through its span, metric, duration, and span-event helpers. It keeps only these keys and only primitive string, number, or boolean values:

deviceId, deviceName, model, manufacturer, measurementTypeKey, platform, status, reason, errorCode, retryCount, attempt, queueDepth, durationMs, success, exhausted, willRetry, requestedMtu, provider, and sampleCount.

Unknown keys and object or array values are dropped. This is an operational allowlist, not a guarantee that every permitted value is safe for every app. Review device identifiers and other context under your data policy.

emitOvokLog does not call this sanitizer. The logger helpers also pass log messages and extra values as supplied. Do not put patient identifiers, credentials, measurement values, or raw device payloads in log records. See Logging for the logger callback and slog behavior.

Built-in SDK signals​

The SDK currently emits these signals through the helpers above:

SignalInstrumentMeaning
Spanbluetooth.connectOne Bluetooth connection attempt.
Spanhealth.importOne HealthKit or Health Connect import run.
Eventbluetooth.scan.startedContinuous Bluetooth scanning started.
Eventdevice.status_changedA device status callback ran.
Eventreading.receivedA measurement reading was received.
Eventpairing.failedThe device connection reports that pairing requires a code.
Counterovok.devices.foundA supported device was found.
Counterovok.readings.receivedA reading was delivered by a device.
Counterovok.pairing.failuresA pairing-required event occurred.
Counterovok.queue.deliveredA queued result was delivered.
Counterovok.queue.retriesA queued delivery attempt failed and will be retried.
Counterovok.queue.exhaustedA queued result reached the retry limit.
Counterovok.health.samples.importedCount of newly created observations in a health-import batch.
Counterovok.errorsA traced operation failed, or the logger received error/fatal.
Counterovok.queue.depthThe current queue length is added as a counter value when the queue is written; this is not a gauge.
Histogramovok.device.connection.durationBluetooth connection duration in milliseconds.
Histogramovok.measurement.save.durationHealth-import batch save duration in milliseconds.

Metric attributes are limited by the sanitizer. Signal availability also depends on the feature running in the foreground or background; the SDK does not guarantee that an OS-scheduled task will run long enough to emit telemetry.

See Logs and telemetry for setup and integration guidance, or return to the Helpers reference.