OpenTelemetry — vyuh_server_plugin_telemetry_otel
Production TelemetryPlugin backed by the OpenTelemetry SDK. Adapts the framework's TelemetrySink / TelemetrySpan interfaces to OTel tracers, span processors, and exporters. Configures itself from standard OTEL_* environment variables — zero plugin-specific knobs for the common case.
Install
dependencies:
vyuh_server_plugin_telemetry_otel:
hosted: https://pub.vyuh.tech
version: ^0.1.0Minimal Wiring
import 'package:vyuh_server/vyuh_server.dart';
import 'package:vyuh_server_plugin_telemetry_otel/vyuh_server_plugin_telemetry_otel.dart';
final runtime = await VyuhServer.bootstrap(
plugins: [
OtelTelemetryPlugin(defaultServiceName: 'saas-api'),
],
);The plugin reads OTEL_* env vars during init. When tracing is off (none of the env vars are set), every call is a no-op — handlers don't need to guard their vyuh.telemetry.startSpan(...) calls.
Env Vars
The plugin honors the standard OpenTelemetry environment variables:
| Variable | Purpose | Example |
|---|---|---|
OTEL_ENABLED=true | Force-enable | true |
OTEL_SDK_DISABLED=true | Force-disable | true |
OTEL_SERVICE_NAME | Override defaultServiceName | saas-api-prod |
OTEL_SERVICE_VERSION | Service version attribute | 2.4.1 |
OTEL_RESOURCE_ATTRIBUTES | Extra resource attrs | env=prod,region=us-east-1 |
OTEL_TRACES_EXPORTER | Exporter selection | otlp, jaeger, cloud_trace, console, none |
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT | Traces endpoint | https://otlp.example.com:4317/v1/traces |
OTEL_EXPORTER_OTLP_ENDPOINT | All-signals endpoint | https://otlp.example.com:4317 |
OTEL_ENDPOINT | Shortcut for the above | https://otlp.example.com:4317 |
OTEL_TRACES_SAMPLER | Sampling | always_on, always_off, parentbased_always_on, parentbased_always_off |
Wire whatever your APM vendor documents (Honeycomb, Lightstep, Datadog, Tempo, Jaeger, OTel Collector) — the plugin doesn't care.
Tracing Middleware
The plugin ships a tracingMiddleware() that starts a span per HTTP request:
await runtime.start(
port: 8080,
middleware: [
tracingMiddleware(), // one span per request
GlobalMiddleware.cors(),
GlobalMiddleware.errorHandler(),
GlobalMiddleware.requestLogger(),
],
);Each request span carries:
http.method,http.route,http.status_codeclient.address(fromreq.clientContext.ipAddress)user_agent.originalvyuh.request_id(correlates with the response'sX-Request-Id)
Child spans started via vyuh.telemetry.startSpan(...) automatically nest under the request span — no parent threading required.
In Handlers
Future<Response> placeOrder(Request req) async {
final span = vyuh.telemetry.startSpan(
'order.place',
attrs: {'tenant_id': req.actor.tenantId},
);
try {
final order = await _persist(req);
span.setAttribute('order_id', order.id);
span.setAttribute('total_cents', order.totalCents);
vyuh.telemetry.counter('orders.created', delta: 1);
return jsonResponse(body: {'success': true, 'data': order.toJson()});
} catch (e, st) {
span.recordException(e, st);
span.end(success: false);
rethrow;
} finally {
span.end();
}
}span.end(success: false) records Status.error so SLO dashboards can split failures cleanly.
Custom Config Object
For non-standard deployments, bypass env vars with an explicit OtelConfig:
final cfg = OtelConfig(
serviceName: 'saas-api',
serviceVersion: '2.4.1',
exporter: OtelExporter.otlp,
endpoint: 'https://otlp.example.com:4317',
resourceAttributes: {
'env': 'prod',
'region': 'us-east-1',
},
sampler: OtelSampler.parentBasedAlwaysOn,
);
OtelTelemetryPlugin(
defaultServiceName: 'saas-api',
config: cfg,
);Shutdown
The plugin's dispose flushes pending spans before the SDK provider shuts down. The framework's graceful-shutdown wiring calls dispose automatically on SIGINT/SIGTERM — no in-flight spans are lost under a kubectl rollout.
Where to Go Next
- Console Telemetry — dev sink with the same API
vyuh.telemetry— the typed verb- Architecture — the graceful-shutdown pipeline