Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into v2-dev
Browse files Browse the repository at this point in the history
  • Loading branch information
darccio committed Apr 8, 2024
1 parent be6407b commit 8d1ea11
Show file tree
Hide file tree
Showing 56 changed files with 1,404 additions and 305 deletions.
6 changes: 3 additions & 3 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ stages:
- test-apps

variables:
# This base image is created here: https://gitlab.ddbuild.io/DataDog/apm-reliability/benchmarking-platform/-/pipelines/30087677
BASE_CI_IMAGE: 486234852809.dkr.ecr.us-east-1.amazonaws.com/ci/benchmarking-platform:dd-trace-go-30087677
# This base image is created here: https://gitlab.ddbuild.io/DataDog/apm-reliability/benchmarking-platform/-/pipelines/30723596
BASE_CI_IMAGE: 486234852809.dkr.ecr.us-east-1.amazonaws.com/ci/benchmarking-platform:dd-trace-go-30723596
INDEX_FILE: index.txt
KUBERNETES_SERVICE_ACCOUNT_OVERWRITE: dd-trace-go
FF_USE_LEGACY_KUBERNETES_EXECUTION_STRATEGY: "true"
BENCHMARK_TARGETS: "BenchmarkStartRequestSpan|BenchmarkHttpServeTrace|BenchmarkTracerAddSpans|BenchmarkStartSpan|BenchmarkSingleSpanRetention|BenchmarkOTelApiWithCustomTags|BenchmarkInjectW3C|BenchmarkExtractW3C|BenchmarkPartialFlushing|BenchmarkConfig|BenchmarkStartSpanConfig|BenchmarkGraphQL"
BENCHMARK_TARGETS: "BenchmarkStartRequestSpan|BenchmarkHttpServeTrace|BenchmarkTracerAddSpans|BenchmarkStartSpan|BenchmarkSingleSpanRetention|BenchmarkOTelApiWithCustomTags|BenchmarkInjectW3C|BenchmarkExtractW3C|BenchmarkPartialFlushing|BenchmarkConfig|BenchmarkStartSpanConfig|BenchmarkGraphQL|BenchmarkSampleWAFContext"

include:
- ".gitlab/benchmarks.yml"
Expand Down
88 changes: 88 additions & 0 deletions ddtrace/tracer/meta_struct.go
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
}
158 changes: 158 additions & 0 deletions ddtrace/tracer/meta_struct_test.go
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)
}
}
}
9 changes: 5 additions & 4 deletions ddtrace/tracer/option.go
Original file line number Diff line number Diff line change
Expand Up @@ -707,12 +707,8 @@ func (c *config) canDropP0s() bool {
func statsTags(c *config) []string {
tags := []string{
"lang:go",
"version:" + version.Tag,
"lang_version:" + runtime.Version(),
}
if c.serviceName != "" {
tags = append(tags, "service:"+c.serviceName)
}
if c.env != "" {
tags = append(tags, "env:"+c.env)
}
Expand All @@ -724,6 +720,11 @@ func statsTags(c *config) []string {
tags = append(tags, k+":"+vstr)
}
}
globalconfig.SetStatsTags(tags)
tags = append(tags, version.Tag)
if c.serviceName != "" {
tags = append(tags, "service:"+c.serviceName)
}
return tags
}

Expand Down
11 changes: 11 additions & 0 deletions ddtrace/tracer/option_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import (
"github.com/DataDog/dd-trace-go/v2/internal/log"
"github.com/DataDog/dd-trace-go/v2/internal/namingschema"
"github.com/DataDog/dd-trace-go/v2/internal/traceprof"
"github.com/DataDog/dd-trace-go/v2/internal/version"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -1255,6 +1256,16 @@ func TestStatsTags(t *testing.T) {
assert.Contains(tags, "service:serviceName")
assert.Contains(tags, "env:envName")
assert.Contains(tags, "host:hostName")

st := globalconfig.StatsTags()
// all of the tracer tags except `service` and `version` should be on `st`
assert.Len(st, len(tags)-2)
assert.Contains(st, "env:envName")
assert.Contains(st, "host:hostName")
assert.Contains(st, "lang:go")
assert.Contains(st, "lang_version:"+runtime.Version())
assert.NotContains(st, "version:"+version.Tag)
assert.NotContains(st, "service:serviceName")
}

func TestGlobalTag(t *testing.T) {
Expand Down
4 changes: 4 additions & 0 deletions ddtrace/tracer/remote_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,10 @@ func (t *tracer) onRemoteConfigUpdate(u remoteconfig.ProductUpdate) map[string]s
if updated {
telemConfigs = append(telemConfigs, t.config.traceSampleRate.toTelemetry())
}
updated = t.config.traceSampleRules.reset()
if updated {
telemConfigs = append(telemConfigs, t.config.traceSampleRules.toTelemetry())
}
updated = t.config.headerAsTags.reset()
if updated {
telemConfigs = append(telemConfigs, t.config.headerAsTags.toTelemetry())
Expand Down
Loading

0 comments on commit 8d1ea11

Please sign in to comment.