-
Notifications
You must be signed in to change notification settings - Fork 419
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge remote-tracking branch 'origin/main' into v2-dev
- Loading branch information
Showing
56 changed files
with
1,404 additions
and
305 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
// Unless explicitly stated otherwise all files in this repository are licensed | ||
// under the Apache License Version 2.0. | ||
// This product includes software developed at Datadog (https://www.datadoghq.com/). | ||
// Copyright 2016 Datadog, Inc. | ||
|
||
package tracer | ||
|
||
import ( | ||
"github.com/tinylib/msgp/msgp" | ||
) | ||
|
||
var ( | ||
_ msgp.Encodable = (*metaStructMap)(nil) | ||
_ msgp.Decodable = (*metaStructMap)(nil) | ||
_ msgp.Sizer = (*metaStructMap)(nil) | ||
) | ||
|
||
// metaStructMap is a map of string to any of metadata embedded in each span | ||
// We export special messagepack methods to handle the encoding and decoding of the map | ||
// Because the agent expects the metadata to be a map of string to byte array, we have to create sub-messages of messagepack for each value | ||
type metaStructMap map[string]any | ||
|
||
// EncodeMsg transforms the map[string]any into a map[string][]byte agent-side (which is parsed back into a map[string]any in the backend) | ||
func (m *metaStructMap) EncodeMsg(en *msgp.Writer) error { | ||
err := en.WriteMapHeader(uint32(len(*m))) | ||
if err != nil { | ||
return msgp.WrapError(err, "MetaStruct") | ||
} | ||
|
||
for key, value := range *m { | ||
err = en.WriteString(key) | ||
if err != nil { | ||
return msgp.WrapError(err, "MetaStruct") | ||
} | ||
|
||
// Wrap the encoded value in a byte array that will not be parsed by the agent | ||
msg, err := msgp.AppendIntf(nil, value) | ||
if err != nil { | ||
return msgp.WrapError(err, "MetaStruct", key) | ||
} | ||
|
||
err = en.WriteBytes(msg) | ||
if err != nil { | ||
return msgp.WrapError(err, "MetaStruct", key) | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
|
||
// DecodeMsg transforms the map[string][]byte agent-side into a map[string]any where values are sub-messages in messagepack | ||
func (m *metaStructMap) DecodeMsg(de *msgp.Reader) error { | ||
header, err := de.ReadMapHeader() | ||
if err != nil { | ||
return msgp.WrapError(err, "MetaStruct") | ||
} | ||
|
||
*m = make(metaStructMap, header) | ||
for i := uint32(0); i < header; i++ { | ||
var key string | ||
key, err = de.ReadString() | ||
if err != nil { | ||
return msgp.WrapError(err, "MetaStruct") | ||
} | ||
|
||
subMsg, err := de.ReadBytes(nil) | ||
if err != nil { | ||
return msgp.WrapError(err, "MetaStruct", key) | ||
} | ||
|
||
(*m)[key], _, err = msgp.ReadIntfBytes(subMsg) | ||
if err != nil { | ||
return msgp.WrapError(err, "MetaStruct", key) | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
|
||
// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message | ||
func (m *metaStructMap) Msgsize() int { | ||
size := msgp.MapHeaderSize | ||
for key, value := range *m { | ||
size += msgp.StringPrefixSize + len(key) | ||
size += msgp.BytesPrefixSize + msgp.GuessSize(value) | ||
} | ||
return size | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,158 @@ | ||
// Unless explicitly stated otherwise all files in this repository are licensed | ||
// under the Apache License Version 2.0. | ||
// This product includes software developed at Datadog (https://www.datadoghq.com/). | ||
// Copyright 2016 Datadog, Inc. | ||
|
||
package tracer | ||
|
||
import ( | ||
"bytes" | ||
"errors" | ||
"github.com/stretchr/testify/require" | ||
"reflect" | ||
"testing" | ||
|
||
"github.com/tinylib/msgp/msgp" | ||
) | ||
|
||
type badWriter struct{} | ||
|
||
func (bw *badWriter) Write(_ []byte) (n int, err error) { | ||
return 0, errors.New("bad writer error") | ||
} | ||
|
||
func TestMetaStructMap_EncodeDecode(t *testing.T) { | ||
// Create a sample metaStructMap | ||
meta := map[string]any{ | ||
"key1": "value1", | ||
"key2": "value2", | ||
} | ||
|
||
for _, tc := range []struct { | ||
name string | ||
input metaStructMap | ||
encodingError error | ||
output map[string]any | ||
decodingError error | ||
}{ | ||
{ | ||
name: "empty", | ||
input: metaStructMap{}, | ||
output: map[string]any{}, | ||
}, | ||
{ | ||
name: "non-empty", | ||
input: meta, | ||
output: meta, | ||
}, | ||
{ | ||
name: "nil", | ||
input: nil, | ||
output: nil, | ||
}, | ||
{ | ||
name: "nested-map", | ||
input: metaStructMap{ | ||
"key": map[string]any{ | ||
"nested-key": "nested-value", | ||
}, | ||
}, | ||
output: map[string]any{ | ||
"key": map[string]any{ | ||
"nested-key": "nested-value", | ||
}, | ||
}, | ||
}, | ||
{ | ||
name: "nested-slice", | ||
input: metaStructMap{ | ||
"key": []any{ | ||
"nested-value", | ||
}, | ||
}, | ||
output: map[string]any{ | ||
"key": []any{ | ||
"nested-value", | ||
}, | ||
}, | ||
}, | ||
{ | ||
name: "encoding-error/nested-chan", | ||
input: metaStructMap{ | ||
"key": map[string]any{ | ||
"nested-key": make(chan struct{}), | ||
}, | ||
}, | ||
encodingError: errors.New("msgp: type \"chan struct {}\" not supported at MetaStruct/key"), | ||
}, | ||
{ | ||
name: "encoding-error/channel", | ||
input: metaStructMap{ | ||
"key": make(chan struct{}), | ||
}, | ||
encodingError: errors.New("msgp: type \"chan struct {}\" not supported at MetaStruct/key"), | ||
}, | ||
{ | ||
name: "encoding-error/func", | ||
input: metaStructMap{ | ||
"key": func() {}, | ||
}, | ||
encodingError: errors.New("msgp: type \"func()\" not supported at MetaStruct/key"), | ||
}, | ||
} { | ||
t.Run(tc.name+"/serdes", func(t *testing.T) { | ||
// Encode the metaStructMap | ||
var buf bytes.Buffer | ||
enc := msgp.NewWriter(&buf) | ||
err := tc.input.EncodeMsg(enc) | ||
require.NoError(t, enc.Flush()) | ||
if tc.encodingError != nil { | ||
require.EqualError(t, err, tc.encodingError.Error()) | ||
return | ||
} | ||
|
||
require.NoError(t, err) | ||
require.NoError(t, enc.Flush()) | ||
|
||
// Decode the encoded metaStructMap | ||
dec := msgp.NewReader(bytes.NewReader(buf.Bytes())) | ||
var decodedMeta metaStructMap | ||
err = decodedMeta.DecodeMsg(dec) | ||
if tc.decodingError != nil { | ||
require.EqualError(t, err, tc.decodingError.Error()) | ||
return | ||
} | ||
|
||
require.NoError(t, err) | ||
|
||
// Compare the original and decoded metaStructMap | ||
compareMetaStructMaps(t, tc.output, decodedMeta) | ||
}) | ||
|
||
t.Run(tc.name+"/bad-writer", func(t *testing.T) { | ||
// Encode the metaStructMap | ||
enc := msgp.NewWriter(&badWriter{}) | ||
err := tc.input.EncodeMsg(enc) | ||
|
||
if tc.encodingError != nil { | ||
require.EqualError(t, err, tc.encodingError.Error()) | ||
return | ||
} | ||
|
||
require.EqualError(t, enc.Flush(), "bad writer error") | ||
}) | ||
} | ||
} | ||
|
||
func compareMetaStructMaps(t *testing.T, m1, m2 metaStructMap) { | ||
require.Equal(t, len(m1), len(m2), "mismatched map lengths: %d != %d", len(m1), len(m2)) | ||
|
||
for k, v := range m1 { | ||
m2v, ok := m2[k] | ||
require.Truef(t, ok, "missing key %s", k) | ||
|
||
if !reflect.DeepEqual(v, m2v) { | ||
require.Fail(t, "compareMetaStructMaps", "mismatched key %s: expected '%v' but got '%v'", k, v, m2v) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.