otel_watch_it 0.2.0 copy "otel_watch_it: ^0.2.0" to clipboard
otel_watch_it: ^0.2.0 copied to clipboard

OpenTelemetry instrumentation for package:watch_it. Wraps GetIt scope push/drop transitions and callOnce blocks in CLIENT-kind spans to expose DI scope churn.

otel_watch_it #

OpenTelemetry instrumentation for package:watch_it — Thomas Burkhart's reactive binding between Flutter widgets and get_it.

watch_it's value-observation calls (watchIt, watchValue, watchPropertyValue, watchStream, watchFuture) are read-side and fire every rebuild — spanning them would produce gigabytes of low-value traces. This package instruments the lifecycle calls instead: the one-shot callOnce init, the DI-scope pushScope init and dispose, and the explicit onDispose hook. These are the moments where widget mount/unmount can hide slow work, and they're often the first questions you ask when a screen feels slow.

Install #

dependencies:
  watch_it: ^2.4.0
  otel_watch_it: ^0.2.0

Use #

Drop-in replacements take a span name as the first argument (since the underlying widget can't be inferred from a BuildContext):

import 'package:dartastic_opentelemetry/dartastic_opentelemetry.dart';
import 'package:otel_watch_it/otel_watch_it.dart';
import 'package:watch_it/watch_it.dart';

class HomePage extends WatchingWidget {
  const HomePage({super.key});

  @override
  Widget build(BuildContext context) {
    callOnceTraced('HomePage init', (ctx) {
      di<AnalyticsService>().screenView('home');
    });

    onDisposeTraced('HomePage release', () {
      // tear-down work runs inside the span
    });

    return const Scaffold(body: ...);
  }
}

class CheckoutScreen extends WatchingWidget {
  @override
  Widget build(BuildContext context) {
    pushScopeTraced(
      'Checkout scope',
      init: (getIt) {
        getIt.registerSingleton<String>('checkout-session-id');
      },
      dispose: () {
        // optional teardown
      },
    );
    return const Scaffold(body: ...);
  }
}

See example/example.md for a full runnable sample.

Span shape #

Function Span name widget.lifecycle
callOnceTraced watch_it callOnce <name> call_once
callOnceTraced dispose watch_it call_once_dispose <name> call_once_dispose
pushScopeTraced watch_it pushScope <name> push_scope
pushScopeTraced dispose watch_it push_scope_dispose <name> push_scope_dispose
onDisposeTraced watch_it dispose <name> dispose

All spans carry:

Attribute Source
widget.name the caller-supplied name
widget.lifecycle the lifecycle phase (see table)
di.system hardcoded get_it
di.scope.is_final only on pushScope (mirrors flag)
error.type exception class on throw

These keys are package-local (no upstream OTel semconv exists yet for widget lifecycle); they're stable across the 0.x line.

What we don't span #

watch_it's observation API — watchIt, watchValue, watchPropertyValue, watchStream, watchFuture, watch — runs on every rebuild. Spanning those would dwarf the rest of your traces. If you need visibility into a specific reactive expression, wrap the producer of the value (e.g. the stream / future you register in get_it), not the read.

Suppression #

runWithoutWatchItInstrumentation(() {
  callOnceTraced('hot-path init', (_) { ... });  // skipped
});

See also #

  • otel_get_it — GetIt itself (registration / allReady / reset).

License #

Apache 2.0 — copyright Mindful Software LLC.

0
likes
160
points
75
downloads

Documentation

API reference

Publisher

verified publisherdartastic.io

Weekly Downloads

OpenTelemetry instrumentation for package:watch_it. Wraps GetIt scope push/drop transitions and callOnce blocks in CLIENT-kind spans to expose DI scope churn.

Homepage
Repository (GitHub)
View/report issues

License

Apache-2.0 (license)

Dependencies

dartastic_opentelemetry, dartastic_opentelemetry_api, flutter, get_it, watch_it

More

Packages that depend on otel_watch_it