Skip to content

WIP: Swap Workiva opentelemetry for Dartastic OpenTelemetry - #1

Draft
michaelbushe wants to merge 1 commit into
mainfrom
dartastic-otel-swap
Draft

WIP: Swap Workiva opentelemetry for Dartastic OpenTelemetry#1
michaelbushe wants to merge 1 commit into
mainfrom
dartastic-otel-swap

Conversation

@michaelbushe

Copy link
Copy Markdown
Member

Summary

Experimental swap of the OpenTelemetry implementation in packages/genkit from Workiva's opentelemetry: ^0.18.10 to Dartastic OpenTelemetry dartastic_opentelemetry: ^1.1.0-beta.4.

  • Web support (Flutter web, dart2js, dart2wasm) — Workiva's SDK is native-only.
  • OTLP/HTTP-JSON wire format built into every signal — Genkit no longer needs to hand-roll a JSON-encoded OTLP exporter for the dev UI.
  • Late-binding global proxies so final _tracer = OTel.tracerProvider().getTracer('genkit-dart') captured at module load stays correct after the host calls OTel.initialize (matches Java's GlobalOpenTelemetry.get() semantics).

What changed

packages/genkit/lib/src/o11y/instrumentation.dart

  • api.globalTracerProvider.getTracer(...)OTel.tracerProvider().getTracer(...) (late-binding proxy)
  • Attribute construction migrated from list-of-`api.Attribute.fromString` to a single OTel.attributesFromMap({...}) call
  • Span attribute setters use Dartastic's typed accessors (setStringAttribute<String>)
  • api.StatusCode.errorSpanStatusCode.Error
  • api.contextWithSpan(api.Context.current, span)Context.current.withSpan(span)
  • Genkit's Zone-keyed (#api.context) context propagation preserved as-is

packages/genkit/lib/src/o11y/telemetry/exporter_impl.dart

  • Hand-rolled CollectorHttpExporter removed — replaced with Dartastic's built-in OtlpHttpSpanExporter configured with OtlpHttpProtocol.httpJson (uses request.toProto3Json() on the generated protobuf classes, no hand-rolled marshaling)
  • setupExporter checks OTel.isInitialized:
    • Host already initialized OTel: dev UI exporter is added alongside existing processors via addSpanProcessor — both exporters fire on each span
    • Not initialized: bootstraps OTel itself with the dev UI exporter as the sole span processor

Tests

  • test/test_util.dart: TextExporter ported to Dartastic's async SpanExporter interface
  • test/core/action_test.dart: tracer-provider setup migrated to the proxy; span.attributes.get(k)span.attributes.getString(k) (Dartastic's typed accessors)
  • test/o11y/instrumentation_test.dart: setUp now await OTel.reset() between tests; asserts via spanContext.parentSpanId / spanContext.spanId
  • test/o11y/otlp_http_exporter_test.dart removed — it tested Genkit's now-deleted CollectorHttpExporter. The equivalent coverage for OtlpHttpSpanExporter lives upstream in Dartastic's own test suite.

Pubspec

  • packages/genkit/pubspec.yaml: dependency swap.

  • Workspace-root pubspec.yaml: dependency_overrides with git refs to in-flight Dartastic branches:

    Remove these overrides once both packages publish their pending betas to pub.dev.

Test plan

  • dart test in packages/genkit252/252 pass
  • Manual smoke test against the Genkit dev UI to confirm traces flow over OTLP/HTTP-JSON to $baseUrl/api/otlp/v1/traces
  • dart test -p chrome against a Flutter-web testapp to confirm web compatibility (the original motivation)
  • Resolve whether the dev UI accepts /v1/traces (spec-compliant OTLP path) or whether it needs to keep accepting the bare /api/otlp path — currently we send to /v1/traces so Dartastic doesn't append it twice

Status: WIP / draft

Filed against the fork's main for experimentation. Promote to genkit-ai/genkit-dart once the Dartastic API/SDK betas are published to pub.dev (the dependency_overrides block disappears at that point) and the dev UI compatibility item above is settled.

🤖 Generated with Claude Code

Experimental swap of the OpenTelemetry implementation in
packages/genkit from Workiva's `opentelemetry: ^0.18.10` to
Dartastic's `dartastic_opentelemetry: ^1.1.0-beta.4`. Motivation:
Dartastic ships web support (Flutter web, dart2js, dart2wasm),
OTLP/HTTP-JSON wire format on every signal natively, and
late-binding global proxies that make module-load tracer capture
correct across `OTel.initialize` — the three things Genkit Dart
needs to ship its dev UI integration on web.

## Code conversion

- `packages/genkit/lib/src/o11y/instrumentation.dart`:
  - `api.globalTracerProvider.getTracer('genkit-dart')` →
    `OTel.tracerProvider().getTracer('genkit-dart')`. The returned
    Tracer is a `LateBindingTracer` proxy whose identity is stable
    across `OTel.initialize`; module-load capture stays correct.
  - `api.Attribute.fromString(k, v)` list-building → single
    `OTel.attributesFromMap({...})` call.
  - `span.setAttribute(api.Attribute.fromString(k, v))` →
    `span.setStringAttribute<String>(k, v)`.
  - `span.setStatus(api.StatusCode.error, msg)` →
    `span.setStatus(SpanStatusCode.Error, msg)`.
  - `api.contextWithSpan(api.Context.current, span)` →
    `Context.current.withSpan(span)`.
  - Genkit's Zone-keyed (`#api.context`) context propagation
    preserved — the original mechanism is independent of the OTel
    package and just stores a `Context` value.

- `packages/genkit/lib/src/o11y/telemetry/exporter_impl.dart`:
  - Hand-rolled `CollectorHttpExporter` (JSON-encoded OTLP over
    HTTP) removed entirely. Replaced with Dartastic's built-in
    `OtlpHttpSpanExporter` configured with
    `OtlpHttpProtocol.httpJson`, which generates proto3-JSON OTLP
    via `request.toProto3Json()` on the generated protobuf classes
    — no hand-rolled marshaling in Dartastic.
  - `setupExporter` now checks `OTel.isInitialized`:
    - If host already initialized OTel (typical when Genkit runs
      inside an app that owns its observability stack), the dev UI
      exporter is added alongside existing processors via
      `OTel.tracerProvider().addSpanProcessor(processor)`. Both
      exporters fire on each span.
    - Otherwise, bootstraps OTel itself with the dev UI exporter as
      the sole span processor. Fire-and-forget initialize — by the
      time the next span is created, init has completed. The
      late-binding proxy held by `runInNewSpan`'s `_tracer`
      module-load capture survives this transition.
  - Endpoint passed as `$baseUrl/api/otlp/v1/traces` so Dartastic
    leaves the path alone (the SDK appends `/v1/traces` only when
    the configured endpoint doesn't already end with it).

## Tests

- `packages/genkit/test/test_util.dart`: `TextExporter` converted
  to Dartastic's `SpanExporter` interface (async export/forceFlush/
  shutdown returning Future<void>).
- `packages/genkit/test/core/action_test.dart`: replaced
  `sdk.TracerProviderBase` + `api.registerGlobalTracerProvider`
  with `OTel.tracerProvider().addSpanProcessor(processor)` on the
  late-binding proxy. `span.attributes.get(k)` →
  `span.attributes.getString(k)` (Dartastic's typed accessors).
- `packages/genkit/test/o11y/instrumentation_test.dart`: setUp
  now `await OTel.reset()` between tests for clean state; uses
  `SimpleSpanProcessor` directly and asserts
  `childSpan.spanContext.parentSpanId == parentSpan.spanContext.spanId`.
- `packages/genkit/test/o11y/otlp_http_exporter_test.dart` removed
  — it tested Genkit's now-deleted `CollectorHttpExporter`. The
  equivalent coverage for `OtlpHttpSpanExporter` lives upstream in
  Dartastic's own test suite.

## Pubspec

- `packages/genkit/pubspec.yaml`: `opentelemetry: ^0.18.10` →
  `dartastic_opentelemetry: ^1.1.0-beta.4`.
- Workspace-root `pubspec.yaml` adds `dependency_overrides` with
  git refs to in-flight Dartastic branches:
  - `dartastic_opentelemetry`: MindfulSoftwareLLC/dartastic_opentelemetry
    @ `feat/late-binding-proxies` — the late-binding-proxies SDK
    work (`OTel.tracer()` captured at module load survives
    `OTel.initialize`) plus OTLP/HTTP-JSON support and web
    compatibility.
  - `dartastic_opentelemetry_api`: MindfulSoftwareLLC/dartastic_opentelemetry_api
    @ `feat/noop-default-factory` — the spec-aligned noop default
    factory that the SDK's proxies rely on.

  Remove these overrides once both packages publish their pending
  betas to pub.dev.

## Validation

All 252 Genkit tests pass with the Dartastic backend.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.

1 participant