diff --git a/CHANGELOG.md b/CHANGELOG.md index d3e95838520..00235a1e28f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -51,6 +51,10 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm - Improve performance of baggage member character validation in `go.opentelemetry.io/otel/baggage`. (#5214) - The `otel-collector` example now uses docker compose to bring up services instead of kubernetes. (#5244) +### Fixed + +- Slice attribute values in `go.opentelemetry.io/otel/attribute` are now emitted as their JSON representation. (#5159) + ## [1.25.0/0.47.0/0.0.8/0.1.0-alpha] 2024-04-05 ### Added diff --git a/attribute/key_test.go b/attribute/key_test.go index 45de9d81817..d0f1b042f79 100644 --- a/attribute/key_test.go +++ b/attribute/key_test.go @@ -63,11 +63,21 @@ func TestEmit(t *testing.T) { v: attribute.BoolValue(true), want: "true", }, + { + name: `test Key.Emit() can emit a string representing self.INT64SLICE`, + v: attribute.Int64SliceValue([]int64{1, 42}), + want: `[1,42]`, + }, { name: `test Key.Emit() can emit a string representing self.INT64`, v: attribute.Int64Value(42), want: "42", }, + { + name: `test Key.Emit() can emit a string representing self.FLOAT64SLICE`, + v: attribute.Float64SliceValue([]float64{1.0, 42.5}), + want: `[1,42.5]`, + }, { name: `test Key.Emit() can emit a string representing self.FLOAT64`, v: attribute.Float64Value(42.1), @@ -78,6 +88,11 @@ func TestEmit(t *testing.T) { v: attribute.StringValue("foo"), want: "foo", }, + { + name: `test Key.Emit() can emit a string representing self.STRINGSLICE`, + v: attribute.StringSliceValue([]string{"foo", "bar"}), + want: `["foo","bar"]`, + }, } { t.Run(testcase.name, func(t *testing.T) { // proto: func (v attribute.Value) Emit() string { diff --git a/attribute/value.go b/attribute/value.go index b320314133a..9ea0ecbbd27 100644 --- a/attribute/value.go +++ b/attribute/value.go @@ -231,15 +231,27 @@ func (v Value) Emit() string { case BOOL: return strconv.FormatBool(v.AsBool()) case INT64SLICE: - return fmt.Sprint(v.asInt64Slice()) + j, err := json.Marshal(v.asInt64Slice()) + if err != nil { + return fmt.Sprintf("invalid: %v", v.asInt64Slice()) + } + return string(j) case INT64: return strconv.FormatInt(v.AsInt64(), 10) case FLOAT64SLICE: - return fmt.Sprint(v.asFloat64Slice()) + j, err := json.Marshal(v.asFloat64Slice()) + if err != nil { + return fmt.Sprintf("invalid: %v", v.asFloat64Slice()) + } + return string(j) case FLOAT64: return fmt.Sprint(v.AsFloat64()) case STRINGSLICE: - return fmt.Sprint(v.asStringSlice()) + j, err := json.Marshal(v.asStringSlice()) + if err != nil { + return fmt.Sprintf("invalid: %v", v.asStringSlice()) + } + return string(j) case STRING: return v.stringly default: diff --git a/sdk/resource/resource_test.go b/sdk/resource/resource_test.go index 8bf3fa1ac6b..85e29087b0a 100644 --- a/sdk/resource/resource_test.go +++ b/sdk/resource/resource_test.go @@ -601,8 +601,9 @@ func TestWithProcessCommandArgs(t *testing.T) { ) require.NoError(t, err) + jsonCommandArgs, _ := json.Marshal(fakeCommandArgs) require.EqualValues(t, map[string]string{ - "process.command_args": fmt.Sprint(fakeCommandArgs), + "process.command_args": string(jsonCommandArgs), }, toMap(res)) } @@ -671,11 +672,12 @@ func TestWithProcess(t *testing.T) { ) require.NoError(t, err) + jsonCommandArgs, _ := json.Marshal(fakeCommandArgs) require.EqualValues(t, map[string]string{ "process.pid": fmt.Sprint(fakePID), "process.executable.name": fakeExecutableName, "process.executable.path": fakeExecutablePath, - "process.command_args": fmt.Sprint(fakeCommandArgs), + "process.command_args": string(jsonCommandArgs), "process.owner": fakeOwner, "process.runtime.name": fakeRuntimeName, "process.runtime.version": fakeRuntimeVersion,