From acb350b8f314c225821a10523d9db09573b00870 Mon Sep 17 00:00:00 2001 From: Joshua MacDonald Date: Wed, 22 Apr 2020 14:32:58 -0700 Subject: [PATCH] Support JSON marshal of Resources (#654) * Support JSON marshal of Resources * Add a test * Another test * Fix arch bug * Fix other test --- api/core/key.go | 24 ++++++++++++------------ api/core/key_test.go | 16 ++++++++++++++++ exporters/trace/stdout/stdout.go | 12 ------------ exporters/trace/stdout/stdout_test.go | 13 ++++++------- sdk/resource/resource.go | 6 ++++++ sdk/resource/resource_test.go | 11 +++++++++++ 6 files changed, 51 insertions(+), 31 deletions(-) diff --git a/api/core/key.go b/api/core/key.go index 5efa4a8dbc1..45fec60ed8e 100644 --- a/api/core/key.go +++ b/api/core/key.go @@ -276,62 +276,62 @@ func (k Key) Defined() bool { } // Type returns a type of the Value. -func (v *Value) Type() ValueType { +func (v Value) Type() ValueType { return v.vtype } // AsBool returns the bool value. Make sure that the Value's type is // BOOL. -func (v *Value) AsBool() bool { +func (v Value) AsBool() bool { return rawToBool(v.numeric) } // AsInt32 returns the int32 value. Make sure that the Value's type is // INT32. -func (v *Value) AsInt32() int32 { +func (v Value) AsInt32() int32 { return rawToInt32(v.numeric) } // AsInt64 returns the int64 value. Make sure that the Value's type is // INT64. -func (v *Value) AsInt64() int64 { +func (v Value) AsInt64() int64 { return rawToInt64(v.numeric) } // AsUint32 returns the uint32 value. Make sure that the Value's type // is UINT32. -func (v *Value) AsUint32() uint32 { +func (v Value) AsUint32() uint32 { return rawToUint32(v.numeric) } // AsUint64 returns the uint64 value. Make sure that the Value's type is // UINT64. -func (v *Value) AsUint64() uint64 { +func (v Value) AsUint64() uint64 { return rawToUint64(v.numeric) } // AsFloat32 returns the float32 value. Make sure that the Value's // type is FLOAT32. -func (v *Value) AsFloat32() float32 { +func (v Value) AsFloat32() float32 { return rawToFloat32(v.numeric) } // AsFloat64 returns the float64 value. Make sure that the Value's // type is FLOAT64. -func (v *Value) AsFloat64() float64 { +func (v Value) AsFloat64() float64 { return rawToFloat64(v.numeric) } // AsString returns the string value. Make sure that the Value's type // is STRING. -func (v *Value) AsString() string { +func (v Value) AsString() string { return v.stringly } type unknownValueType struct{} // AsInterface returns Value's data as interface{}. -func (v *Value) AsInterface() interface{} { +func (v Value) AsInterface() interface{} { switch v.Type() { case BOOL: return v.AsBool() @@ -354,7 +354,7 @@ func (v *Value) AsInterface() interface{} { } // Emit returns a string representation of Value's data. -func (v *Value) Emit() string { +func (v Value) Emit() string { switch v.Type() { case BOOL: return strconv.FormatBool(v.AsBool()) @@ -378,7 +378,7 @@ func (v *Value) Emit() string { } // MarshalJSON returns the JSON encoding of the Value. -func (v *Value) MarshalJSON() ([]byte, error) { +func (v Value) MarshalJSON() ([]byte, error) { var jsonVal struct { Type string Value interface{} diff --git a/api/core/key_test.go b/api/core/key_test.go index 3a5b9ef5c8d..8c5f4b9ff76 100644 --- a/api/core/key_test.go +++ b/api/core/key_test.go @@ -15,12 +15,15 @@ package core_test import ( + "encoding/json" "testing" "unsafe" "github.com/google/go-cmp/cmp" + "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/api/core" + "go.opentelemetry.io/otel/api/key" ) func TestValue(t *testing.T) { @@ -161,6 +164,19 @@ func TestDefined(t *testing.T) { } } +func TestJSONValue(t *testing.T) { + var kvs interface{} = [2]core.KeyValue{ + key.String("A", "B"), + key.Int64("C", 1), + } + + data, err := json.Marshal(kvs) + require.NoError(t, err) + require.Equal(t, + `[{"Key":"A","Value":{"Type":"STRING","Value":"B"}},{"Key":"C","Value":{"Type":"INT64","Value":1}}]`, + string(data)) +} + func TestEmit(t *testing.T) { for _, testcase := range []struct { name string diff --git a/exporters/trace/stdout/stdout.go b/exporters/trace/stdout/stdout.go index b78461a36cb..29f3d0eff04 100644 --- a/exporters/trace/stdout/stdout.go +++ b/exporters/trace/stdout/stdout.go @@ -51,18 +51,6 @@ func NewExporter(o Options) (*Exporter, error) { // ExportSpan writes a SpanData in json format to stdout. func (e *Exporter) ExportSpan(ctx context.Context, data *export.SpanData) { - if data.Resource != nil { - dataCopy := *data - dataCopy.Attributes = append(data.Attributes, data.Resource.Attributes()...) - dataCopy.Resource = nil - e.exportSpan(ctx, &dataCopy) - } else { - e.exportSpan(ctx, data) - } -} - -// ExportSpan writes a SpanData in json format to stdout. -func (e *Exporter) exportSpan(ctx context.Context, data *export.SpanData) { var jsonSpan []byte var err error if e.pretty { diff --git a/exporters/trace/stdout/stdout_test.go b/exporters/trace/stdout/stdout_test.go index ee5d5415d1f..714b28fa3d5 100644 --- a/exporters/trace/stdout/stdout_test.go +++ b/exporters/trace/stdout/stdout_test.go @@ -88,12 +88,7 @@ func TestExporter_ExportSpan(t *testing.T) { `{` + `"Key":"double",` + `"Value":{"Type":"FLOAT64","Value":123.456}` + - `},` + - `{` + - `"Key":"rk1",` + - `"Value":{"Type":"STRING","Value":"rv11"}` + - `}` + - `],` + + `}],` + `"MessageEvents":[` + `{` + `"Name":"foo",` + @@ -124,7 +119,11 @@ func TestExporter_ExportSpan(t *testing.T) { `"DroppedMessageEventCount":0,` + `"DroppedLinkCount":0,` + `"ChildSpanCount":0,` + - `"Resource":null}` + "\n" + `"Resource":[` + + `{` + + `"Key":"rk1",` + + `"Value":{"Type":"STRING","Value":"rv11"}` + + `}]}` + "\n" if got != expectedOutput { t.Errorf("Want: %v but got: %v", expectedOutput, got) diff --git a/sdk/resource/resource.go b/sdk/resource/resource.go index 5b6eb8822ab..ab6b0c95e8b 100644 --- a/sdk/resource/resource.go +++ b/sdk/resource/resource.go @@ -17,6 +17,7 @@ package resource import ( + "encoding/json" "sort" "strings" @@ -109,3 +110,8 @@ func Merge(a, b *Resource) *Resource { kvs = append(kvs, b.sorted...) return New(kvs...) } + +// MarshalJSON prints the resource attributes in sorted order. +func (r Resource) MarshalJSON() ([]byte, error) { + return json.Marshal(r.sorted) +} diff --git a/sdk/resource/resource_test.go b/sdk/resource/resource_test.go index 7cb656bd9b1..9f2203ea24a 100644 --- a/sdk/resource/resource_test.go +++ b/sdk/resource/resource_test.go @@ -15,10 +15,12 @@ package resource_test import ( + "encoding/json" "fmt" "testing" "github.com/google/go-cmp/cmp" + "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/api/core" "go.opentelemetry.io/otel/api/key" @@ -211,3 +213,12 @@ func TestString(t *testing.T) { } } } + +func TestMarshalJSON(t *testing.T) { + r := resource.New(key.Int64("A", 1), key.String("C", "D")) + data, err := json.Marshal(r) + require.NoError(t, err) + require.Equal(t, + `[{"Key":"A","Value":{"Type":"INT64","Value":1}},{"Key":"C","Value":{"Type":"STRING","Value":"D"}}]`, + string(data)) +}