Skip to content

Commit

Permalink
poc(ddtrace/tracer): migrate enabled (RC)
Browse files Browse the repository at this point in the history
  • Loading branch information
darccio committed Dec 13, 2024
1 parent 34f6128 commit e7f6893
Show file tree
Hide file tree
Showing 7 changed files with 64 additions and 30 deletions.
36 changes: 29 additions & 7 deletions ddtrace/tracer/option.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,10 @@ var (
type config struct {
*knobs.Scope

dynamic struct {
// enabled reports whether tracing is enabled.
enabled dynamicConfig[bool]
}

// debug, when true, writes details to logs.
debug bool
Expand Down Expand Up @@ -235,9 +239,6 @@ type config struct {
// profilerEndpoints specifies whether profiler endpoint filtering is enabled.
profilerEndpoints bool

// enabled reports whether tracing is enabled.
enabled dynamicConfig[bool]

// enableHostnameDetection specifies whether the tracer should enable hostname detection.
enableHostnameDetection bool

Expand Down Expand Up @@ -295,6 +296,26 @@ var (
)

var (
enabled = knobs.Register(&knobs.Definition[bool]{
Default: true,
EnvVars: []knobs.EnvVar{
{
Key: "DD_TRACE_ENABLED",
},
{
Key: "OTEL_TRACES_EXPORTER",
Transform: mapEnabled,
},
},
Parse: func(s string) (bool, error) {
if s == "" {
// Short-circuit if the value is empty, to avoid parsing errors.
return true, nil
}
return strconv.ParseBool(s)
},
})

// globalSampleRate holds sample rate read from environment variables.
globalSampleRate = knobs.Register(&knobs.Definition[float64]{
Default: math.NaN(),
Expand Down Expand Up @@ -450,9 +471,10 @@ func newConfig(opts ...StartOption) *config {
c.runtimeMetricsV2 = internal.BoolEnv("DD_RUNTIME_METRICS_V2_ENABLED", false)
c.debug = internal.BoolVal(getDDorOtelConfig("debugMode"), false)
c.logDirectory = os.Getenv("DD_TRACE_LOG_DIRECTORY")
c.enabled = newDynamicConfig("tracing_enabled", internal.BoolVal(getDDorOtelConfig("enabled"), true), func(b bool) bool { return true }, equal[bool])
c.dynamic.enabled = newDynamicConfig("tracing_enabled", knobs.GetScope(c.Scope, enabled), func(b bool) bool { knobs.SetScope(c.Scope, enabled, knobs.Code, b); return true }, equal[bool])
if _, ok := os.LookupEnv("DD_TRACE_ENABLED"); ok {
c.enabled.cfgOrigin = telemetry.OriginEnvVar
// TODO: shouldn't we track this for the OTEL_TRACES_EXPORTER case?
c.dynamic.enabled.cfgOrigin = telemetry.OriginEnvVar
}
c.profilerEndpoints = internal.BoolEnv(traceprof.EndpointEnvVar, true)
c.profilerHotspots = internal.BoolEnv(traceprof.CodeHotspotsEnvVar, true)
Expand Down Expand Up @@ -567,7 +589,7 @@ func newConfig(opts ...StartOption) *config {
log.SetLevel(log.LevelDebug)
}
// if using stdout or traces are disabled, agent is disabled
agentDisabled := c.logToStdout || !c.enabled.current
agentDisabled := c.logToStdout || !knobs.GetScope(c.Scope, enabled)
c.agent = loadAgentFeatures(agentDisabled, c.agentURL, c.httpClient)
info, ok := debug.ReadBuildInfo()
if !ok {
Expand Down Expand Up @@ -1169,7 +1191,7 @@ func WithHostname(name string) StartOption {
// WithTraceEnabled allows specifying whether tracing will be enabled
func WithTraceEnabled(enabled bool) StartOption {
return func(c *config) {
c.enabled = newDynamicConfig("tracing_enabled", enabled, func(b bool) bool { return true }, equal[bool])
c.dynamic.enabled.update(enabled, telemetry.OriginCode)
}
}

Expand Down
25 changes: 16 additions & 9 deletions ddtrace/tracer/option_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -637,17 +637,19 @@ func TestTracerOptionsDefaults(t *testing.T) {
tracer := newTracer(WithAgentTimeout(2))
defer tracer.Stop()
c := tracer.config
assert.True(t, c.enabled.current)
assert.Equal(t, c.enabled.cfgOrigin, telemetry.OriginDefault)
assert.True(t, c.dynamic.enabled.current)
assert.True(t, knobs.GetScope(c.Scope, enabled))
assert.Equal(t, c.dynamic.enabled.cfgOrigin, telemetry.OriginDefault)
})

t.Run("override", func(t *testing.T) {
t.Setenv("DD_TRACE_ENABLED", "false")
tracer := newTracer(WithAgentTimeout(2))
defer tracer.Stop()
c := tracer.config
assert.False(t, c.enabled.current)
assert.Equal(t, c.enabled.cfgOrigin, telemetry.OriginEnvVar)
assert.False(t, c.dynamic.enabled.current)
assert.False(t, knobs.GetScope(c.Scope, enabled))
assert.Equal(t, c.dynamic.enabled.cfgOrigin, telemetry.OriginEnvVar)
})
})

Expand Down Expand Up @@ -1365,21 +1367,24 @@ func TestWithTraceEnabled(t *testing.T) {
t.Run("WithTraceEnabled", func(t *testing.T) {
assert := assert.New(t)
c := newConfig(WithTraceEnabled(false))
assert.False(c.enabled.current)
assert.False(c.dynamic.enabled.current)
assert.False(knobs.GetScope(c.Scope, enabled))
})

t.Run("otel-env", func(t *testing.T) {
assert := assert.New(t)
t.Setenv("OTEL_TRACES_EXPORTER", "none")
c := newConfig()
assert.False(c.enabled.current)
assert.False(c.dynamic.enabled.current)
assert.False(knobs.GetScope(c.Scope, enabled))
})

t.Run("dd-env", func(t *testing.T) {
assert := assert.New(t)
t.Setenv("DD_TRACE_ENABLED", "false")
c := newConfig()
assert.False(c.enabled.current)
assert.False(c.dynamic.enabled.current)
assert.False(knobs.GetScope(c.Scope, enabled))
})

t.Run("override-chain", func(t *testing.T) {
Expand All @@ -1388,10 +1393,12 @@ func TestWithTraceEnabled(t *testing.T) {
t.Setenv("OTEL_TRACES_EXPORTER", "none")
t.Setenv("DD_TRACE_ENABLED", "true")
c := newConfig()
assert.True(c.enabled.current)
assert.True(c.dynamic.enabled.current)
assert.True(knobs.GetScope(c.Scope, enabled))
// tracer option overrides dd env
c = newConfig(WithTraceEnabled(false))
assert.False(c.enabled.current)
assert.False(c.dynamic.enabled.current)
assert.False(knobs.GetScope(c.Scope, enabled))
})
}

Expand Down
10 changes: 5 additions & 5 deletions ddtrace/tracer/remote_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ func (t *tracer) onRemoteConfigUpdate(u remoteconfig.ProductUpdate) map[string]s
if updated {
telemConfigs = append(telemConfigs, t.config.globalTags.toTelemetry())
}
if !t.config.enabled.current {
if !t.config.dynamic.enabled.current {
log.Debug("APM Tracing is disabled. Restart the service to enable it.")
}
if len(telemConfigs) > 0 {
Expand Down Expand Up @@ -233,11 +233,11 @@ func (t *tracer) onRemoteConfigUpdate(u remoteconfig.ProductUpdate) map[string]s
telemConfigs = append(telemConfigs, t.config.globalTags.toTelemetry())
}
if c.LibConfig.Enabled != nil {
if t.config.enabled.current == true && *c.LibConfig.Enabled == false {
if t.config.dynamic.enabled.current == true && *c.LibConfig.Enabled == false {
log.Debug("Disabled APM Tracing through RC. Restart the service to enable it.")
t.config.enabled.handleRC(c.LibConfig.Enabled)
telemConfigs = append(telemConfigs, t.config.enabled.toTelemetry())
} else if t.config.enabled.current == false && *c.LibConfig.Enabled == true {
t.config.dynamic.enabled.handleRC(c.LibConfig.Enabled)
telemConfigs = append(telemConfigs, t.config.dynamic.enabled.toTelemetry())
} else if t.config.dynamic.enabled.current == false && *c.LibConfig.Enabled == true {
log.Debug("APM Tracing is disabled. Restart the service to enable it.")
}
}
Expand Down
8 changes: 5 additions & 3 deletions ddtrace/tracer/remote_config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"gopkg.in/DataDog/dd-trace-go.v1/internal/telemetry/telemetrytest"

"github.com/DataDog/datadog-agent/pkg/remoteconfig/state"
"github.com/darccio/knobs"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
Expand Down Expand Up @@ -395,7 +396,7 @@ func TestOnRemoteConfigUpdate(t *testing.T) {

applyStatus := tr.onRemoteConfigUpdate(input)
require.Equal(t, state.ApplyStateAcknowledged, applyStatus["path"].State)
require.Equal(t, false, tr.config.enabled.current)
require.Equal(t, false, tr.config.dynamic.enabled.current)
headers := TextMapCarrier{
traceparentHeader: "00-12345678901234567890123456789012-1234567890123456-01",
tracestateHeader: "dd=s:2;o:rum;t.usr.id:baz64~~",
Expand All @@ -417,7 +418,7 @@ func TestOnRemoteConfigUpdate(t *testing.T) {
input = remoteconfig.ProductUpdate{"path": nil}
applyStatus = tr.onRemoteConfigUpdate(input)
require.Equal(t, state.ApplyStateAcknowledged, applyStatus["path"].State)
require.Equal(t, false, tr.config.enabled.current)
require.Equal(t, false, knobs.GetScope(tr.config.Scope, enabled))

// turning tracing back explicitly is not allowed
input = remoteconfig.ProductUpdate{
Expand All @@ -427,7 +428,8 @@ func TestOnRemoteConfigUpdate(t *testing.T) {
}
applyStatus = tr.onRemoteConfigUpdate(input)
require.Equal(t, state.ApplyStateAcknowledged, applyStatus["path"].State)
require.Equal(t, false, tr.config.enabled.current)
require.Equal(t, false, tr.config.dynamic.enabled.current)
require.Equal(t, false, knobs.GetScope(tr.config.Scope, enabled))

telemetryClient.AssertNumberOfCalls(t, "ConfigChange", 1)
})
Expand Down
3 changes: 2 additions & 1 deletion ddtrace/tracer/span.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import (
"gopkg.in/DataDog/dd-trace-go.v1/internal/samplernames"
"gopkg.in/DataDog/dd-trace-go.v1/internal/traceprof"

"github.com/darccio/knobs"
"github.com/tinylib/msgp/msgp"
"golang.org/x/xerrors"

Expand Down Expand Up @@ -548,7 +549,7 @@ func (s *span) finish(finishTime int64) {

keep := true
if t, ok := internal.GetGlobalTracer().(*tracer); ok {
if !t.config.enabled.current {
if !knobs.GetScope(t.config.Scope, enabled) {
return
}
// we have an active tracer
Expand Down
4 changes: 3 additions & 1 deletion ddtrace/tracer/telemetry.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import (
"strings"

"gopkg.in/DataDog/dd-trace-go.v1/internal/telemetry"

"github.com/darccio/knobs"
)

var additionalConfigs []telemetry.Configuration
Expand Down Expand Up @@ -63,7 +65,7 @@ func startTelemetry(c *config) {
{Name: "trace_span_attribute_schema", Value: c.spanAttributeSchemaVersion},
{Name: "trace_peer_service_defaults_enabled", Value: c.peerServiceDefaultsEnabled},
{Name: "orchestrion_enabled", Value: c.orchestrionCfg.Enabled},
{Name: "trace_enabled", Value: c.enabled.current, Origin: c.enabled.cfgOrigin},
{Name: "trace_enabled", Value: knobs.GetScope(c.Scope, enabled), Origin: c.dynamic.enabled.cfgOrigin},
{Name: "trace_log_directory", Value: c.logDirectory},
c.traceSampleRate.toTelemetry(),
c.headerAsTags.toTelemetry(),
Expand Down
8 changes: 4 additions & 4 deletions ddtrace/tracer/tracer.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ func Start(opts ...StartOption) {
}
defer telemetry.Time(telemetry.NamespaceGeneral, "init_time", nil, true)()
t := newTracer(opts...)
if !t.config.enabled.current {
if !knobs.GetScope(t.config.Scope, enabled) {
// TODO: instrumentation telemetry client won't get started
// if tracing is disabled, but we still want to capture this
// telemetry information. Will be fixed when the tracer and profiler
Expand Down Expand Up @@ -500,7 +500,7 @@ func (t *tracer) pushChunk(trace *chunk) {

// StartSpan creates, starts, and returns a new Span with the given `operationName`.
func (t *tracer) StartSpan(operationName string, options ...ddtrace.StartSpanOption) ddtrace.Span {
if !t.config.enabled.current {
if !knobs.GetScope(t.config.Scope, enabled) {
return internal.NoopSpan{}
}
var opts ddtrace.StartSpanConfig
Expand Down Expand Up @@ -716,7 +716,7 @@ func (t *tracer) Stop() {

// Inject uses the configured or default TextMap Propagator.
func (t *tracer) Inject(ctx ddtrace.SpanContext, carrier interface{}) error {
if !t.config.enabled.current {
if !knobs.GetScope(t.config.Scope, enabled) {
return nil
}
t.updateSampling(ctx)
Expand Down Expand Up @@ -755,7 +755,7 @@ func (t *tracer) updateSampling(ctx ddtrace.SpanContext) {

// Extract uses the configured or default TextMap Propagator.
func (t *tracer) Extract(carrier interface{}) (ddtrace.SpanContext, error) {
if !t.config.enabled.current {
if !knobs.GetScope(t.config.Scope, enabled) {
return internal.NoopSpanContext{}, nil
}
return t.config.propagator.Extract(carrier)
Expand Down

0 comments on commit e7f6893

Please sign in to comment.