Skip to content

OpenTelemetry

Server-side OpenTelemetry instrumentation for distributed tracing and metrics. Requires pip install vgi-rpc[otel].

Usage

from vgi_rpc import RpcServer
from vgi_rpc.otel import OtelConfig, instrument_server

server = RpcServer(MyService, MyServiceImpl())
instrument_server(server)  # uses global TracerProvider / MeterProvider

This creates spans and records metrics for every RPC call:

  • Span: includes method name, service name, auth context, duration, error status, and per-call I/O statistics
  • Counter: rpc.server.requests — number of RPC requests handled
  • Histogram: rpc.server.duration — duration in seconds

Trace context propagates automatically: from contextvars (pipe transport) or W3C headers (HTTP transport).

Span Attributes

Each span carries the following attributes:

Attribute Type Description
rpc.system str Always "vgi_rpc"
rpc.service str Protocol class name
rpc.method str Method name
rpc.vgi_rpc.method_type str "unary" or "stream"
rpc.vgi_rpc.server_id str Server instance identifier
enduser.id str Caller principal (when authenticated)
rpc.vgi_rpc.auth.domain str Auth scheme (when authenticated)
rpc.vgi_rpc.auth.authenticated str "true" or "false"
net.peer.ip str Client IP address (HTTP only)
user_agent.original str User agent string (HTTP only)
rpc.vgi_rpc.input_batches int Number of input batches read by the server
rpc.vgi_rpc.output_batches int Number of output batches written by the server
rpc.vgi_rpc.input_rows int Total rows across all input batches
rpc.vgi_rpc.output_rows int Total rows across all output batches
rpc.vgi_rpc.input_bytes int Approximate logical bytes across all input batches
rpc.vgi_rpc.output_bytes int Approximate logical bytes across all output batches
rpc.vgi_rpc.error_type str Exception class name (error spans only)

The I/O statistics attributes (input_batches through output_bytes) are populated from CallStatistics — see CallStatistics for counting semantics.

Note: Byte counts use pa.RecordBatch.get_total_buffer_size() — logical Arrow buffer sizes without IPC framing overhead.

API Reference

OtelConfig

OtelConfig dataclass

OtelConfig(
    tracer_provider: TracerProvider | None = None,
    meter_provider: MeterProvider | None = None,
    enable_tracing: bool = True,
    enable_metrics: bool = True,
    record_exceptions: bool = True,
    custom_attributes: Mapping[str, str] = dict(),
)

Configuration for OpenTelemetry instrumentation.

ATTRIBUTE DESCRIPTION
tracer_provider

Custom TracerProvider; uses the global provider when None.

TYPE: TracerProvider | None

meter_provider

Custom MeterProvider; uses the global provider when None.

TYPE: MeterProvider | None

enable_tracing

Enable span creation (default True).

TYPE: bool

enable_metrics

Enable counter/histogram recording (default True).

TYPE: bool

record_exceptions

Record exceptions on error spans (default True).

TYPE: bool

custom_attributes

Extra span/metric attributes merged into every dispatch.

TYPE: Mapping[str, str]

instrument_server

instrument_server

instrument_server(
    server: RpcServer, config: OtelConfig | None = None
) -> RpcServer

Attach OpenTelemetry tracing and metrics to a server.

Must be called before serve() — not thread-safe during dispatch.

PARAMETER DESCRIPTION
server

The RpcServer to instrument.

TYPE: RpcServer

config

Optional configuration; uses global providers and defaults when None.

TYPE: OtelConfig | None DEFAULT: None

RETURNS DESCRIPTION
RpcServer

The same server instance (for chaining).

Source code in vgi_rpc/otel.py
def instrument_server(server: RpcServer, config: OtelConfig | None = None) -> RpcServer:
    """Attach OpenTelemetry tracing and metrics to a server.

    Must be called before ``serve()`` — not thread-safe during dispatch.

    Args:
        server: The ``RpcServer`` to instrument.
        config: Optional configuration; uses global providers and defaults when ``None``.

    Returns:
        The same *server* instance (for chaining).

    """
    if config is None:
        config = OtelConfig()
    hook = _OtelDispatchHook(config, server.protocol_name, server.server_id)
    server._dispatch_hook = hook
    return server