Testing an OTLP/gRPC endpoint with grpcurl confirms that a Collector or backend listener accepts the OpenTelemetry trace export service before application instrumentation becomes the next suspect. It fits cases where a client cannot send telemetry and the first question is whether the endpoint, transport mode, and protobuf service are reachable.
grpcurl needs the OTLP protobuf schema because many OTLP receivers do not expose gRPC server reflection. The smoke test loads the official trace service definition and calls the trace export RPC directly instead of relying on list or describe.
Use -plaintext only for a local or explicitly plaintext receiver. For a TLS endpoint, omit -plaintext and add --cacert when the server certificate chains to a private CA. A successful export response proves the receiver accepted the request, but backend storage still needs a pipeline or backend-side check.
$ git clone --depth 1 https://github.com/open-telemetry/opentelemetry-proto.git
Skip this step when the opentelemetry-proto source or an equivalent protoset is already available.
{
"resourceSpans": [
{
"resource": {
"attributes": [
{
"key": "service.name",
"value": {
"stringValue": "checkout-api"
}
}
]
},
"scopeSpans": [
{
"scope": {
"name": "manual-grpcurl"
},
"spans": [
{
"traceId": "W47/95gDgQPSabYzgT/GDA==",
"spanId": "7uGbfsPBsXQ=",
"name": "grpcurl-otlp-smoke",
"kind": 1,
"startTimeUnixNano": "1717260000000000000",
"endTimeUnixNano": "1717260001000000000"
}
]
}
]
}
]
}
grpcurl uses protobuf JSON encoding. Byte fields such as traceId and spanId must be base64 strings, while the debug exporter later prints those same IDs as hexadecimal.
$ grpcurl -plaintext \
-import-path opentelemetry-proto \
-proto opentelemetry/proto/collector/trace/v1/trace_service.proto \
-d @ collector.example.net:4317 \
opentelemetry.proto.collector.trace.v1.TraceService/Export < otlp-trace.json
{
"partialSuccess": {}
}
Replace collector.example.net:4317 with the endpoint under test. For a TLS endpoint, remove -plaintext; for a private CA, add --cacert before the endpoint.
$ grpcurl -plaintext collector.example.net:4317 list Failed to list services: server does not support the reflection API
OTLP receivers commonly accept TraceService/Export without enabling server reflection. Use the explicit -proto export call as the endpoint check.
$ journalctl -u otelcol --since "5 minutes ago" --no-pager
##### snipped #####
Traces {"otelcol.component.id":"debug","otelcol.component.kind":"exporter","otelcol.signal":"traces","resource spans":1,"spans":1}
Resource attributes:
-> service.name: Str(checkout-api)
InstrumentationScope manual-grpcurl
Span #0
Trace ID : 5b8efff798038103d269b633813fc60c
ID : eee19b7ec3c1b174
Name : grpcurl-otlp-smoke
The grpcurl response confirms the receiver accepted the request. The log or backend view confirms the trace reached the expected pipeline or storage path.
Related: How to test OpenTelemetry Collector pipelines with the debug exporter
$ rm -rf opentelemetry-proto otlp-trace.json