feat(otlp): add gRPC protocol support for trace ingestion#1105
Open
jchrostek-dd wants to merge 8 commits intomainfrom
Open
feat(otlp): add gRPC protocol support for trace ingestion#1105jchrostek-dd wants to merge 8 commits intomainfrom
jchrostek-dd wants to merge 8 commits intomainfrom
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
Adds OTLP trace ingestion over gRPC (port 4317) alongside the existing HTTP OTLP endpoint (port 4318), wiring enablement through existing config and adding integration coverage for the new protocol.
Changes:
- Introduce a tonic-based gRPC OTLP TraceService server and start it from the bottlecap binary when configured.
- Refactor the OTLP processor to accept a pre-deserialized
ExportTraceServiceRequestfor reuse across HTTP and gRPC paths. - Extend integration test stack + test suite with a Node.js Lambda that exports traces via OTLP gRPC.
Reviewed changes
Copilot reviewed 8 out of 10 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
integration-tests/tests/otlp.test.ts |
Adds a new test block covering gRPC OTLP trace export. |
integration-tests/lib/stacks/otlp.ts |
Provisions an additional Node Lambda configured to export traces via OTLP gRPC. |
integration-tests/lambda/otlp-node/package.json |
Adds the OTLP gRPC trace exporter dependency. |
integration-tests/lambda/otlp-node/grpc-handler.js |
Implements the Node Lambda handler that emits spans and exports via gRPC. |
bottlecap/src/otlp/processor.rs |
Splits decoding from processing to support gRPC’s already-decoded request type. |
bottlecap/src/otlp/mod.rs |
Adds gRPC module + enablement helpers and tests. |
bottlecap/src/otlp/grpc_agent.rs |
New gRPC server implementation for OTLP trace ingestion. |
bottlecap/src/bin/bottlecap/main.rs |
Starts HTTP and/or gRPC OTLP servers based on config. |
bottlecap/Cargo.toml |
Adds tonic dependency needed for the gRPC server. |
bottlecap/Cargo.lock |
Lockfile updates for the added tonic dependency. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+137
to
+151
| fn parse_port(endpoint: Option<&String>, default_port: u16) -> u16 { | ||
| if let Some(endpoint) = endpoint { | ||
| let port = endpoint.split(':').nth(1); | ||
| if let Some(port) = port { | ||
| return port.parse::<u16>().unwrap_or_else(|_| { | ||
| error!("Invalid OTLP gRPC port, using default port {default_port}"); | ||
| default_port | ||
| }); | ||
| } | ||
|
|
||
| error!("Invalid OTLP gRPC endpoint format, using default port {default_port}"); | ||
| } | ||
|
|
||
| default_port | ||
| } |
Comment on lines
+156
to
+161
| let max_recv_msg_size = self | ||
| .config | ||
| .otlp_config_receiver_protocols_grpc_max_recv_msg_size_mib | ||
| .map_or(DEFAULT_MAX_RECV_MSG_SIZE, |mib| { | ||
| mib.unsigned_abs() as usize * 1024 * 1024 | ||
| }); |
integration-tests/tests/otlp.test.ts
Outdated
Comment on lines
+117
to
+121
| it('should preserve span parent-child relationships', () => { | ||
| const result = getResult(); | ||
| expect(result).toBeDefined(); | ||
| const trace = result.traces![0]; | ||
| // Verify that the trace has at least one span |
bottlecap/src/otlp/grpc_agent.rs
Outdated
Comment on lines
+52
to
+59
| let tracer_header_tags = DatadogTracerHeaderTags::default(); | ||
| let body_size = size_of_val(&traces); | ||
| if body_size == 0 { | ||
| error!("OTLP gRPC | Not sending traces, processor returned empty data"); | ||
| return Err(Status::internal( | ||
| "Not sending traces, processor returned empty data", | ||
| )); | ||
| } |
Add gRPC support for OTLP trace ingestion on port 4317, complementing the existing HTTP endpoint on port 4318. Changes: - Add tonic dependency with transport/server features - Implement TraceService trait in new grpc_agent.rs module - Refactor OtlpProcessor to accept ExportTraceServiceRequest directly - Update enablement logic to check both HTTP and gRPC endpoints - Wire up max message size config from DD_OTLP_CONFIG_RECEIVER_PROTOCOLS_GRPC_MAX_RECV_MSG_SIZE_MIB - Add integration tests for gRPC protocol Users can now configure gRPC OTLP export by setting: DD_OTLP_CONFIG_RECEIVER_PROTOCOLS_GRPC_ENDPOINT=localhost:4317 Binary size impact: +16 bytes (negligible - tonic transport was already pulled in transitively). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix parse_port to handle URL schemes (http://, https://) - Validate max_recv_msg_size: reject negative values, cap at 64MiB - Use encoded_len() for body_size, traces.iter().all(Vec::is_empty) for empty check - Rename misleading test to match actual assertions - Add tests for URL scheme handling 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Simplify enablement logic by using only should_enable_http and should_enable_grpc functions directly. The combined check is now inlined in start_otlp_agent. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
ab535e1 to
b3dd772
Compare
Previously, each OTLP agent created its own CancellationToken internally, but only the gRPC agent's token was captured and used for shutdown. The HTTP agent's token was never retrieved, so it couldn't be cancelled. Now both agents accept a CancellationToken parameter, and the caller creates a single shared token. One cancel() cleanly shuts down both. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
92e6442 to
ef1508e
Compare
Align with trace agent's TRACE_REQUEST_BODY_LIMIT (50MB) instead of 64MB. More appropriate for Lambda's memory-constrained environment. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Rename should_enable_http → should_enable_otlp_http Rename should_enable_grpc → should_enable_otlp_grpc 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
a6b99bc to
650a404
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
TraceServicetrait using tonic for gRPC serverOtlpProcessorto acceptExportTraceServiceRequestdirectly (avoids re-encoding for gRPC)DD_OTLP_CONFIG_RECEIVER_PROTOCOLS_GRPC_ENDPOINTandDD_OTLP_CONFIG_RECEIVER_PROTOCOLS_GRPC_MAX_RECV_MSG_SIZE_MIBMotivation
Users were configuring gRPC OTLP endpoints (
DD_OTLP_CONFIG_RECEIVER_PROTOCOLS_GRPC_ENDPOINT) but the feature was not implemented, resulting in silent failures. This PR enables gRPC support. This was for an old ticket, but we should go ahead and add this, especially since OTLP is getting more popular.Changes
bottlecap/Cargo.tomlbottlecap/src/otlp/grpc_agent.rsbottlecap/src/otlp/processor.rsbottlecap/src/otlp/mod.rsbottlecap/src/bin/bottlecap/main.rsBinary Size Impact
Measured from CI layer size checks (arm64):
This is a ~1.7% increase, well under historical concerns (OTLP was removed from Go agent for adding ~1.15MB).
Test plan
cargo fmt,cargo clippy,cargo testpass🤖 Generated with Claude Code