Skip to content

Commit

Permalink
tracer: handle rc deletion in dynamic config
Browse files Browse the repository at this point in the history
  • Loading branch information
ahmed-mez committed Dec 27, 2023
1 parent f986cc5 commit 67e0c5a
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 1 deletion.
37 changes: 36 additions & 1 deletion ddtrace/tracer/remote_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,45 @@ func (t *tags) toMap() *map[string]interface{} {
// onRemoteConfigUpdate is a remote config callaback responsible for processing APM_TRACING RC-product updates.
func (t *tracer) onRemoteConfigUpdate(u remoteconfig.ProductUpdate) map[string]state.ApplyStatus {
statuses := map[string]state.ApplyStatus{}
if u == nil {
if len(u) == 0 {
return statuses
}
removed := func() bool {
// Returns true if all the values in the update are nil.
for _, raw := range u {
if raw != nil {
return false
}
}
return true
}
var telemConfigs []telemetry.Configuration
if removed() {
// The remote-config client is signaling that the configuration has been deleted for this product.
// We re-apply the startup configuration values.
for path := range u {
log.Debug("Nil payload from RC. Path: %s.", path)
statuses[path] = state.ApplyStatus{State: state.ApplyStateAcknowledged}
}
log.Debug("Resetting configurations")
updated := t.config.traceSampleRate.reset()
if updated {
telemConfigs = append(telemConfigs, t.config.traceSampleRate.toTelemetry())
}
updated = t.config.headerAsTags.reset()
if updated {
telemConfigs = append(telemConfigs, t.config.headerAsTags.toTelemetry())
}
updated = t.config.globalTags.reset()
if updated {
telemConfigs = append(telemConfigs, t.config.globalTags.toTelemetry())
}
if len(telemConfigs) > 0 {
log.Debug("Reporting %d configuration changes to telemetry", len(telemConfigs))
telemetry.GlobalClient.ConfigChange(telemConfigs)
}
return statuses
}
for path, raw := range u {
if raw == nil {
continue
Expand Down
50 changes: 50 additions & 0 deletions ddtrace/tracer/remote_config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,56 @@ func TestOnRemoteConfigUpdate(t *testing.T) {
telemetryClient.AssertCalled(t, "ConfigChange", []telemetry.Configuration{{Name: "trace_tags", Value: "key0:val0,key1:val1,key2:val2," + runtimeIDTag, Origin: ""}})
})

t.Run("Deleted config", func(t *testing.T) {
defer globalconfig.ClearHeaderTags()
telemetryClient := new(telemetrytest.MockClient)
defer telemetry.MockGlobalClient(telemetryClient)()

t.Setenv("DD_TRACE_SAMPLE_RATE", "0.1")
t.Setenv("DD_TRACE_HEADER_TAGS", "X-Test-Header:my-tag-from-env")
t.Setenv("DD_TAGS", "ddtag:from-env")
tracer, _, _, stop := startTestTracer(t, WithService("my-service"), WithEnv("my-env"))
defer stop()

// Apply RC. Assert configuration is updated to the RC values.
input := remoteconfig.ProductUpdate{
"path": []byte(`{"lib_config": {"tracing_sampling_rate": 0.2,"tracing_header_tags": [{"header": "X-Test-Header", "tag_name": "my-tag-from-rc"}],"tracing_tags": ["ddtag:from-rc"]}, "service_target": {"service": "my-service", "env": "my-env"}}`),
}
applyStatus := tracer.onRemoteConfigUpdate(input)
require.Equal(t, state.ApplyStateAcknowledged, applyStatus["path"].State)
s := tracer.StartSpan("web.request").(*span)
s.Finish()
require.Equal(t, 0.2, s.Metrics[keyRulesSamplerAppliedRate])
require.Equal(t, "my-tag-from-rc", globalconfig.HeaderTag("X-Test-Header"))
require.Equal(t, "from-rc", s.Meta["ddtag"])

// Telemetry
telemetryClient.AssertNumberOfCalls(t, "ConfigChange", 1)
telemetryClient.AssertCalled(t, "ConfigChange", []telemetry.Configuration{
{Name: "trace_sample_rate", Value: 0.2, Origin: "remote_config"},
{Name: "trace_header_tags", Value: "X-Test-Header:my-tag-from-rc", Origin: "remote_config"},
{Name: "trace_tags", Value: "ddtag:from-rc," + ext.RuntimeID + ":" + globalconfig.RuntimeID(), Origin: "remote_config"},
})

// Remove RC. Assert configuration is reset to the original values.
input = remoteconfig.ProductUpdate{"path": nil}
applyStatus = tracer.onRemoteConfigUpdate(input)
require.Equal(t, state.ApplyStateAcknowledged, applyStatus["path"].State)
s = tracer.StartSpan("web.request").(*span)
s.Finish()
require.Equal(t, 0.1, s.Metrics[keyRulesSamplerAppliedRate])
require.Equal(t, "my-tag-from-env", globalconfig.HeaderTag("X-Test-Header"))
require.Equal(t, "from-env", s.Meta["ddtag"])

// Telemetry
telemetryClient.AssertNumberOfCalls(t, "ConfigChange", 2)
telemetryClient.AssertCalled(t, "ConfigChange", []telemetry.Configuration{
{Name: "trace_sample_rate", Value: 0.1, Origin: ""},
{Name: "trace_header_tags", Value: "X-Test-Header:my-tag-from-env", Origin: ""},
{Name: "trace_tags", Value: "ddtag:from-env," + ext.RuntimeID + ":" + globalconfig.RuntimeID(), Origin: ""},
})
})

assert.Equal(t, 0, globalconfig.HeaderTagsLen())
}

Expand Down

0 comments on commit 67e0c5a

Please sign in to comment.