-
Notifications
You must be signed in to change notification settings - Fork 605
fix: serialization/deserialization for u64, f64, and "NaN" float fields in Metrics #3284
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
fix: serialization/deserialization for u64, f64, and "NaN" float fields in Metrics #3284
Conversation
In metric type summary, `quantileValue` with `quantile` = 1 gets treated as u64
|
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #3284 +/- ##
=====================================
Coverage 80.5% 80.5%
=====================================
Files 129 129
Lines 23294 23294
=====================================
Hits 18756 18756
Misses 4538 4538 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR fixes serialization and deserialization issues for metric fields in the OpenTelemetry Protocol (OTLP) JSON format. It addresses the requirement that certain numeric fields (u64 counts, bucket counts) must be serialized as strings in JSON, and adds proper handling for special floating-point values (NaN, Infinity, -Infinity) that cannot be directly represented in standard JSON.
Key changes:
- Added custom serializers/deserializers for u64 count and bucket_counts fields to convert between u64 and string representation
- Implemented special handling for f64 fields that may contain NaN, Infinity, or -Infinity values
- Added
defaultattribute to optional fields (flags, sum, count) to handle cases where they may be missing from JSON payloads
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 10 comments.
| File | Description |
|---|---|
opentelemetry-proto/tests/json_serde.rs |
Updated existing test expectations to reflect u64 values serialized as strings; added comprehensive test cases for NaN handling in Summary metrics |
opentelemetry-proto/tests/grpc_build.rs |
Added field attribute configurations for timestamps, counts, bucket counts, and special f64 handling to ensure proper serialization/deserialization code generation |
opentelemetry-proto/src/proto/tonic/opentelemetry.proto.metrics.v1.rs |
Applied serde attributes to metric data point fields (HistogramDataPoint, ExponentialHistogramDataPoint, SummaryDataPoint) for proper string/numeric conversions and NaN handling |
opentelemetry-proto/src/proto.rs |
Implemented new serializer/deserializer functions for vector u64-to-string conversions and special f64 handling for NaN/Infinity values |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| builder = builder.field_attribute( | ||
| path, | ||
| "#[cfg_attr(feature = \"with-serde\", serde(serialize_with = \"crate::proto::serializers::serialize_vec_u64_to_strings\", deserialize_with = \"crate::proto::serializers::deserialize_strings_to_vec_u64\"))]", | ||
| ); |
Copilot
AI
Dec 18, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inconsistent indentation in field_attribute call. Lines 160-163 have inconsistent indentation compared to the similar block above at lines 145-148. The path and the attribute string should be indented consistently with other field_attribute calls in the file.
| path, | ||
| "#[cfg_attr(feature = \"with-serde\", serde(serialize_with = \"crate::proto::serializers::serialize_f64_special\", deserialize_with = \"crate::proto::serializers::deserialize_f64_special\"))]", | ||
| ); |
Copilot
AI
Dec 18, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inconsistent indentation in field_attribute call. Lines 173-176 have inconsistent indentation compared to the field_attribute call at lines 145-148. The path and the attribute string should be indented consistently with other field_attribute calls in the file.
| path, | |
| "#[cfg_attr(feature = \"with-serde\", serde(serialize_with = \"crate::proto::serializers::serialize_f64_special\", deserialize_with = \"crate::proto::serializers::deserialize_f64_special\"))]", | |
| ); | |
| path, | |
| "#[cfg_attr(feature = \"with-serde\", serde(serialize_with = \"crate::proto::serializers::serialize_f64_special\", deserialize_with = \"crate::proto::serializers::deserialize_f64_special\"))]", | |
| ); |
| let str_vec: Vec<String> = vec.iter().map(|&num| num.to_string()).collect(); | ||
| serializer.collect_seq(str_vec) | ||
| } | ||
|
|
Copilot
AI
Dec 18, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Trailing whitespace on this line. The line ends with spaces after the closing brace, which should be removed for consistency with coding standards.
| } | ||
|
|
||
| deserializer.deserialize_any(F64Visitor) | ||
| } |
Copilot
AI
Dec 18, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Trailing whitespace on this line. The line ends with a space after the closing brace, which should be removed for consistency with coding standards.
| } | |
| } |
| } | ||
|
|
||
| // special serializer and deserializer for metrics bucket counts | ||
| // OTLP/JSON format may uses string for bucket counts |
Copilot
AI
Dec 18, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Grammatical error in comment. The phrase "may uses" is grammatically incorrect and should be "may use" (without the 's').
| pub fn serialize_vec_u64_to_strings<S>(vec: &Vec<u64>, serializer: S) -> Result<S::Ok, S::Error> | ||
| where | ||
| S: Serializer, | ||
| { | ||
| let str_vec: Vec<String> = vec.iter().map(|&num| num.to_string()).collect(); |
Copilot
AI
Dec 18, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Function parameter should use slice instead of vector reference. The parameter vec: &Vec<u64> should be value: &[u64] to follow Rust best practices and match the existing serialize_vec_u64_to_string function pattern at line 178. Using &[u64] is more idiomatic and flexible as it accepts both vectors and slices.
| pub fn serialize_vec_u64_to_strings<S>(vec: &Vec<u64>, serializer: S) -> Result<S::Ok, S::Error> | |
| where | |
| S: Serializer, | |
| { | |
| let str_vec: Vec<String> = vec.iter().map(|&num| num.to_string()).collect(); | |
| pub fn serialize_vec_u64_to_strings<S>(value: &[u64], serializer: S) -> Result<S::Ok, S::Error> | |
| where | |
| S: Serializer, | |
| { | |
| let str_vec: Vec<String> = value.iter().map(|&num| num.to_string()).collect(); |
| .collect() | ||
| } | ||
|
|
||
|
|
Copilot
AI
Dec 18, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unnecessary blank line. This blank line creates excessive vertical spacing (two consecutive blank lines). Remove this line to maintain consistent spacing throughout the file.
| { | ||
| Ok(value as f64) | ||
| } | ||
|
|
Copilot
AI
Dec 18, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The deserializer should handle additional numeric types. The visit_u64 method is implemented but visit_i64 is missing. If the JSON contains integer values like 0 or 1 for quantile values, they might be deserialized as i64 depending on the JSON parser, which would cause deserialization to fail. Consider adding a visit_i64 method similar to visit_u64.
| fn visit_i64<E>(self, value: i64) -> Result<f64, E> | |
| where | |
| E: de::Error, | |
| { | |
| Ok(value as f64) | |
| } |
| } | ||
|
|
||
| // special serializer and deserializer for metrics count | ||
| // OTLP/JSON format may uses string for count |
Copilot
AI
Dec 18, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Grammatical error in comment. The phrase "may uses" is grammatically incorrect and should be "may use" (without the 's').
| use serde::de::{self, MapAccess, Visitor}; | ||
| use serde::ser::{SerializeMap, SerializeSeq, SerializeStruct}; | ||
| use serde::{Deserialize, Deserializer, Serialize, Serializer}; | ||
| use core::f64; |
Copilot
AI
Dec 18, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unnecessary import statement. The use core::f64; import is not needed since f64 is a primitive type in Rust and its associated constants (NAN, INFINITY, NEG_INFINITY) can be accessed directly without importing the module. This import can be removed.
| use core::f64; |
|
@parmesant - thanks for the PR. Can you go through the comments from copilot if they make sense. |
Fixes #2487
Design discussion issue (if applicable) #
Changes
This PR adds to the changes made by @lalitb in his PR #2491
For metric type
Summary,quantileValues.quantilegets treated as u64 and not f64 when its value is 1Also,
flagscomes optionally in the payload hence added default to it (and some other fields)Merge requirement checklist
CHANGELOG.mdfiles updated for non-trivial, user-facing changes