fix(otlp): accept flexible timestamp formats in JSON payloads#1108
fix(otlp): accept flexible timestamp formats in JSON payloads#1108jchrostek-dd merged 5 commits intomainfrom
Conversation
The opentelemetry-proto crate's serde deserializer only accepts
string-encoded 64-bit timestamps (per proto3 JSON spec), but some
OpenTelemetry SDKs send timestamps as integers or objects.
This change adds a normalization layer that converts timestamps to
strings before deserialization, supporting:
- Strings (proto3 JSON spec compliant) - unchanged
- Integers (common in some SDKs) - converted to strings
- Objects {"low": n, "high": m} (buggy older JS SDKs) - reconstructed and converted
Fixes errors like:
- "invalid type: integer `[timestamp]`, expected a string"
- DecodeError when JSON payloads parsed as protobuf
🤖 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>
|
Why not use the opentelemetry-proto |
|
We already have The issue is that PR #1666's pub fn deserialize_string_to_u64<'de, D>(deserializer: D) -> Result<u64, D::Error>
where
D: Deserializer<'de>,
{
let s: String = Deserialize::deserialize(deserializer)?; // ← Only accepts String
s.parse::<u64>().map_err(de::Error::custom)
}When the JSON contains an integer timestamp like The proto3 JSON spec says 64-bit integers SHOULD be string-encoded, and that's what PR #1666 implemented. However, some OpenTelemetry SDKs (particularly older JS versions like 0.36.1) don't follow the spec and send integers. There's an open issue about this. Our normalization layer converts these integer timestamps to strings before passing to serde, making us compatible with both spec-compliant and non-compliant SDKs. |
Summary
{"low": n, "high": m}(from buggy older JS SDKs)"invalid type: integer, expected a string"seen with serverless-self-monitoringRoot Cause
The
opentelemetry-protocrate's serde deserializer only accepts string-encoded 64-bit timestamps (per proto3 JSON spec), but some OpenTelemetry SDKs send timestamps as integers or objects.serverless-self-monitoring uses outdated SDK versions:
@opentelemetry/exporter-trace-otlp-httpopentelemetry-exporter-otlp-proto-httpThe extension's integration tests use 0.54.2 (current), which properly serializes timestamps as strings, so this issue wasn't caught.
Known upstream issue: opentelemetry-rust #1662 - The Rust
opentelemetry-protocrate's serde implementation doesn't accept both string and integer formats for 64-bit integers, as the proto3 JSON spec recommends.Related JS SDK issue: opentelemetry-js #4216 - Older JS SDK versions sent timestamps as
{"low": n, "high": m}objects instead of strings.Solution
Instead of waiting for upstream fixes or requiring all senders to update their SDKs, we normalize JSON timestamps before deserialization:
serde_json::ValuestartTimeUnixNano,endTimeUnixNano,timeUnixNano,observedTimeUnixNano){"low": n, "high": m}→ reconstructed stringopentelemetry-protoTest plan
-D warnings🤖 Generated with Claude Code