Skip to main content

rpc_dart_opentelemetry 0.5.0 copy "rpc_dart_opentelemetry: ^0.5.0" to clipboard
rpc_dart_opentelemetry: ^0.5.0 copied to clipboard

OpenTelemetry tracing, metrics, and logging integration for rpc_dart.

example/example.dart

// SPDX-FileCopyrightText: 2026 Karim "nogipx" Mamatkazin <nogipx@gmail.com>
//
// SPDX-License-Identifier: MIT

import 'package:opentelemetry/api.dart';
import 'package:opentelemetry/sdk.dart';
import 'package:rpc_dart/rpc_dart.dart';
import 'package:rpc_dart_opentelemetry/rpc_dart_opentelemetry.dart';

/// Example: one trace from a caller to a responder over an in-memory
/// transport.
///
/// Spans are printed to stdout. To send them to an OpenTelemetry collector
/// instead, pass its OTLP/HTTP traces endpoint to [bootstrapTracing]:
///
///   docker run -p 4318:4318 otel/opentelemetry-collector-contrib
///   bootstrapTracing(otlpTraces: Uri.parse('http://localhost:4318/v1/traces'))
///
/// `CollectorExporter` ships in `package:opentelemetry/sdk.dart` and sends
/// OTLP over HTTP with protobuf, so use the HTTP port 4318, not gRPC 4317.
TracerProviderBase bootstrapTracing({Uri? otlpTraces}) {
  final provider = TracerProviderBase(
    processors: [
      if (otlpTraces == null)
        SimpleSpanProcessor(ConsoleExporter())
      else
        BatchSpanProcessor(CollectorExporter(otlpTraces)),
    ],
  );
  registerGlobalTracerProvider(provider);
  return provider;
}

final class GreeterResponder extends RpcResponderContract {
  GreeterResponder() : super('Greeter');

  @override
  void setup() {
    addUnaryMethod<RpcString, RpcString>(
      methodName: 'hello',
      handler: _hello,
      requestCodec: RpcString.codec,
      responseCodec: RpcString.codec,
    );
  }

  Future<RpcString> _hello(RpcString request, {RpcContext? context}) async {
    // OtelRpcInterceptor stores the server span of this call in the context.
    final span = context?.getValue<Span>(OtelRpcKeys.span);
    span?.setAttribute(Attribute.fromString('greeting.name', request.value));
    return RpcString('Hello, ${request.value}');
  }
}

final class GreeterCaller extends RpcCallerContract {
  GreeterCaller(RpcCallerEndpoint endpoint) : super('Greeter', endpoint);

  Future<RpcString> hello(RpcString request, {RpcContext? context}) =>
      callUnary<RpcString, RpcString>(
        methodName: 'hello',
        request: request,
        requestCodec: RpcString.codec,
        responseCodec: RpcString.codec,
        context: context,
      );
}

Future<void> main() async {
  final provider = bootstrapTracing();
  final tracer = globalTracerProvider.getTracer('greeter', version: '1.0.0');

  final (clientTransport, serverTransport) = RpcChannelTransport.memoryPair();

  // Server side: one SERVER span per call, parented on the incoming
  // traceparent.
  final responder = RpcResponderEndpoint(transport: serverTransport)
    ..addInterceptor(OtelRpcInterceptor(tracer: tracer))
    ..registerServiceContract(GreeterResponder())
    ..start();

  // Client side: one CLIENT span per call, traceparent injected into the
  // outgoing metadata.
  final caller = RpcCallerEndpoint(transport: clientTransport)
    ..addInterceptor(OtelRpcClientInterceptor(tracer: tracer));

  // One trace: client span Greeter/hello -> server span Greeter/hello.
  await GreeterCaller(caller).hello(const RpcString('Ada'));

  await caller.close();
  await responder.close();

  // Flush buffered spans before the process exits.
  provider.shutdown();
}
0
likes
70
points
176
downloads

Documentation

API reference

Publisher

verified publisherrpc.nogipx.dev

Weekly Downloads

OpenTelemetry tracing, metrics, and logging integration for rpc_dart.

Homepage
Repository (GitHub)
View/report issues

Topics

#rpc #opentelemetry #tracing #observability

License

MIT (license)

Dependencies

fixnum, meta, opentelemetry, rpc_dart

More

Packages that depend on rpc_dart_opentelemetry