From 9e5efad8360362ac016d88babb3cfe39207837d5 Mon Sep 17 00:00:00 2001 From: Mahad Zaryab Date: Sun, 14 Sep 2025 20:52:17 -0400 Subject: [PATCH 01/14] Add Helpers For Marshalling And Unmarshalling AnyValue Signed-off-by: Mahad Zaryab --- pdata/ptrace/json.go | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/pdata/ptrace/json.go b/pdata/ptrace/json.go index 1c1cab317dda..776583c0e995 100644 --- a/pdata/ptrace/json.go +++ b/pdata/ptrace/json.go @@ -7,6 +7,7 @@ import ( "slices" "go.opentelemetry.io/collector/pdata/internal" + otlpcommon "go.opentelemetry.io/collector/pdata/internal/data/protogen/common/v1" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/otlp" ) @@ -25,6 +26,16 @@ func (*JSONMarshaler) MarshalTraces(td Traces) ([]byte, error) { return slices.Clone(dest.Buffer()), nil } +func (*JSONMarshaler) MarshalAnyValue(value *otlpcommon.AnyValue) ([]byte, error) { + dest := json.BorrowStream(nil) + defer json.ReturnStream(dest) + internal.MarshalJSONOrigAnyValue(value, dest) + if dest.Error() != nil { + return nil, dest.Error() + } + return slices.Clone(dest.Buffer()), nil +} + // JSONUnmarshaler unmarshals OTLP/JSON formatted-bytes to Traces. type JSONUnmarshaler struct{} @@ -40,3 +51,14 @@ func (*JSONUnmarshaler) UnmarshalTraces(buf []byte) (Traces, error) { otlp.MigrateTraces(td.getOrig().ResourceSpans) return td, nil } + +func (*JSONMarshaler) UnmarshalAnyValue(buf []byte) (*otlpcommon.AnyValue, error) { + iter := json.BorrowIterator(buf) + defer json.ReturnIterator(iter) + value := &otlpcommon.AnyValue{} + internal.UnmarshalJSONOrigAnyValue(value, iter) + if iter.Error() != nil { + return nil, iter.Error() + } + return value, nil +} From e0dc4186ac5914c1e3e8897836c82eb16703487e Mon Sep 17 00:00:00 2001 From: Mahad Zaryab Date: Mon, 15 Sep 2025 23:03:57 -0400 Subject: [PATCH 02/14] Move To pcommon Signed-off-by: Mahad Zaryab --- pdata/pcommon/json.go | 34 ++++++++++++++++++++++++++++++++++ pdata/ptrace/json.go | 22 ---------------------- 2 files changed, 34 insertions(+), 22 deletions(-) create mode 100644 pdata/pcommon/json.go diff --git a/pdata/pcommon/json.go b/pdata/pcommon/json.go new file mode 100644 index 000000000000..a3b1a7397fde --- /dev/null +++ b/pdata/pcommon/json.go @@ -0,0 +1,34 @@ +package pcommon + +import ( + "slices" + + "go.opentelemetry.io/collector/pdata/internal" + otlpcommon "go.opentelemetry.io/collector/pdata/internal/data/protogen/common/v1" + "go.opentelemetry.io/collector/pdata/internal/json" +) + +type JSONMarshaler struct{} + +func (*JSONMarshaler) MarshalAnyValue(value *otlpcommon.AnyValue) ([]byte, error) { + dest := json.BorrowStream(nil) + defer json.ReturnStream(dest) + internal.MarshalJSONOrigAnyValue(value, dest) + if dest.Error() != nil { + return nil, dest.Error() + } + return slices.Clone(dest.Buffer()), nil +} + +type JSONUnmarshaler struct{} + +func (*JSONMarshaler) UnmarshalAnyValue(buf []byte) (*otlpcommon.AnyValue, error) { + iter := json.BorrowIterator(buf) + defer json.ReturnIterator(iter) + value := &otlpcommon.AnyValue{} + internal.UnmarshalJSONOrigAnyValue(value, iter) + if iter.Error() != nil { + return nil, iter.Error() + } + return value, nil +} diff --git a/pdata/ptrace/json.go b/pdata/ptrace/json.go index 776583c0e995..1c1cab317dda 100644 --- a/pdata/ptrace/json.go +++ b/pdata/ptrace/json.go @@ -7,7 +7,6 @@ import ( "slices" "go.opentelemetry.io/collector/pdata/internal" - otlpcommon "go.opentelemetry.io/collector/pdata/internal/data/protogen/common/v1" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/otlp" ) @@ -26,16 +25,6 @@ func (*JSONMarshaler) MarshalTraces(td Traces) ([]byte, error) { return slices.Clone(dest.Buffer()), nil } -func (*JSONMarshaler) MarshalAnyValue(value *otlpcommon.AnyValue) ([]byte, error) { - dest := json.BorrowStream(nil) - defer json.ReturnStream(dest) - internal.MarshalJSONOrigAnyValue(value, dest) - if dest.Error() != nil { - return nil, dest.Error() - } - return slices.Clone(dest.Buffer()), nil -} - // JSONUnmarshaler unmarshals OTLP/JSON formatted-bytes to Traces. type JSONUnmarshaler struct{} @@ -51,14 +40,3 @@ func (*JSONUnmarshaler) UnmarshalTraces(buf []byte) (Traces, error) { otlp.MigrateTraces(td.getOrig().ResourceSpans) return td, nil } - -func (*JSONMarshaler) UnmarshalAnyValue(buf []byte) (*otlpcommon.AnyValue, error) { - iter := json.BorrowIterator(buf) - defer json.ReturnIterator(iter) - value := &otlpcommon.AnyValue{} - internal.UnmarshalJSONOrigAnyValue(value, iter) - if iter.Error() != nil { - return nil, iter.Error() - } - return value, nil -} From c0b826d59cc93cb33627aacd976e267f0e7b9af1 Mon Sep 17 00:00:00 2001 From: Mahad Zaryab Date: Tue, 16 Sep 2025 18:08:52 -0400 Subject: [PATCH 03/14] Fix Signed-off-by: Mahad Zaryab --- pdata/pcommon/json.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pdata/pcommon/json.go b/pdata/pcommon/json.go index a3b1a7397fde..8b279f3d5c49 100644 --- a/pdata/pcommon/json.go +++ b/pdata/pcommon/json.go @@ -22,7 +22,7 @@ func (*JSONMarshaler) MarshalAnyValue(value *otlpcommon.AnyValue) ([]byte, error type JSONUnmarshaler struct{} -func (*JSONMarshaler) UnmarshalAnyValue(buf []byte) (*otlpcommon.AnyValue, error) { +func (*JSONUnmarshaler) UnmarshalAnyValue(buf []byte) (*otlpcommon.AnyValue, error) { iter := json.BorrowIterator(buf) defer json.ReturnIterator(iter) value := &otlpcommon.AnyValue{} From 8b89b7a71dbbea31b1de458cfb829131ef64d216 Mon Sep 17 00:00:00 2001 From: Mahad Zaryab Date: Tue, 16 Sep 2025 18:09:22 -0400 Subject: [PATCH 04/14] Add Fuzz Tests Signed-off-by: Mahad Zaryab --- pdata/pcommon/fuzz_test.go | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 pdata/pcommon/fuzz_test.go diff --git a/pdata/pcommon/fuzz_test.go b/pdata/pcommon/fuzz_test.go new file mode 100644 index 000000000000..5219406cc2e9 --- /dev/null +++ b/pdata/pcommon/fuzz_test.go @@ -0,0 +1,32 @@ +package pcommon + +import ( + "bytes" + "testing" + + "github.com/stretchr/testify/require" +) + +var unexpectedBytes = "expected the same bytes from unmarshaling and marshaling." + +func FuzzUnmarshalJSONTraces(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + u1 := &JSONUnmarshaler{} + ld1, err := u1.UnmarshalAnyValue(data) + if err != nil { + return + } + m1 := &JSONMarshaler{} + b1, err := m1.MarshalAnyValue(ld1) + require.NoError(t, err, "failed to marshal valid struct") + + u2 := &JSONUnmarshaler{} + ld2, err := u2.UnmarshalAnyValue(b1) + require.NoError(t, err, "failed to unmarshal valid bytes") + m2 := &JSONMarshaler{} + b2, err := m2.MarshalAnyValue(ld2) + require.NoError(t, err, "failed to marshal valid struct") + + require.True(t, bytes.Equal(b1, b2), "%s. \nexpected %d but got %d\n", unexpectedBytes, b1, b2) + }) +} From d079200db0bcd935bedcbb9ec3e1f079968e7efd Mon Sep 17 00:00:00 2001 From: Mahad Zaryab Date: Tue, 16 Sep 2025 19:16:14 -0400 Subject: [PATCH 05/14] Add License Signed-off-by: Mahad Zaryab --- pdata/pcommon/fuzz_test.go | 3 +++ pdata/pcommon/json.go | 3 +++ 2 files changed, 6 insertions(+) diff --git a/pdata/pcommon/fuzz_test.go b/pdata/pcommon/fuzz_test.go index 5219406cc2e9..c6e28c03ee59 100644 --- a/pdata/pcommon/fuzz_test.go +++ b/pdata/pcommon/fuzz_test.go @@ -1,3 +1,6 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + package pcommon import ( diff --git a/pdata/pcommon/json.go b/pdata/pcommon/json.go index 8b279f3d5c49..6e0abd89065a 100644 --- a/pdata/pcommon/json.go +++ b/pdata/pcommon/json.go @@ -1,3 +1,6 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + package pcommon import ( From 690431d775ff74b71ff154d3840a9b7dc06f6239 Mon Sep 17 00:00:00 2001 From: Mahad Zaryab Date: Tue, 16 Sep 2025 19:16:52 -0400 Subject: [PATCH 06/14] Fix Test Name Signed-off-by: Mahad Zaryab --- pdata/pcommon/fuzz_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pdata/pcommon/fuzz_test.go b/pdata/pcommon/fuzz_test.go index c6e28c03ee59..bf9c35ac3dff 100644 --- a/pdata/pcommon/fuzz_test.go +++ b/pdata/pcommon/fuzz_test.go @@ -12,7 +12,7 @@ import ( var unexpectedBytes = "expected the same bytes from unmarshaling and marshaling." -func FuzzUnmarshalJSONTraces(f *testing.F) { +func FuzzUnmarshalJSONAnyValue(f *testing.F) { f.Fuzz(func(t *testing.T, data []byte) { u1 := &JSONUnmarshaler{} ld1, err := u1.UnmarshalAnyValue(data) From c4939f9b5ed37b21be874f1842a6af9bf6cd1f07 Mon Sep 17 00:00:00 2001 From: Mahad Zaryab Date: Tue, 16 Sep 2025 19:20:22 -0400 Subject: [PATCH 07/14] Add Changelog Signed-off-by: Mahad Zaryab --- .chloggen/any-value.yaml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 .chloggen/any-value.yaml diff --git a/.chloggen/any-value.yaml b/.chloggen/any-value.yaml new file mode 100644 index 000000000000..3e6c50039475 --- /dev/null +++ b/.chloggen/any-value.yaml @@ -0,0 +1,25 @@ +# Use this changelog template to create an entry for release notes. + +# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' +change_type: + +# The name of the component, or a single word describing the area of concern, (e.g. otlpreceiver) +component: + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: + +# One or more tracking issues or pull requests related to the change +issues: [] + +# (Optional) One or more lines of additional information to render under the primary note. +# These lines will be padded with 2 spaces and then inserted directly into the document. +# Use pipe (|) for multiline entries. +subtext: + +# Optional: The change log or logs in which this entry should be included. +# e.g. '[user]' or '[user, api]' +# Include 'user' if the change is relevant to end users. +# Include 'api' if there is a change to a library API. +# Default: '[user]' +change_logs: [] From 58245e3d0d6589f90c09c01ea4c0dfc5a0ce4a42 Mon Sep 17 00:00:00 2001 From: Mahad Zaryab Date: Tue, 16 Sep 2025 19:20:34 -0400 Subject: [PATCH 08/14] Update Changelog Signed-off-by: Mahad Zaryab --- .chloggen/any-value.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.chloggen/any-value.yaml b/.chloggen/any-value.yaml index 3e6c50039475..955bdeafed5c 100644 --- a/.chloggen/any-value.yaml +++ b/.chloggen/any-value.yaml @@ -1,16 +1,16 @@ # Use this changelog template to create an entry for release notes. # One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' -change_type: +change_type: enhancement # The name of the component, or a single word describing the area of concern, (e.g. otlpreceiver) -component: +component: pcommon # A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). -note: +note: Add Serialization and Deserialization of AnyValue # One or more tracking issues or pull requests related to the change -issues: [] +issues: [12826] # (Optional) One or more lines of additional information to render under the primary note. # These lines will be padded with 2 spaces and then inserted directly into the document. From 24df39fc2a7db384d7a443f097dbe88f64a3b191 Mon Sep 17 00:00:00 2001 From: Mahad Zaryab Date: Tue, 16 Sep 2025 19:23:05 -0400 Subject: [PATCH 09/14] make goporto Signed-off-by: Mahad Zaryab --- pdata/pcommon/json.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pdata/pcommon/json.go b/pdata/pcommon/json.go index 6e0abd89065a..c49b006c5419 100644 --- a/pdata/pcommon/json.go +++ b/pdata/pcommon/json.go @@ -1,7 +1,7 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 -package pcommon +package pcommon // import "go.opentelemetry.io/collector/pdata/pcommon" import ( "slices" From 339d3a9984430ef4fac3197cbc6e15a0116a83a7 Mon Sep 17 00:00:00 2001 From: Mahad Zaryab Date: Thu, 18 Sep 2025 08:16:58 -0400 Subject: [PATCH 10/14] Address Feedback Signed-off-by: Mahad Zaryab --- pdata/{pcommon => xpdata}/fuzz_test.go | 2 +- pdata/{pcommon => xpdata}/json.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename pdata/{pcommon => xpdata}/fuzz_test.go (98%) rename pdata/{pcommon => xpdata}/json.go (92%) diff --git a/pdata/pcommon/fuzz_test.go b/pdata/xpdata/fuzz_test.go similarity index 98% rename from pdata/pcommon/fuzz_test.go rename to pdata/xpdata/fuzz_test.go index bf9c35ac3dff..aa1131dad063 100644 --- a/pdata/pcommon/fuzz_test.go +++ b/pdata/xpdata/fuzz_test.go @@ -1,7 +1,7 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 -package pcommon +package xpdata import ( "bytes" diff --git a/pdata/pcommon/json.go b/pdata/xpdata/json.go similarity index 92% rename from pdata/pcommon/json.go rename to pdata/xpdata/json.go index c49b006c5419..247e81186b0b 100644 --- a/pdata/pcommon/json.go +++ b/pdata/xpdata/json.go @@ -1,7 +1,7 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 -package pcommon // import "go.opentelemetry.io/collector/pdata/pcommon" +package xpdata // import "go.opentelemetry.io/collector/pdata/xpdata" import ( "slices" From 043d8620b82be2fb763cff260459d5d8f5e027f1 Mon Sep 17 00:00:00 2001 From: Mahad Zaryab Date: Thu, 18 Sep 2025 08:17:28 -0400 Subject: [PATCH 11/14] Update Changelog Signed-off-by: Mahad Zaryab --- .chloggen/any-value.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.chloggen/any-value.yaml b/.chloggen/any-value.yaml index 955bdeafed5c..c177c1068659 100644 --- a/.chloggen/any-value.yaml +++ b/.chloggen/any-value.yaml @@ -4,7 +4,7 @@ change_type: enhancement # The name of the component, or a single word describing the area of concern, (e.g. otlpreceiver) -component: pcommon +component: xpdata # A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). note: Add Serialization and Deserialization of AnyValue From ecf526c9ea668288bf736c7a6163ef36c3c1a509 Mon Sep 17 00:00:00 2001 From: Mahad Zaryab Date: Thu, 18 Sep 2025 08:39:15 -0400 Subject: [PATCH 12/14] Add Unit Tests Signed-off-by: Mahad Zaryab --- pdata/xpdata/json_test.go | 46 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 pdata/xpdata/json_test.go diff --git a/pdata/xpdata/json_test.go b/pdata/xpdata/json_test.go new file mode 100644 index 000000000000..e1fec3aaa088 --- /dev/null +++ b/pdata/xpdata/json_test.go @@ -0,0 +1,46 @@ +package xpdata + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "go.opentelemetry.io/collector/pdata/internal" + otlpcommon "go.opentelemetry.io/collector/pdata/internal/data/protogen/common/v1" +) + +func TestMarshalAndUnmarshalAnyValue(t *testing.T) { + for name, src := range genTestEncodingValuesAnyValue() { + t.Run(name, func(t *testing.T) { + m := &JSONMarshaler{} + b, err := m.MarshalAnyValue(src) + require.NoError(t, err) + + u := &JSONUnmarshaler{} + dest, err := u.UnmarshalAnyValue(b) + require.NoError(t, err) + + require.Equal(t, src, dest) + }) + } +} + +func genTestEncodingValuesAnyValue() map[string]*otlpcommon.AnyValue { + return map[string]*otlpcommon.AnyValue{ + "empty": internal.NewOrigAnyValue(), + "StringValue/default": {Value: &otlpcommon.AnyValue_StringValue{StringValue: ""}}, + "StringValue/test": {Value: &otlpcommon.AnyValue_StringValue{StringValue: "test_stringvalue"}}, + "BoolValue/default": {Value: &otlpcommon.AnyValue_BoolValue{BoolValue: false}}, + "BoolValue/test": {Value: &otlpcommon.AnyValue_BoolValue{BoolValue: true}}, + "IntValue/default": {Value: &otlpcommon.AnyValue_IntValue{IntValue: int64(0)}}, + "IntValue/test": {Value: &otlpcommon.AnyValue_IntValue{IntValue: int64(13)}}, + "DoubleValue/default": {Value: &otlpcommon.AnyValue_DoubleValue{DoubleValue: float64(0)}}, + "DoubleValue/test": {Value: &otlpcommon.AnyValue_DoubleValue{DoubleValue: float64(3.1415926)}}, + "ArrayValue/default": {Value: &otlpcommon.AnyValue_ArrayValue{ArrayValue: &otlpcommon.ArrayValue{}}}, + "ArrayValue/test": {Value: &otlpcommon.AnyValue_ArrayValue{ArrayValue: internal.GenTestOrigArrayValue()}}, + "KvlistValue/default": {Value: &otlpcommon.AnyValue_KvlistValue{KvlistValue: &otlpcommon.KeyValueList{}}}, + "KvlistValue/test": {Value: &otlpcommon.AnyValue_KvlistValue{KvlistValue: internal.GenTestOrigKeyValueList()}}, + "BytesValue/default": {Value: &otlpcommon.AnyValue_BytesValue{BytesValue: nil}}, + "BytesValue/test": {Value: &otlpcommon.AnyValue_BytesValue{BytesValue: []byte{1, 2, 3}}}, + } +} From f950d8d2175fd0270c5adfabb600b9a57af5e507 Mon Sep 17 00:00:00 2001 From: Mahad Zaryab Date: Thu, 18 Sep 2025 08:43:47 -0400 Subject: [PATCH 13/14] Add Test For Unmarshalling Unknown AnyValue Signed-off-by: Mahad Zaryab --- pdata/xpdata/json_test.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/pdata/xpdata/json_test.go b/pdata/xpdata/json_test.go index e1fec3aaa088..d7b48e94a7d3 100644 --- a/pdata/xpdata/json_test.go +++ b/pdata/xpdata/json_test.go @@ -3,6 +3,7 @@ package xpdata import ( "testing" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/pdata/internal" @@ -25,6 +26,14 @@ func TestMarshalAndUnmarshalAnyValue(t *testing.T) { } } +func TestUnmarshalAnyValueUnknown(t *testing.T) { + m := &JSONUnmarshaler{} + + b, err := m.UnmarshalAnyValue([]byte(`{"unknown": "string"}`)) + require.NoError(t, err) + assert.Equal(t, internal.NewOrigAnyValue(), b) +} + func genTestEncodingValuesAnyValue() map[string]*otlpcommon.AnyValue { return map[string]*otlpcommon.AnyValue{ "empty": internal.NewOrigAnyValue(), From 6c7de3bf45232583dafbf4d808468324716c2e0b Mon Sep 17 00:00:00 2001 From: Mahad Zaryab Date: Thu, 18 Sep 2025 08:46:03 -0400 Subject: [PATCH 14/14] Add License Signed-off-by: Mahad Zaryab --- pdata/xpdata/json_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pdata/xpdata/json_test.go b/pdata/xpdata/json_test.go index d7b48e94a7d3..ce6ce7a77357 100644 --- a/pdata/xpdata/json_test.go +++ b/pdata/xpdata/json_test.go @@ -1,3 +1,6 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + package xpdata import (