datadog 2.23.0 → 2.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +44 -2
- data/ext/datadog_profiling_native_extension/collectors_stack.c +17 -5
- data/ext/datadog_profiling_native_extension/crashtracking_runtime_stacks.c +239 -0
- data/ext/datadog_profiling_native_extension/extconf.rb +4 -1
- data/ext/datadog_profiling_native_extension/private_vm_api_access.c +12 -0
- data/ext/datadog_profiling_native_extension/private_vm_api_access.h +4 -0
- data/ext/datadog_profiling_native_extension/profiling.c +2 -0
- data/lib/datadog/appsec/context.rb +2 -1
- data/lib/datadog/appsec/remote.rb +1 -9
- data/lib/datadog/appsec/security_engine/result.rb +2 -1
- data/lib/datadog/core/configuration/config_helper.rb +1 -1
- data/lib/datadog/core/configuration/deprecations.rb +2 -2
- data/lib/datadog/core/configuration/option_definition.rb +4 -2
- data/lib/datadog/core/configuration/options.rb +8 -5
- data/lib/datadog/core/configuration/settings.rb +14 -3
- data/lib/datadog/core/configuration/supported_configurations.rb +2 -1
- data/lib/datadog/core/environment/cgroup.rb +52 -25
- data/lib/datadog/core/environment/container.rb +140 -46
- data/lib/datadog/core/environment/ext.rb +1 -0
- data/lib/datadog/core/environment/process.rb +9 -1
- data/lib/datadog/core/rate_limiter.rb +9 -1
- data/lib/datadog/core/remote/client.rb +14 -6
- data/lib/datadog/core/remote/component.rb +6 -4
- data/lib/datadog/core/remote/configuration/content.rb +15 -2
- data/lib/datadog/core/remote/configuration/digest.rb +14 -7
- data/lib/datadog/core/remote/configuration/repository.rb +1 -1
- data/lib/datadog/core/remote/configuration/target.rb +13 -6
- data/lib/datadog/core/remote/transport/config.rb +3 -16
- data/lib/datadog/core/remote/transport/http/config.rb +4 -44
- data/lib/datadog/core/remote/transport/http/negotiation.rb +0 -39
- data/lib/datadog/core/remote/transport/http.rb +13 -24
- data/lib/datadog/core/remote/transport/negotiation.rb +7 -16
- data/lib/datadog/core/telemetry/component.rb +52 -13
- data/lib/datadog/core/telemetry/event/app_started.rb +34 -0
- data/lib/datadog/core/telemetry/event/synth_app_client_configuration_change.rb +27 -4
- data/lib/datadog/core/telemetry/metrics_manager.rb +9 -0
- data/lib/datadog/core/telemetry/request.rb +17 -3
- data/lib/datadog/core/telemetry/transport/http/telemetry.rb +2 -32
- data/lib/datadog/core/telemetry/transport/http.rb +21 -16
- data/lib/datadog/core/telemetry/transport/telemetry.rb +3 -10
- data/lib/datadog/core/telemetry/worker.rb +88 -32
- data/lib/datadog/core/transport/ext.rb +2 -0
- data/lib/datadog/core/transport/http/api/endpoint.rb +9 -4
- data/lib/datadog/core/transport/http/api/instance.rb +4 -21
- data/lib/datadog/core/transport/http/builder.rb +9 -5
- data/lib/datadog/core/transport/http/client.rb +19 -8
- data/lib/datadog/core/transport/http.rb +22 -19
- data/lib/datadog/core/transport/response.rb +9 -0
- data/lib/datadog/core/transport/transport.rb +90 -0
- data/lib/datadog/core/utils/only_once_successful.rb +2 -0
- data/lib/datadog/core/utils/time.rb +1 -1
- data/lib/datadog/core/workers/async.rb +10 -1
- data/lib/datadog/core/workers/interval_loop.rb +44 -3
- data/lib/datadog/core/workers/polling.rb +2 -0
- data/lib/datadog/core/workers/queue.rb +100 -1
- data/lib/datadog/data_streams/processor.rb +1 -1
- data/lib/datadog/data_streams/transport/http/stats.rb +1 -36
- data/lib/datadog/data_streams/transport/http.rb +5 -6
- data/lib/datadog/data_streams/transport/stats.rb +3 -17
- data/lib/datadog/di/contrib/active_record.rb +31 -5
- data/lib/datadog/di/el/compiler.rb +8 -4
- data/lib/datadog/di/error.rb +5 -0
- data/lib/datadog/di/instrumenter.rb +17 -4
- data/lib/datadog/di/probe_builder.rb +2 -1
- data/lib/datadog/di/probe_manager.rb +37 -31
- data/lib/datadog/di/probe_notification_builder.rb +15 -2
- data/lib/datadog/di/remote.rb +89 -84
- data/lib/datadog/di/transport/diagnostics.rb +7 -35
- data/lib/datadog/di/transport/http/diagnostics.rb +1 -31
- data/lib/datadog/di/transport/http/input.rb +1 -31
- data/lib/datadog/di/transport/http.rb +28 -17
- data/lib/datadog/di/transport/input.rb +7 -34
- data/lib/datadog/di.rb +61 -5
- data/lib/datadog/open_feature/evaluation_engine.rb +2 -1
- data/lib/datadog/open_feature/remote.rb +3 -10
- data/lib/datadog/open_feature/transport.rb +9 -11
- data/lib/datadog/opentelemetry/api/baggage.rb +1 -1
- data/lib/datadog/opentelemetry/configuration/settings.rb +2 -2
- data/lib/datadog/opentelemetry/metrics.rb +21 -14
- data/lib/datadog/opentelemetry/sdk/metrics_exporter.rb +5 -8
- data/lib/datadog/profiling/collectors/code_provenance.rb +27 -2
- data/lib/datadog/profiling/collectors/info.rb +2 -1
- data/lib/datadog/profiling/component.rb +12 -11
- data/lib/datadog/profiling/http_transport.rb +4 -1
- data/lib/datadog/tracing/contrib/extensions.rb +10 -2
- data/lib/datadog/tracing/contrib/karafka/patcher.rb +31 -32
- data/lib/datadog/tracing/contrib/status_range_matcher.rb +2 -1
- data/lib/datadog/tracing/contrib/utils/quantization/hash.rb +3 -1
- data/lib/datadog/tracing/contrib/waterdrop/patcher.rb +6 -3
- data/lib/datadog/tracing/diagnostics/environment_logger.rb +1 -1
- data/lib/datadog/tracing/remote.rb +1 -9
- data/lib/datadog/tracing/span_event.rb +2 -2
- data/lib/datadog/tracing/span_operation.rb +9 -4
- data/lib/datadog/tracing/trace_operation.rb +44 -6
- data/lib/datadog/tracing/tracer.rb +42 -16
- data/lib/datadog/tracing/transport/http/traces.rb +2 -50
- data/lib/datadog/tracing/transport/http.rb +15 -9
- data/lib/datadog/tracing/transport/io/client.rb +1 -1
- data/lib/datadog/tracing/transport/traces.rb +6 -66
- data/lib/datadog/tracing/workers/trace_writer.rb +5 -0
- data/lib/datadog/tracing/writer.rb +1 -0
- data/lib/datadog/version.rb +2 -2
- metadata +7 -13
- data/lib/datadog/core/remote/transport/http/api.rb +0 -53
- data/lib/datadog/core/telemetry/transport/http/api.rb +0 -43
- data/lib/datadog/core/transport/http/api/spec.rb +0 -36
- data/lib/datadog/data_streams/transport/http/api.rb +0 -33
- data/lib/datadog/data_streams/transport/http/client.rb +0 -21
- data/lib/datadog/di/transport/http/api.rb +0 -42
- data/lib/datadog/opentelemetry/api/baggage.rbs +0 -26
- data/lib/datadog/tracing/transport/http/api.rb +0 -44
|
@@ -10,40 +10,67 @@ module Datadog
|
|
|
10
10
|
# about the current Linux container identity.
|
|
11
11
|
# @see https://man7.org/linux/man-pages/man7/cgroups.7.html
|
|
12
12
|
module Cgroup
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
:
|
|
17
|
-
:groups,
|
|
13
|
+
# A parsed cgroup entry from /proc/<pid>/cgroup
|
|
14
|
+
Entry = Struct.new(
|
|
15
|
+
:hierarchy,
|
|
16
|
+
:controllers,
|
|
18
17
|
:path,
|
|
19
|
-
:
|
|
18
|
+
:inode
|
|
20
19
|
)
|
|
21
20
|
|
|
22
21
|
module_function
|
|
23
22
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
end
|
|
34
|
-
rescue => e
|
|
35
|
-
Datadog.logger.error(
|
|
36
|
-
"Error while parsing cgroup. Cause: #{e.class.name} #{e.message} Location: #{Array(e.backtrace).first}"
|
|
37
|
-
)
|
|
23
|
+
# Parses the /proc/self/cgroup file,
|
|
24
|
+
# @return [Array<Entry>] one entry for each valid cgroup line
|
|
25
|
+
def entries
|
|
26
|
+
filepath = '/proc/self/cgroup'
|
|
27
|
+
return [] unless File.exist?(filepath)
|
|
28
|
+
|
|
29
|
+
ret = []
|
|
30
|
+
File.foreach(filepath) do |entry_line|
|
|
31
|
+
ret << parse(entry_line) unless entry_line.empty?
|
|
38
32
|
end
|
|
33
|
+
ret
|
|
39
34
|
end
|
|
40
35
|
|
|
41
|
-
|
|
42
|
-
|
|
36
|
+
# Parses a single cgroup entry from /proc/<pid>/cgroup.
|
|
37
|
+
#
|
|
38
|
+
# Files can have cgroup v1 and v2 entries mixed. Their format is the same.
|
|
39
|
+
#
|
|
40
|
+
# Each entry has 3 colon-separated fields:
|
|
41
|
+
# hierarchy-ID:controllers:path
|
|
42
|
+
# Examples:
|
|
43
|
+
# 10:memory:/docker/1234567890abcdef (cgroup v1)
|
|
44
|
+
# 0::/docker/1234567890abcdef (cgroup v2)
|
|
45
|
+
#
|
|
46
|
+
# @see https://man7.org/linux/man-pages/man7/cgroups.7.html#:~:text=%2Fproc%2Fpid%2Fcgroup
|
|
47
|
+
# @return [Entry]
|
|
48
|
+
def parse(entry_line)
|
|
49
|
+
hierarchy, controllers, path = entry_line.split(':', 3)
|
|
43
50
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
51
|
+
Entry.new(
|
|
52
|
+
hierarchy,
|
|
53
|
+
controllers,
|
|
54
|
+
path,
|
|
55
|
+
inode_for(controllers, path)
|
|
56
|
+
)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# We can find the container inode by running a file stat on the cgroup filesystem path.
|
|
60
|
+
# Example:
|
|
61
|
+
# For the entry `0:cpu:/docker/abc123`,
|
|
62
|
+
# we read `stat -c '%i' /sys/fs/cgroup/cpu/docker/abc123`
|
|
63
|
+
def inode_for(controllers, path)
|
|
64
|
+
return if controllers.nil? || path.nil?
|
|
65
|
+
|
|
66
|
+
# In cgroup v1, when multiple controllers are co-mounted, the controllers
|
|
67
|
+
# becomes part of the directory name (with commas preserved).
|
|
68
|
+
# Example entry:
|
|
69
|
+
# For the line "10:cpu,cpuacct:/docker/abc123", the path is
|
|
70
|
+
# "/sys/fs/cgroup/cpu,cpuacct/docker/abc123"
|
|
71
|
+
inode_path = File.join('/sys/fs/cgroup', controllers, path)
|
|
72
|
+
|
|
73
|
+
File.stat(inode_path).ino if File.exist?(inode_path)
|
|
47
74
|
end
|
|
48
75
|
end
|
|
49
76
|
end
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative 'cgroup'
|
|
4
|
+
require_relative 'ext'
|
|
4
5
|
|
|
5
6
|
module Datadog
|
|
6
7
|
module Core
|
|
@@ -15,73 +16,166 @@ module Datadog
|
|
|
15
16
|
CONTAINER_REGEX = /(?<container>#{UUID_PATTERN}|#{CONTAINER_PATTERN})(?:.scope)?$/.freeze
|
|
16
17
|
FARGATE_14_CONTAINER_REGEX = /(?<container>[0-9a-f]{32}-[0-9]{1,10})/.freeze
|
|
17
18
|
|
|
18
|
-
|
|
19
|
+
# From https://github.com/torvalds/linux/blob/5859a2b1991101d6b978f3feb5325dad39421f29/include/linux/proc_ns.h#L41-L49
|
|
20
|
+
# Currently, the host namespace inode number is hardcoded.
|
|
21
|
+
# We use it to determine if we're running in the host namespace.
|
|
22
|
+
# This detection approach does not work when running in
|
|
23
|
+
# ["Docker-in-Docker"](https://www.docker.com/resources/docker-in-docker-containerized-ci-workflows-dockercon-2023/).
|
|
24
|
+
HOST_CGROUP_NAMESPACE_INODE = 0xEFFFFFFB
|
|
25
|
+
|
|
26
|
+
Entry = Struct.new(
|
|
19
27
|
:platform,
|
|
28
|
+
:task_uid,
|
|
20
29
|
:container_id,
|
|
21
|
-
:
|
|
30
|
+
:inode
|
|
22
31
|
)
|
|
23
32
|
|
|
24
33
|
module_function
|
|
25
34
|
|
|
35
|
+
# Returns HTTP headers representing container information.
|
|
36
|
+
# These can used in any Datadog request that requires origin detection.
|
|
37
|
+
# This is the recommended method to call to get container information.
|
|
38
|
+
def to_headers
|
|
39
|
+
headers = {}
|
|
40
|
+
headers["Datadog-Container-ID"] = container_id if container_id
|
|
41
|
+
headers["Datadog-Entity-ID"] = entity_id if entity_id
|
|
42
|
+
headers["Datadog-External-Env"] = external_env if external_env
|
|
43
|
+
headers
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Container ID, prefixed with "ci-" or Inode, prefixed with "in-".
|
|
47
|
+
def entity_id
|
|
48
|
+
if container_id
|
|
49
|
+
"ci-#{container_id}"
|
|
50
|
+
elsif inode
|
|
51
|
+
"in-#{inode}"
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# External data supplied by the Datadog Cluster Agent Admission Controller.
|
|
56
|
+
# @see {Ext::ENV_EXTERNAL_ENV} for more details.
|
|
57
|
+
def external_env
|
|
58
|
+
Datadog.configuration.container.external_env
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# The container orchestration platform or runtime environment.
|
|
62
|
+
#
|
|
63
|
+
# Examples: Docker, Kubernetes, AWS Fargate, LXC, etc.
|
|
64
|
+
#
|
|
65
|
+
# @return [String, nil] The platform name (e.g., "docker", "kubepods", "fargate"), or nil if not containerized
|
|
26
66
|
def platform
|
|
27
|
-
|
|
67
|
+
entry.platform
|
|
28
68
|
end
|
|
29
69
|
|
|
70
|
+
# The unique identifier of the current container in the container environment.
|
|
71
|
+
#
|
|
72
|
+
# @return [String, nil] The container ID, or nil if not running in a containerized environment
|
|
30
73
|
def container_id
|
|
31
|
-
|
|
74
|
+
entry.container_id
|
|
32
75
|
end
|
|
33
76
|
|
|
77
|
+
# The unique identifier of the task or pod containing this container.
|
|
78
|
+
#
|
|
79
|
+
# In Kubernetes, this is the Pod UID; in AWS ECS/Fargate, the task ID.
|
|
80
|
+
# Used to identify higher-level workloads beyond this container,
|
|
81
|
+
# enabling correlation across container restarts and multi-container applications.
|
|
82
|
+
#
|
|
83
|
+
# @return [String, nil] The task/pod UID, or nil if not available in the current environment
|
|
34
84
|
def task_uid
|
|
35
|
-
|
|
85
|
+
entry.task_uid
|
|
36
86
|
end
|
|
37
87
|
|
|
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
|
-
|
|
88
|
+
# A unique identifier for the execution context (container or host namespace).
|
|
89
|
+
#
|
|
90
|
+
# Used as a fallback identifier when {#container_id} is unavailable.
|
|
91
|
+
#
|
|
92
|
+
# @return [Integer, nil] The namespace inode, or nil if unavailable
|
|
93
|
+
def inode
|
|
94
|
+
entry.inode
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# Checks if the current process is running on the host cgroup namespace.
|
|
98
|
+
# This indicates that the process is not running inside a container.
|
|
99
|
+
# When unsure, we return `false` (not running on host).
|
|
100
|
+
def running_on_host?
|
|
101
|
+
return @running_on_host if defined?(@running_on_host)
|
|
102
|
+
|
|
103
|
+
@running_on_host = begin
|
|
104
|
+
if File.exist?('/proc/self/ns/cgroup')
|
|
105
|
+
File.stat('/proc/self/ns/cgroup').ino == HOST_CGROUP_NAMESPACE_INODE
|
|
106
|
+
else
|
|
107
|
+
false
|
|
108
|
+
end
|
|
109
|
+
rescue => e
|
|
110
|
+
Datadog.logger.debug(
|
|
111
|
+
"Error while checking cgroup namespace. Cause: #{e.class.name} #{e.message} Location: #{Array(e.backtrace).first}"
|
|
112
|
+
)
|
|
113
|
+
false
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# All cgroup entries have the same container identity.
|
|
118
|
+
# The first valid one is sufficient.
|
|
119
|
+
# v2 entries are preferred over v1.
|
|
120
|
+
def entry
|
|
121
|
+
return @entry if defined?(@entry)
|
|
122
|
+
|
|
123
|
+
# Scan all v2 entries first, only then falling back to v1 entries.
|
|
124
|
+
#
|
|
125
|
+
# To do this, we {Enumerable#partition} the list between v1 and v2,
|
|
126
|
+
# with a `true` predicate for v2 entries, making v2 first
|
|
127
|
+
# partition returned.
|
|
128
|
+
#
|
|
129
|
+
# All v2 entries have the `hierarchy` set to zero.
|
|
130
|
+
# v1 entries have a non-zero `hierarchy`.
|
|
131
|
+
entries = Cgroup.entries.partition { |d| d.hierarchy == '0' }.flatten(1)
|
|
132
|
+
entries.each do |entry_obj|
|
|
133
|
+
path = entry_obj.path
|
|
134
|
+
next unless path
|
|
135
|
+
|
|
136
|
+
# To ease handling, remove the emtpy leading "",
|
|
137
|
+
# as `path` starts with a "/".
|
|
138
|
+
path.delete_prefix!('/')
|
|
139
|
+
parts = path.split('/')
|
|
140
|
+
|
|
141
|
+
# With not path information, we can still use the inode
|
|
142
|
+
if parts.empty? && entry_obj.inode && !running_on_host?
|
|
143
|
+
return @entry = Entry.new(nil, nil, nil, entry_obj.inode)
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
platform = parts[0][PLATFORM_REGEX, :platform]
|
|
147
|
+
|
|
148
|
+
# Extract container_id and task_uid based on path structure
|
|
149
|
+
container_id = task_uid = nil
|
|
150
|
+
if parts.length >= 2
|
|
151
|
+
# Try standard container regex first
|
|
152
|
+
if (container_id = parts[-1][CONTAINER_REGEX, :container])
|
|
153
|
+
# For 3+ parts, also extract task_uid
|
|
154
|
+
if parts.length > 2
|
|
63
155
|
task_uid = parts[-2][POD_REGEX, :pod] || parts[1][POD_REGEX, :pod]
|
|
64
|
-
else
|
|
65
|
-
container_id = parts[-1][FARGATE_14_CONTAINER_REGEX, :container]
|
|
66
156
|
end
|
|
157
|
+
else
|
|
158
|
+
# Fall back to Fargate regex
|
|
159
|
+
container_id = parts[-1][FARGATE_14_CONTAINER_REGEX, :container]
|
|
67
160
|
end
|
|
161
|
+
end
|
|
68
162
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
descriptor.task_uid = task_uid
|
|
76
|
-
|
|
77
|
-
break
|
|
163
|
+
# container_id is a better container identifier than inode.
|
|
164
|
+
# We MUST only populate one of them, to avoid container identification ambiguity.
|
|
165
|
+
if container_id
|
|
166
|
+
return @entry = Entry.new(platform, task_uid, container_id)
|
|
167
|
+
elsif entry_obj.inode && !running_on_host?
|
|
168
|
+
return @entry = Entry.new(platform, task_uid, nil, entry_obj.inode)
|
|
78
169
|
end
|
|
79
|
-
rescue => e
|
|
80
|
-
Datadog.logger.error(
|
|
81
|
-
"Error while parsing container info. Cause: #{e.class.name} #{e.message} " \
|
|
82
|
-
"Location: #{Array(e.backtrace).first}"
|
|
83
|
-
)
|
|
84
170
|
end
|
|
171
|
+
|
|
172
|
+
@entry = Entry.new # Empty entry if no valid cgroup entry is found
|
|
173
|
+
rescue => e
|
|
174
|
+
Datadog.logger.debug(
|
|
175
|
+
"Error while reading container entry. Cause: #{e.class.name} #{e.message} Location: #{Array(e.backtrace).first}"
|
|
176
|
+
)
|
|
177
|
+
@entry = Entry.new unless defined?(@entry)
|
|
178
|
+
@entry
|
|
85
179
|
end
|
|
86
180
|
end
|
|
87
181
|
end
|
|
@@ -14,6 +14,14 @@ module Datadog
|
|
|
14
14
|
# @return [String] comma-separated normalized key:value pairs
|
|
15
15
|
def self.serialized
|
|
16
16
|
return @serialized if defined?(@serialized)
|
|
17
|
+
|
|
18
|
+
@serialized = tags.join(',').freeze
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# This method returns an array in the format ["k1:v1","k2:v2","k3:v3"]
|
|
22
|
+
# @return [Array<String>] array of normalized key:value pairs
|
|
23
|
+
def self.tags
|
|
24
|
+
return @tags if defined?(@tags)
|
|
17
25
|
tags = []
|
|
18
26
|
|
|
19
27
|
workdir = TagNormalizer.normalize_process_value(entrypoint_workdir.to_s)
|
|
@@ -27,7 +35,7 @@ module Datadog
|
|
|
27
35
|
|
|
28
36
|
tags << "#{Environment::Ext::TAG_ENTRYPOINT_TYPE}:#{TagNormalizer.normalize(entrypoint_type, remove_digit_start_char: false)}"
|
|
29
37
|
|
|
30
|
-
@
|
|
38
|
+
@tags = tags.freeze
|
|
31
39
|
end
|
|
32
40
|
|
|
33
41
|
# Returns the last segment of the working directory of the process
|
|
@@ -81,6 +81,10 @@ module Datadog
|
|
|
81
81
|
|
|
82
82
|
return current_window_rate if @prev_conforming_messages.nil? || @prev_total_messages.nil?
|
|
83
83
|
|
|
84
|
+
# Steep: Due to https://github.com/soutaro/steep/issues/477,
|
|
85
|
+
# the previous nil check does not narrow type to Integer
|
|
86
|
+
# The annotation fixes the typing error, but it takes effect in the method
|
|
87
|
+
# @type ivar @prev_total_messages: Integer
|
|
84
88
|
(@conforming_messages.to_f + @prev_conforming_messages.to_f) / (@total_messages + @prev_total_messages)
|
|
85
89
|
end
|
|
86
90
|
|
|
@@ -154,7 +158,11 @@ module Datadog
|
|
|
154
158
|
if @current_window.nil?
|
|
155
159
|
@current_window = now
|
|
156
160
|
# If more than 1 second has past since last window, reset
|
|
157
|
-
|
|
161
|
+
#
|
|
162
|
+
# Steep: @current_window is a Float, but for some reason annotations does not work here
|
|
163
|
+
# Once a fix will be out for nil checks on instance variables, we can remove the steep:ignore
|
|
164
|
+
# https://github.com/soutaro/steep/issues/477
|
|
165
|
+
elsif now - @current_window >= 1 # steep:ignore UnresolvedOverloading
|
|
158
166
|
@prev_conforming_messages = @conforming_messages
|
|
159
167
|
@prev_total_messages = @total_messages
|
|
160
168
|
@conforming_messages = 0
|
|
@@ -14,10 +14,11 @@ module Datadog
|
|
|
14
14
|
|
|
15
15
|
class SyncError < StandardError; end
|
|
16
16
|
|
|
17
|
-
attr_reader :transport, :repository, :id, :dispatcher, :logger
|
|
17
|
+
attr_reader :transport, :repository, :id, :dispatcher, :settings, :logger
|
|
18
18
|
|
|
19
|
-
def initialize(transport, capabilities,
|
|
19
|
+
def initialize(transport, capabilities, settings:, logger:, repository: Configuration::Repository.new)
|
|
20
20
|
@transport = transport
|
|
21
|
+
@settings = settings
|
|
21
22
|
@logger = logger
|
|
22
23
|
|
|
23
24
|
@repository = repository
|
|
@@ -97,7 +98,9 @@ module Datadog
|
|
|
97
98
|
content = contents.find_content(path, target)
|
|
98
99
|
|
|
99
100
|
# abort entirely if matching content not found
|
|
100
|
-
|
|
101
|
+
if content.nil?
|
|
102
|
+
raise SyncError, "no valid content for target at path '#{path}'"
|
|
103
|
+
end
|
|
101
104
|
|
|
102
105
|
# to be added or updated << config
|
|
103
106
|
# TODO: metadata (hash, version, etc...)
|
|
@@ -153,14 +156,19 @@ module Datadog
|
|
|
153
156
|
language: Core::Environment::Identity.lang,
|
|
154
157
|
tracer_version: tracer_version,
|
|
155
158
|
service: service_name,
|
|
156
|
-
env:
|
|
159
|
+
env: settings.env,
|
|
157
160
|
tags: client_tracer_tags,
|
|
158
161
|
}
|
|
159
162
|
|
|
160
|
-
app_version =
|
|
163
|
+
app_version = settings.version
|
|
161
164
|
|
|
162
165
|
client_tracer[:app_version] = app_version if app_version
|
|
163
166
|
|
|
167
|
+
if settings.experimental_propagate_process_tags_enabled
|
|
168
|
+
process_tags = Core::Environment::Process.tags
|
|
169
|
+
client_tracer[:process_tags] = process_tags if process_tags.any?
|
|
170
|
+
end
|
|
171
|
+
|
|
164
172
|
{
|
|
165
173
|
client: {
|
|
166
174
|
state: {
|
|
@@ -184,7 +192,7 @@ module Datadog
|
|
|
184
192
|
end
|
|
185
193
|
|
|
186
194
|
def service_name
|
|
187
|
-
|
|
195
|
+
settings.remote.service || settings.service
|
|
188
196
|
end
|
|
189
197
|
|
|
190
198
|
def tracer_version
|
|
@@ -11,9 +11,11 @@ module Datadog
|
|
|
11
11
|
module Core
|
|
12
12
|
module Remote
|
|
13
13
|
# Configures the HTTP transport to communicate with the agent
|
|
14
|
-
# to fetch and sync the remote configuration
|
|
14
|
+
# to fetch and sync the remote configuration.
|
|
15
|
+
#
|
|
16
|
+
# @api private
|
|
15
17
|
class Component
|
|
16
|
-
attr_reader :logger, :client, :healthy
|
|
18
|
+
attr_reader :logger, :client, :healthy, :worker
|
|
17
19
|
|
|
18
20
|
def initialize(settings, capabilities, agent_settings, logger:)
|
|
19
21
|
@logger = logger
|
|
@@ -23,7 +25,7 @@ module Datadog
|
|
|
23
25
|
|
|
24
26
|
@barrier = Barrier.new(settings.remote.boot_timeout_seconds)
|
|
25
27
|
|
|
26
|
-
@client = Client.new(transport_v7, capabilities, logger: logger)
|
|
28
|
+
@client = Client.new(transport_v7, capabilities, settings: settings, logger: logger)
|
|
27
29
|
@healthy = false
|
|
28
30
|
logger.debug { "new remote configuration client: #{@client.id}" }
|
|
29
31
|
|
|
@@ -55,7 +57,7 @@ module Datadog
|
|
|
55
57
|
end
|
|
56
58
|
|
|
57
59
|
# client state is unknown, state might be corrupted
|
|
58
|
-
@client = Client.new(transport_v7, capabilities, logger: logger)
|
|
60
|
+
@client = Client.new(transport_v7, capabilities, settings: settings, logger: logger)
|
|
59
61
|
@healthy = false
|
|
60
62
|
logger.debug { "new remote configuration client: #{@client.id}" }
|
|
61
63
|
|
|
@@ -22,6 +22,18 @@ module Datadog
|
|
|
22
22
|
attr_accessor :version
|
|
23
23
|
|
|
24
24
|
def initialize(path:, data:)
|
|
25
|
+
if data.nil?
|
|
26
|
+
# +data+ is passed to Digest calculation and also is
|
|
27
|
+
# unconditionally taken length of by +length+ method.
|
|
28
|
+
# As such, the class is not written to expect +data+ to be nil.
|
|
29
|
+
# Detect bad incoming values here to provide earlier diagnostics
|
|
30
|
+
# when developing tests, for example.
|
|
31
|
+
raise ArgumentError, 'data must not be nil'
|
|
32
|
+
end
|
|
33
|
+
unless String === data
|
|
34
|
+
raise ArgumentError, "Invalid type for data: #{data.class}: expected String"
|
|
35
|
+
end
|
|
36
|
+
|
|
25
37
|
@path = path
|
|
26
38
|
@data = data
|
|
27
39
|
@apply_state = ApplyState::UNACKNOWLEDGED
|
|
@@ -72,8 +84,9 @@ module Datadog
|
|
|
72
84
|
private_class_method :new
|
|
73
85
|
end
|
|
74
86
|
|
|
75
|
-
# ContentList stores a list of
|
|
76
|
-
# It provides
|
|
87
|
+
# ContentList stores a list of Content instances.
|
|
88
|
+
# It provides convenient methods for finding content based on
|
|
89
|
+
# Configuration::Path and Configuration::Target.
|
|
77
90
|
class ContentList < Array
|
|
78
91
|
class << self
|
|
79
92
|
def parse(array)
|
|
@@ -24,10 +24,21 @@ module Datadog
|
|
|
24
24
|
class InvalidHashTypeError < StandardError; end
|
|
25
25
|
attr_reader :type, :hexdigest
|
|
26
26
|
|
|
27
|
-
DIGEST_CHUNK = 1024
|
|
28
|
-
|
|
29
27
|
class << self
|
|
30
28
|
def hexdigest(type, data)
|
|
29
|
+
unless String === data
|
|
30
|
+
# This class (Digest) passes +data+ to the Ruby standard
|
|
31
|
+
# library Digest routines without validating its type.
|
|
32
|
+
# The stdlib Digest requires a String, and the previous
|
|
33
|
+
# implementation of this class that used StringIO
|
|
34
|
+
# unconditionally read from +data+ without validating the
|
|
35
|
+
# type. Meaning, passing +nil+ as +data+ has never worked.
|
|
36
|
+
# It still doesn't work in the present implementation.
|
|
37
|
+
# Flag the nil data now to get earlier diagnostics when
|
|
38
|
+
# developing tests for example.
|
|
39
|
+
raise ArgumentError, "Invalid type for data: #{data.class}: expected String"
|
|
40
|
+
end
|
|
41
|
+
|
|
31
42
|
d = case type
|
|
32
43
|
when :sha256
|
|
33
44
|
::Digest::SHA256.new
|
|
@@ -37,13 +48,9 @@ module Datadog
|
|
|
37
48
|
raise InvalidHashTypeError, type
|
|
38
49
|
end
|
|
39
50
|
|
|
40
|
-
|
|
41
|
-
d.update(buf)
|
|
42
|
-
end
|
|
51
|
+
d.update(data)
|
|
43
52
|
|
|
44
53
|
d.hexdigest
|
|
45
|
-
ensure
|
|
46
|
-
data.rewind
|
|
47
54
|
end
|
|
48
55
|
end
|
|
49
56
|
|
|
@@ -11,8 +11,15 @@ module Datadog
|
|
|
11
11
|
class TargetMap < Hash
|
|
12
12
|
class << self
|
|
13
13
|
def parse(hash)
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
signed = hash.fetch('signed')
|
|
15
|
+
# Note that the +dig+ call permits +hash['signed']+ to be
|
|
16
|
+
# missing the +custom+ subtree entirely.
|
|
17
|
+
# Previously the subtree was required but +opaque_backend_state+
|
|
18
|
+
# could still be missing (and obtained here as nil).
|
|
19
|
+
opaque_backend_state = signed.dig('custom', 'opaque_backend_state')
|
|
20
|
+
# The version appears to be optional to the rest of this class,
|
|
21
|
+
# and we have tests that do not provide it.
|
|
22
|
+
version = signed['version']
|
|
16
23
|
|
|
17
24
|
map = new
|
|
18
25
|
|
|
@@ -21,7 +28,7 @@ module Datadog
|
|
|
21
28
|
@version = version
|
|
22
29
|
end
|
|
23
30
|
|
|
24
|
-
|
|
31
|
+
signed.fetch('targets').each_with_object(map) do |(p, t), m|
|
|
25
32
|
path = Configuration::Path.parse(p)
|
|
26
33
|
target = Configuration::Target.parse(t)
|
|
27
34
|
|
|
@@ -46,9 +53,9 @@ module Datadog
|
|
|
46
53
|
class Target
|
|
47
54
|
class << self
|
|
48
55
|
def parse(hash)
|
|
49
|
-
length = Integer(hash
|
|
50
|
-
digests = Configuration::DigestList.parse(hash
|
|
51
|
-
version = Integer(hash
|
|
56
|
+
length = Integer(hash.fetch('length'))
|
|
57
|
+
digests = Configuration::DigestList.parse(hash.fetch('hashes'))
|
|
58
|
+
version = Integer(hash.dig('custom', 'v'))
|
|
52
59
|
|
|
53
60
|
new(digests: digests, length: length, version: version)
|
|
54
61
|
end
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require_relative '../../../core/transport/request'
|
|
4
4
|
require_relative '../../../core/transport/parcel'
|
|
5
|
+
require_relative '../../../core/transport/transport'
|
|
5
6
|
require_relative 'http/config'
|
|
6
7
|
|
|
7
8
|
module Datadog
|
|
@@ -23,27 +24,13 @@ module Datadog
|
|
|
23
24
|
end
|
|
24
25
|
|
|
25
26
|
# Config transport
|
|
26
|
-
class Transport
|
|
27
|
-
attr_reader :client, :apis, :default_api, :current_api_id, :logger
|
|
28
|
-
|
|
29
|
-
def initialize(apis, default_api, logger: Datadog.logger)
|
|
30
|
-
@apis = apis
|
|
31
|
-
@logger = logger
|
|
32
|
-
|
|
33
|
-
@client = Remote::Transport::HTTP::Config::Client.new(current_api, logger: logger)
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
##### there is only one transport! it's negotiation!
|
|
27
|
+
class Transport < Core::Transport::Transport
|
|
37
28
|
def send_config(payload)
|
|
38
29
|
json = JSON.dump(payload)
|
|
39
30
|
parcel = EncodedParcel.new(json)
|
|
40
31
|
request = Request.new(parcel)
|
|
41
32
|
|
|
42
|
-
@client.
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
def current_api
|
|
46
|
-
@apis[HTTP::API::V7]
|
|
33
|
+
@client.send_request(:config, request)
|
|
47
34
|
end
|
|
48
35
|
end
|
|
49
36
|
end
|