Skip to content

Allow configuring the gRPC export channel - #156

Merged
cetra3 merged 1 commit into
mainfrom
grpc-channel-hook
Sep 24, 2026
Merged

cetra3 merged 1 commit into
mainfrom
grpc-channel-hook

Conversation

@cetra3

@cetra3 cetra3 commented Sep 24, 2026

Copy link
Copy Markdown
Contributor

Adds AdvancedOptions::with_grpc_channel, which lets the caller build the tonic channel for gRPC exports from the Endpoint that the SDK prepares. Before this change, the SDK always called Endpoint::connect_lazy(), so no transport option could be set.

Why

A gRPC exporter keeps one HTTP/2 connection open, and an export that times out does not close it. If the collector host stops responding without closing the connection, every later export on that connection times out too. The connection only closes when the kernel stops retransmitting, which takes about 15 minutes with the Linux defaults. For that time, the exporter drops every batch.

Two settings fix this, and neither was reachable before:

  • TCP_USER_TIMEOUT closes a connection whose sent data stays unacknowledged. tonic has no option for it, so it needs a custom connector.
  • Endpoint::connect_timeout bounds a reconnect to an address that does not answer. TCP_USER_TIMEOUT does not apply while a connection is being opened.

A hook covers both, and every other Endpoint option, without one SDK method per option:

AdvancedOptions::default().with_grpc_channel(|endpoint| {
    let mut connector = HttpConnector::new();
    connector.enforce_http(false);
    connector.set_nodelay(true);
    connector.set_tcp_user_timeout(Some(Duration::from_secs(20)));
    endpoint
        .connect_timeout(Duration::from_secs(5))
        .connect_with_connector_lazy(connector)
})

Change

  • AdvancedOptions::with_grpc_channel(impl Fn(Endpoint) -> Channel), available with the export-grpc feature. The Endpoint has the export URL and, for https, TLS configured. The SDK calls build once for each of the span, log and metric exporters, inside the export runtime.
  • A crate-private ExportOptions carries the hook to the exporters. The public span_exporter, metric_exporter and log_exporter functions keep their signatures.
  • Without the hook, the channel is built with connect_lazy() as before.

This puts tonic types in the public API behind export-grpc. The tonic version already follows opentelemetry-otlp, which is part of each breaking logfire release.

HTTP exports are unchanged. They use HTTP/1.1, where an export that times out closes its connection.

Validation

  • cargo clippy --workspace --all-features -- -D warnings passes.
  • cargo check --workspace --no-default-features passes with no export feature, with each export feature, and with all of them.
  • cargo doc with -D warnings --cfg docsrs passes.
  • The existing gRPC tests pass. This PR adds no test for the hook.

@codecov-commenter

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 69.64286% with 17 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
logfire/src/config.rs 0.00% 7 Missing ⚠️
logfire/src/exporters.rs 78.12% 3 Missing and 4 partials ⚠️
logfire/src/logfire.rs 82.35% 0 Missing and 3 partials ⚠️

📢 Thoughts on this report? Let us know!

@cetra3
cetra3 merged commit 804eca4 into main Sep 24, 2026
8 checks passed
@cetra3
cetra3 deleted the grpc-channel-hook branch September 24, 2026 23:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants