Aller au contenu

Couches · Référence

OpenTelemetry

Server and browser OpenTelemetry for errors, traces, metrics, logs, and named events.

Dernière mise à jour le 20 octobre 2026

Setup

Server/browser telemetry infrastructure for errors, traces, metrics, logs and named events. Events adds consent UI, page tracking and optional SQL audit history.

shell
bunx shadcn@latest add @krak-stack/service-opentelemetry

Server

env
OTEL_SERVICE_NAME=my-app-api
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318
OTEL_TRACES_EXPORTER=otlp
OTEL_METRICS_EXPORTER=otlp
OTEL_LOGS_EXPORTER=otlp
ts
import { Layer } from 'effect';
import { Otlp } from '@/services/opentelemetry';
import { HttpApiOtlp } from '@/services/opentelemetry/api';

const server = HttpApiOtlp.layer.pipe(Layer.provideMerge(Otlp.layer));

Otlp.layer owns server exporters and works without HTTP in workers/CLIs. HttpApiOtlp.layer adds browser ingestion endpoints; it does not construct its own Otlp foundation. Provide Events.ingestionLayer for application-event enrichment/persistence as shown in Events setup.

Browser

Mount in your browser runtime, not during SSR:

ts
import { BrowserOtlp } from '@/services/opentelemetry/browser';

const telemetry = BrowserOtlp.layer({ serviceName: 'my-app-web' });
Browser optionDefault / behavior
serviceNameRequired
traces{}; automatic browser errors included; false disables both
events{}; false disables all event export
logs, metricsfalse; enable independently with {}
baseUrl/api/otel
attributes, serviceVersion, headersOptional resource/transport metadata

BrowserOtlp creates no automatic page tracking or visitor/session identity. Automatic errors use generic messages and sanitized source locations. Do not attach sensitive identity/resource annotations to essential diagnostics.

tsx
import { Layer } from 'effect';
import { BrowserEvents } from '@/services/events/browser';
import { TrackingNotice } from '@/services/events/client/tracking-notice';
import { BrowserWebVitals } from '@/services/opentelemetry/web-vitals';

const browser = Layer.mergeAll(
  BrowserEvents.layer(),
  BrowserWebVitals.layer(),
).pipe(Layer.provideMerge(telemetry));

// Mount once in a persistent footer. English/French defaults are included.
<TrackingNotice privacyHref="/privacy-policy" />

BrowserEvents and Web Vitals require shared acceptance by default and honor DNT/GPC. Web Vitals requires consent before navigation begins and does not resume within a document after withdrawal. Essential automatic error reporting is independent of that choice. Generic events, custom spans, metrics/logs and third-party scripts are application-owned; do not use them to bypass preferences. See tracking consent for the policy and overrides.

Install

shell
bunx shadcn@latest add @krak-stack/service-opentelemetry

Named events

Run these Effects inside the appropriate runtime:

ts
yield* Otlp.event('order.completed', { total: 42 });
yield* BrowserOtlp.event('diagnostic.ready', { component: 'editor' });

Events are INFO OTLP logs; they do not create spans or SQL history. Invalid inputs fail schema validation.

Event optionMeaning
userId, anonymousId, sessionIdExplicit identity attributes; never proof of authentication
messageIdCorrelation ID, not guaranteed collector deduplication
contextFlat attributes
timestampEffect DateTime.Utc occurrence time

Attribute precedence: context, properties, explicit identity options, scoped log annotations. Values support strings, finite numbers, booleans and homogeneous arrays. Keep sensitive data out of telemetry.

Web Vitals

The optional BrowserWebVitals layer reports document-level LCP, INP, CLS, FCP and TTFB through the shared BrowserOtlp exporter. No SQL is required; these are not SPA navigation timings.

If using Web Vitals without Events UI, you must still integrate the shared consent preference or explicitly assess a deployment override:

ts
const browser = BrowserWebVitals.layer({
  requireConsent: false,
  respectDoNotTrack: true,
}).pipe(Layer.provideMerge(telemetry));

This override is not a claim of legal exemption. With requireConsent: true, shared consent honors DNT/GPC even if respectDoNotTrack is false.

Events use name browser.web_vital, scope krakstack.events and these attributes:

Attribute suffix under browser.web_vital.*Meaning
name, idMetric name and instance ID
value, deltaCumulative value and change since the previous report
ratinggood / needs-improvement / poor
navigation_typeLibrary navigation type

Values are milliseconds except unitless CLS. Use the latest cumulative value or sum deduplicated deltas, not cumulative values. Unsupported metrics may be absent. Closing the layer releases its subscriber; library observers are document-scoped. No URLs, DOM attribution, performance entries or analytics identity are exported automatically.

Transport

ts
const telemetry = BrowserOtlp.layer({
  serviceName: 'my-app-web',
  events: { exportInterval: '5 seconds', maxBatchSize: 20 },
});

Default event batching is 30 seconds / 100 records. shutdownTimeout is also configurable. Page-hidden/shutdown flushing is best effort and uses browser keepalive. Consent is checked before batch serialization; already-started exports and their retries are not cancelled by withdrawal.

ConcernBehavior
Browser endpoints/api/otel/v1/{traces,metrics,logs}
Server overridesOTEL_EXPORTER_OTLP_{LOGS,METRICS,TRACES}_{ENDPOINT,HEADERS}
OTEL_SDK_DISABLED=trueDisables server export, not browser collection
Storage/credentialsCollector-owned; credentials remain server-side

Apply edge limits, collector retention and access controls. Package imports: @krak-stack/registry/opentelemetry, /opentelemetry/api, /opentelemetry/browser and /opentelemetry/web-vitals.

Dependencies
Packages and shadcn components required by this registry item.