-
Notifications
You must be signed in to change notification settings - Fork 535
Expand file tree
/
Copy pathtelemetry.go
More file actions
139 lines (129 loc) · 6.5 KB
/
Copy pathtelemetry.go
File metadata and controls
139 lines (129 loc) · 6.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// 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 (
"fmt"
"strings"
"github.com/DataDog/dd-trace-go/v2/internal/log"
"github.com/DataDog/dd-trace-go/v2/internal/telemetry"
)
var additionalConfigs []telemetry.Configuration
func reportTelemetryOnAppStarted(c telemetry.Configuration) {
additionalConfigs = append(additionalConfigs, c)
}
// startTelemetry starts the global instrumentation telemetry client with tracer data
// unless instrumentation telemetry is disabled via the DD_INSTRUMENTATION_TELEMETRY_ENABLED
// env var.
// If the telemetry client has already been started by the profiler, then
// an app-product-change event is sent with appsec information and an app-client-configuration-change
// event is sent with tracer config data.
// Note that the tracer is not considered as a standalone product by telemetry so we cannot send
// an app-product-change event for the tracer.
// TODO (APMAPI-1771): This function should be deleted once config migration is complete
func startTelemetry(c *config) telemetry.Client {
if telemetry.Disabled() {
// Do not do extra work populating config data if instrumentation telemetry is disabled.
return nil
}
telemetry.ProductStarted(telemetry.NamespaceTracers)
// Read enabled value and origin atomically to prevent TOCTOU bugs
traceEnabled, traceEnabledOrigin := c.enabled.getCurrentAndOrigin()
// Hoist to local var so both fields come from the same atomic snapshot.
a := c.agent.load()
telemetryConfigs := []telemetry.Configuration{
{Name: "agent_feature_drop_p0s", Value: a.DropP0s},
{Name: "stats_computation_enabled", Value: c.canComputeStats()},
{Name: "dogstatsd_port", Value: a.StatsdPort},
{Name: "lambda_mode", Value: c.internalConfig.LogToStdout()},
{Name: "send_retries", Value: c.sendRetries},
{Name: "retry_interval", Value: c.internalConfig.RetryInterval()},
{Name: "trace_startup_logs_enabled", Value: c.internalConfig.LogStartup()},
{Name: "service", Value: c.internalConfig.ServiceName()},
{Name: "universal_version", Value: c.universalVersion},
{Name: "env", Value: c.internalConfig.Env()},
{Name: "version", Value: c.internalConfig.Version()},
{Name: "trace_agent_url", Value: c.internalConfig.AgentURL().String()},
{Name: "agent_hostname", Value: c.internalConfig.Hostname()},
{Name: "runtime_metrics_v2_enabled", Value: c.internalConfig.RuntimeMetricsV2Enabled()},
{Name: "dogstatsd_addr", Value: c.dogstatsdAddr},
{Name: "profiling_endpoints_enabled", Value: c.internalConfig.ProfilerEndpoints()},
{Name: "debug_stack_enabled", Value: c.internalConfig.DebugStack()},
{Name: "profiling_hotspots_enabled", Value: c.internalConfig.ProfilerHotspotsEnabled()},
{Name: "trace_peer_service_defaults_enabled", Value: c.internalConfig.PeerServiceDefaultsEnabled()},
{Name: "orchestrion_enabled", Value: c.orchestrionCfg.Enabled, Origin: telemetry.OriginCode},
{Name: "trace_enabled", Value: traceEnabled, Origin: traceEnabledOrigin},
{Name: "trace_log_directory", Value: c.internalConfig.LogDirectory()},
c.headerAsTags.toTelemetry(),
c.globalTags.toTelemetry(),
c.traceSampleRules.toTelemetry(),
{Name: "span_sample_rules", Value: c.spanRules},
}
var peerServiceMapping []string
for key, value := range c.internalConfig.PeerServiceMappings() {
peerServiceMapping = append(peerServiceMapping, fmt.Sprintf("%s:%s", key, value))
}
telemetryConfigs = append(telemetryConfigs,
telemetry.Configuration{Name: "trace_peer_service_mapping", Value: strings.Join(peerServiceMapping, ",")})
if chained, ok := c.propagator.(*chainedPropagator); ok {
telemetryConfigs = append(telemetryConfigs,
telemetry.Configuration{Name: "trace_propagation_style_inject", Value: chained.injectorNames})
telemetryConfigs = append(telemetryConfigs,
telemetry.Configuration{Name: "trace_propagation_style_extract", Value: chained.extractorsNames})
}
for k, v := range c.internalConfig.FeatureFlags() {
telemetryConfigs = append(telemetryConfigs, telemetry.Configuration{Name: k, Value: v})
}
for k, v := range c.internalConfig.ServiceMappings() {
telemetryConfigs = append(telemetryConfigs, telemetry.Configuration{Name: "service_mapping_" + k, Value: v})
}
for k, v := range c.globalTags.get() {
telemetryConfigs = append(telemetryConfigs, telemetry.Configuration{Name: "global_tag_" + k, Value: v})
}
rules := append(c.spanRules, c.traceRules...)
for _, rule := range rules {
var service string
var name string
if rule.Service != nil {
service = rule.Service.String()
}
if rule.Name != nil {
name = rule.Name.String()
}
telemetryConfigs = append(telemetryConfigs,
telemetry.Configuration{Name: fmt.Sprintf("sr_%s_(%s)_(%s)", rule.ruleType.String(), service, name),
Value: fmt.Sprintf("rate:%f_maxPerSecond:%f", rule.Rate, rule.MaxPerSecond)})
}
if c.orchestrionCfg.Enabled {
telemetryConfigs = append(telemetryConfigs, telemetry.Configuration{Name: "orchestrion_version", Value: c.orchestrionCfg.Metadata.Version, Origin: telemetry.OriginCode})
}
telemetryConfigs = append(telemetryConfigs, additionalConfigs...)
telemetry.RegisterAppConfigs(telemetryConfigs...)
cfg := telemetry.ClientConfig{
HTTPClient: c.httpClient,
}
// Only omit the agent URL when the agent was reachable but explicitly does not
// expose the telemetry proxy endpoint (e.g. the Datadog Lambda extension).
// When the agent was unreachable at startup, we still set the URL so that
// telemetry is attempted rather than silently dropped.
// When the spans are emitted on stdout it means there is no agent at all in the env.
if (!a.reachable || a.hasTelemetryProxy) && !c.internalConfig.LogToStdout() {
cfg.AgentURL = c.internalConfig.AgentURL().String()
}
if c.internalConfig.LogToStdout() || c.ciVisibilityAgentless {
cfg.APIKey = c.internalConfig.APIKey()
}
client, err := telemetry.NewClient(c.internalConfig.ServiceName(), c.internalConfig.Env(), c.internalConfig.Version(), cfg)
if err != nil {
log.Debug("tracer: failed to create telemetry client: %s", err.Error())
return nil
}
if c.orchestrionCfg.Enabled {
// If orchestrion is enabled, report it to the back-end via a telemetry metric on every flush.
handle := client.Gauge(telemetry.NamespaceTracers, "orchestrion.enabled", []string{"version:" + c.orchestrionCfg.Metadata.Version})
client.AddFlushTicker(func(_ telemetry.Client) { handle.Submit(1) })
}
telemetry.StartApp(client)
return client
}