feat(trace): add allocation-free to_hex() for TraceId and SpanId#3557
feat(trace): add allocation-free to_hex() for TraceId and SpanId#3557BRGOVIND wants to merge 2 commits into
Conversation
Exporters that need a hex string for trace/span IDs currently have to
call .to_string() which heap-allocates a String on every export. On hot
paths this is two unnecessary allocations per record.
This commit adds:
- HexEncode<N> — a stack-allocated buffer of N ASCII bytes that derefs
to &str and implements Display/Debug. No heap allocation, no unsafe
visible to callers.
- TraceId::to_hex() -> HexEncode<32> — 32-char lowercase hex, no alloc.
- SpanId::to_hex() -> HexEncode<16> — 16-char lowercase hex, no alloc.
HexEncode is re-exported from the crate root alongside TraceId/SpanId.
Exporters that currently write:
format!("{}", trace_id)
can switch to:
let hex = trace_id.to_hex();
write_field(&*hex)
and avoid the allocation entirely.
Closes open-telemetry#3544
Signed-off-by: B R GOVIND <brgovind2005@gmail.com>
|
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #3557 +/- ##
=====================================
Coverage 82.9% 82.9%
=====================================
Files 130 130
Lines 27484 27557 +73
=====================================
+ Hits 22796 22869 +73
Misses 4688 4688 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Cover HexEncode<N>: as_str(), Deref to &str, Display, Debug, Clone, PartialEq, and the all-bytes encoding correctness. Also test the INVALID sentinel values for both types. Signed-off-by: B R GOVIND <brgovind2005@gmail.com>
|
Added tests in the latest commit to cover the new code paths (fixes the Codecov patch coverage):
|
|
Gentle ping — this adds an allocation-free |
|
Thank you for your contribution! This PR has been automatically marked as stale because it has not had activity in the last 14 days. This may be due to a delay in review on our side or awaiting a response from you; either is fine, and we appreciate your patience. It will be closed in 14 days if no further activity occurs. Pushing a new commit or leaving a comment will remove the stale label and keep the PR open. |
Maintainers can u please take a look at the pr ? |
I'll review today |
There was a problem hiding this comment.
Pull request overview
Adds allocation-free, stack-based lowercase hex encoding for TraceId and SpanId to avoid per-export heap allocations, along with a reusable HexEncode<N> wrapper type.
Changes:
- Introduces
HexEncode<const N: usize>(stack[u8; N]) that derefs tostrand implementsDisplay/Debug. - Adds
TraceId::to_hex() -> HexEncode<32>andSpanId::to_hex() -> HexEncode<16>using a sharedencode_hex_byteshelper. - Re-exports
HexEncodefrom the crate root and adds tests validating formatting behavior.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| opentelemetry/src/trace_context.rs | Adds HexEncode, to_hex() APIs, encoding helper, and new unit tests. |
| opentelemetry/src/lib.rs | Re-exports HexEncode alongside existing trace ID types. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| /// Return the hex string as a `&str`. | ||
| pub fn as_str(&self) -> &str { | ||
| // SAFETY: the buffer is always filled with ASCII hex digits. | ||
| unsafe { std::str::from_utf8_unchecked(&self.0) } | ||
| } |
| #[test] | ||
| fn test_to_hex_all_bytes() { | ||
| // Verify every possible byte value encodes correctly. | ||
| let mut bytes = [0u8; 16]; | ||
| for i in 0u8..=255 { | ||
| bytes[i as usize % 16] = i; | ||
| } | ||
| let id = TraceId::from_bytes(bytes); | ||
| let hex = id.to_hex(); | ||
| assert_eq!(hex.as_str(), format!("{}", id)); | ||
| assert_eq!(hex.len(), 32); | ||
| } |
| mod trace_context; | ||
| pub use trace_context::{SpanId, TraceFlags, TraceId}; | ||
| pub use trace_context::{HexEncode, SpanId, TraceFlags, TraceId}; |
Closes #3544 — adds allocation-free hex encoding methods for
TraceIdandSpanId.Problem
Exporters that need the hex representation of a trace/span ID today call
.to_string(), which heap-allocates aStringon every export event. On hot paths this is two unnecessary allocations per span record.Solution
This PR adds:
HexEncode<N>— a stack-allocated[u8; N]newtype that:Deref<Target = str>DisplayandDebugTraceId::to_hex() -> HexEncode<32>— 32-char lowercase hex, no allocationSpanId::to_hex() -> HexEncode<16>— 16-char lowercase hex, no allocationHexEncodeis re-exported from the crate root alongsideTraceId/SpanId.Usage
Before:
After:
Exporters can switch from
format!("{}", trace_id)totrace_id.to_hex()and eliminate both allocations per record.