opentelemetry-otlp's HTTP exporters still pull opentelemetry-proto/gen-tonic-messages, which in turn pulls tonic, tonic-prost, and prost, even when grpc-tonic is not enabled.
This affects both http-proto and http-json.
Relevant code:
Minimal repro:
[dependencies]
opentelemetry = { version = "0.31.0", default-features = false, features = ["trace"] }
opentelemetry-otlp = { version = "0.31.1", default-features = false, features = ["http-proto"] } # or ["http-json"]
opentelemetry_sdk = { version = "0.31.0", default-features = false, features = ["trace"] }
use opentelemetry::trace::{Tracer, TracerProvider};
use opentelemetry_otlp::{Protocol, WithExportConfig};
use opentelemetry_sdk::trace::SdkTracerProvider;
fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
let exporter = opentelemetry_otlp::SpanExporter::builder()
.with_http()
.with_protocol(Protocol::HttpBinary) // use HttpJson for the json repro
.build()?;
let provider = SdkTracerProvider::builder()
.with_simple_exporter(exporter)
.build();
let tracer = provider.tracer("repro");
tracer.in_span("one-span", |_| {});
provider.shutdown()?;
Ok(())
}
cargo tree -e features -i tonic still shows tonic in both cases.
Measured impact from clean cargo build --release --timings builds on rustc 1.94.1, cargo 1.94.1, macOS arm64. The baseline uses the same trace SDK shape, but with a local no-op exporter instead of OTLP.
| Metric |
Baseline |
http-proto |
http-json |
| Build time |
real 3.83s |
real 6.49s (+69%) |
real 6.93s (+81%) |
| Binary size |
613 KiB |
888 KiB (+45%) |
967 KiB (+58%) |
Relevant timing rows:
| Crate |
http-proto |
http-json |
opentelemetry-proto v0.31.0 |
1.1s |
1.4s |
tonic v0.14.5 |
0.8s |
1.0s |
prost v0.14.3 |
0.8s |
0.9s |
prost-derive v0.14.3 |
0.6s |
0.6s |
tonic-prost v0.14.5 |
0.1s |
0.1s |
serde_json v1.0.149 |
- |
0.6s |
Expected:
http-proto should not need tonic
http-json should not need tonic
If the current implementation needs shared generated message types, it would be useful to split “message types needed by HTTP exporters” from “tonic-specific gRPC/client code”.
This is the http-json timing plot. The final binary is using HTTP/JSON, but a visible part of the build is still in the tonic/prost path.

opentelemetry-otlp's HTTP exporters still pullopentelemetry-proto/gen-tonic-messages, which in turn pullstonic,tonic-prost, andprost, even whengrpc-tonicis not enabled.This affects both
http-protoandhttp-json.Relevant code:
http-protoandhttp-jsonboth enableopentelemetry-proto/gen-tonic-messagesopentelemetry-otlp/Cargo.toml#L93-L99gen-tonic-messagesenablestonic,tonic-prost, andprostopentelemetry-proto/Cargo.toml#L37-L39,opentelemetry-proto/Cargo.toml#L54-L57opentelemetry_proto::tonic::*request types for both JSON and protobufhttp/mod.rs#L11-L20,http/mod.rs#L600-L676Minimal repro:
cargo tree -e features -i tonicstill showstonicin both cases.Measured impact from clean
cargo build --release --timingsbuilds onrustc 1.94.1,cargo 1.94.1, macOS arm64. The baseline uses the same trace SDK shape, but with a local no-op exporter instead of OTLP.http-protohttp-jsonreal 3.83sreal 6.49s(+69%)real 6.93s(+81%)613 KiB888 KiB(+45%)967 KiB(+58%)Relevant timing rows:
http-protohttp-jsonopentelemetry-proto v0.31.01.1s1.4stonic v0.14.50.8s1.0sprost v0.14.30.8s0.9sprost-derive v0.14.30.6s0.6stonic-prost v0.14.50.1s0.1sserde_json v1.0.1490.6sExpected:
http-protoshould not needtonichttp-jsonshould not needtonicIf the current implementation needs shared generated message types, it would be useful to split “message types needed by HTTP exporters” from “tonic-specific gRPC/client code”.
This is the
http-jsontiming plot. The final binary is using HTTP/JSON, but a visible part of the build is still in the tonic/prost path.