datadog 2.3.0 → 2.5.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 +64 -2
- data/ext/datadog_profiling_loader/datadog_profiling_loader.c +9 -1
- data/ext/datadog_profiling_loader/extconf.rb +10 -22
- data/ext/datadog_profiling_native_extension/NativeExtensionDesign.md +3 -3
- data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +198 -41
- data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.c +4 -2
- data/ext/datadog_profiling_native_extension/collectors_stack.c +89 -46
- data/ext/datadog_profiling_native_extension/collectors_thread_context.c +645 -107
- data/ext/datadog_profiling_native_extension/collectors_thread_context.h +15 -1
- data/ext/datadog_profiling_native_extension/datadog_ruby_common.c +0 -27
- data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +0 -4
- data/ext/datadog_profiling_native_extension/extconf.rb +42 -25
- data/ext/datadog_profiling_native_extension/gvl_profiling_helper.c +50 -0
- data/ext/datadog_profiling_native_extension/gvl_profiling_helper.h +75 -0
- data/ext/datadog_profiling_native_extension/heap_recorder.c +194 -34
- data/ext/datadog_profiling_native_extension/heap_recorder.h +11 -0
- data/ext/datadog_profiling_native_extension/http_transport.c +38 -6
- data/ext/datadog_profiling_native_extension/native_extension_helpers.rb +1 -1
- data/ext/datadog_profiling_native_extension/private_vm_api_access.c +53 -2
- data/ext/datadog_profiling_native_extension/private_vm_api_access.h +3 -0
- data/ext/datadog_profiling_native_extension/profiling.c +1 -1
- data/ext/datadog_profiling_native_extension/ruby_helpers.c +14 -11
- data/ext/datadog_profiling_native_extension/stack_recorder.c +58 -22
- data/ext/datadog_profiling_native_extension/stack_recorder.h +2 -0
- data/ext/libdatadog_api/crashtracker.c +20 -18
- data/ext/libdatadog_api/datadog_ruby_common.c +0 -27
- data/ext/libdatadog_api/datadog_ruby_common.h +0 -4
- data/ext/libdatadog_extconf_helpers.rb +1 -1
- data/lib/datadog/appsec/assets/waf_rules/recommended.json +2184 -108
- data/lib/datadog/appsec/assets/waf_rules/strict.json +1430 -2
- data/lib/datadog/appsec/component.rb +29 -8
- data/lib/datadog/appsec/configuration/settings.rb +10 -2
- data/lib/datadog/appsec/contrib/devise/patcher/authenticatable_patch.rb +1 -0
- data/lib/datadog/appsec/contrib/devise/patcher/rememberable_patch.rb +21 -0
- data/lib/datadog/appsec/contrib/devise/patcher.rb +12 -2
- data/lib/datadog/appsec/contrib/graphql/appsec_trace.rb +0 -14
- data/lib/datadog/appsec/contrib/graphql/gateway/multiplex.rb +67 -31
- data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +14 -15
- data/lib/datadog/appsec/contrib/graphql/integration.rb +14 -1
- data/lib/datadog/appsec/contrib/graphql/reactive/multiplex.rb +7 -20
- data/lib/datadog/appsec/contrib/rack/gateway/request.rb +2 -5
- data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +9 -15
- data/lib/datadog/appsec/contrib/rack/reactive/request.rb +6 -18
- data/lib/datadog/appsec/contrib/rack/reactive/request_body.rb +7 -20
- data/lib/datadog/appsec/contrib/rack/reactive/response.rb +5 -18
- data/lib/datadog/appsec/contrib/rack/request_middleware.rb +3 -1
- data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +3 -5
- data/lib/datadog/appsec/contrib/rails/reactive/action.rb +5 -18
- data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +6 -10
- data/lib/datadog/appsec/contrib/sinatra/reactive/routed.rb +7 -20
- data/lib/datadog/appsec/event.rb +25 -1
- data/lib/datadog/appsec/ext.rb +4 -0
- data/lib/datadog/appsec/monitor/gateway/watcher.rb +3 -5
- data/lib/datadog/appsec/monitor/reactive/set_user.rb +7 -20
- data/lib/datadog/appsec/processor/context.rb +109 -0
- data/lib/datadog/appsec/processor/rule_loader.rb +3 -1
- data/lib/datadog/appsec/processor/rule_merger.rb +33 -15
- data/lib/datadog/appsec/processor.rb +42 -107
- data/lib/datadog/appsec/rate_limiter.rb +25 -40
- data/lib/datadog/appsec/remote.rb +7 -3
- data/lib/datadog/appsec/scope.rb +1 -4
- data/lib/datadog/appsec/utils/trace_operation.rb +15 -0
- data/lib/datadog/appsec/utils.rb +2 -0
- data/lib/datadog/appsec.rb +3 -2
- data/lib/datadog/core/configuration/agent_settings_resolver.rb +26 -25
- data/lib/datadog/core/configuration/components.rb +4 -3
- data/lib/datadog/core/configuration/settings.rb +96 -5
- data/lib/datadog/core/configuration.rb +1 -3
- data/lib/datadog/core/crashtracking/component.rb +9 -6
- data/lib/datadog/core/environment/execution.rb +5 -5
- data/lib/datadog/core/environment/yjit.rb +5 -0
- data/lib/datadog/core/metrics/client.rb +7 -0
- data/lib/datadog/core/rate_limiter.rb +183 -0
- data/lib/datadog/core/remote/client/capabilities.rb +4 -3
- data/lib/datadog/core/remote/component.rb +4 -2
- data/lib/datadog/core/remote/negotiation.rb +4 -4
- data/lib/datadog/core/remote/tie.rb +2 -0
- data/lib/datadog/core/remote/transport/http.rb +5 -0
- data/lib/datadog/core/remote/worker.rb +1 -1
- data/lib/datadog/core/runtime/ext.rb +1 -0
- data/lib/datadog/core/runtime/metrics.rb +5 -1
- data/lib/datadog/core/semaphore.rb +35 -0
- data/lib/datadog/core/telemetry/component.rb +2 -0
- data/lib/datadog/core/telemetry/event.rb +12 -7
- data/lib/datadog/core/telemetry/logger.rb +51 -0
- data/lib/datadog/core/telemetry/logging.rb +50 -14
- data/lib/datadog/core/telemetry/request.rb +13 -1
- data/lib/datadog/core/transport/ext.rb +1 -0
- data/lib/datadog/core/utils/time.rb +12 -0
- data/lib/datadog/core/workers/async.rb +1 -1
- data/lib/datadog/di/code_tracker.rb +166 -0
- data/lib/datadog/di/configuration/settings.rb +163 -0
- data/lib/datadog/di/configuration.rb +11 -0
- data/lib/datadog/di/error.rb +31 -0
- data/lib/datadog/di/extensions.rb +16 -0
- data/lib/datadog/di/instrumenter.rb +301 -0
- data/lib/datadog/di/probe.rb +162 -0
- data/lib/datadog/di/probe_builder.rb +47 -0
- data/lib/datadog/di/probe_notification_builder.rb +207 -0
- data/lib/datadog/di/probe_notifier_worker.rb +244 -0
- data/lib/datadog/di/redactor.rb +188 -0
- data/lib/datadog/di/serializer.rb +215 -0
- data/lib/datadog/di/transport.rb +67 -0
- data/lib/datadog/di/utils.rb +39 -0
- data/lib/datadog/di.rb +57 -0
- data/lib/datadog/opentelemetry/sdk/propagator.rb +2 -0
- data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +12 -10
- data/lib/datadog/profiling/collectors/info.rb +12 -3
- data/lib/datadog/profiling/collectors/thread_context.rb +32 -8
- data/lib/datadog/profiling/component.rb +21 -4
- data/lib/datadog/profiling/http_transport.rb +6 -1
- data/lib/datadog/profiling/scheduler.rb +2 -0
- data/lib/datadog/profiling/stack_recorder.rb +40 -9
- data/lib/datadog/single_step_instrument.rb +12 -0
- data/lib/datadog/tracing/component.rb +13 -0
- data/lib/datadog/tracing/contrib/action_cable/instrumentation.rb +8 -12
- data/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb +5 -0
- data/lib/datadog/tracing/contrib/action_pack/action_dispatch/instrumentation.rb +78 -0
- data/lib/datadog/tracing/contrib/action_pack/action_dispatch/patcher.rb +33 -0
- data/lib/datadog/tracing/contrib/action_pack/patcher.rb +2 -0
- data/lib/datadog/tracing/contrib/active_record/configuration/resolver.rb +4 -0
- data/lib/datadog/tracing/contrib/active_record/events/instantiation.rb +3 -1
- data/lib/datadog/tracing/contrib/active_record/events/sql.rb +3 -1
- data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +5 -1
- data/lib/datadog/tracing/contrib/aws/instrumentation.rb +5 -0
- data/lib/datadog/tracing/contrib/elasticsearch/patcher.rb +6 -1
- data/lib/datadog/tracing/contrib/ethon/easy_patch.rb +4 -0
- data/lib/datadog/tracing/contrib/excon/middleware.rb +3 -0
- data/lib/datadog/tracing/contrib/faraday/middleware.rb +12 -0
- data/lib/datadog/tracing/contrib/grape/endpoint.rb +24 -2
- data/lib/datadog/tracing/contrib/graphql/patcher.rb +9 -12
- data/lib/datadog/tracing/contrib/graphql/trace_patcher.rb +3 -3
- data/lib/datadog/tracing/contrib/graphql/tracing_patcher.rb +3 -3
- data/lib/datadog/tracing/contrib/graphql/unified_trace.rb +13 -9
- data/lib/datadog/tracing/contrib/graphql/unified_trace_patcher.rb +6 -3
- data/lib/datadog/tracing/contrib/http/circuit_breaker.rb +9 -0
- data/lib/datadog/tracing/contrib/http/instrumentation.rb +22 -15
- data/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +10 -5
- data/lib/datadog/tracing/contrib/httpclient/patcher.rb +1 -14
- data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +9 -0
- data/lib/datadog/tracing/contrib/httprb/patcher.rb +1 -14
- data/lib/datadog/tracing/contrib/lograge/patcher.rb +1 -2
- data/lib/datadog/tracing/contrib/mongodb/subscribers.rb +2 -0
- data/lib/datadog/tracing/contrib/opensearch/patcher.rb +13 -6
- data/lib/datadog/tracing/contrib/patcher.rb +2 -1
- data/lib/datadog/tracing/contrib/presto/patcher.rb +1 -13
- data/lib/datadog/tracing/contrib/rack/middlewares.rb +27 -0
- data/lib/datadog/tracing/contrib/rails/runner.rb +1 -1
- data/lib/datadog/tracing/contrib/redis/tags.rb +4 -0
- data/lib/datadog/tracing/contrib/rest_client/request_patch.rb +3 -0
- data/lib/datadog/tracing/contrib/sinatra/tracer.rb +4 -0
- data/lib/datadog/tracing/contrib/stripe/request.rb +3 -2
- data/lib/datadog/tracing/distributed/propagation.rb +7 -0
- data/lib/datadog/tracing/metadata/ext.rb +2 -0
- data/lib/datadog/tracing/remote.rb +5 -2
- data/lib/datadog/tracing/sampling/matcher.rb +6 -1
- data/lib/datadog/tracing/sampling/rate_sampler.rb +1 -1
- data/lib/datadog/tracing/sampling/rule.rb +2 -0
- data/lib/datadog/tracing/sampling/rule_sampler.rb +15 -9
- data/lib/datadog/tracing/sampling/span/ext.rb +1 -1
- data/lib/datadog/tracing/sampling/span/rule.rb +2 -2
- data/lib/datadog/tracing/trace_operation.rb +26 -2
- data/lib/datadog/tracing/tracer.rb +29 -22
- data/lib/datadog/tracing/transport/http/client.rb +1 -0
- data/lib/datadog/tracing/transport/http.rb +4 -0
- data/lib/datadog/tracing/transport/io/client.rb +1 -0
- data/lib/datadog/tracing/workers/trace_writer.rb +1 -1
- data/lib/datadog/tracing/workers.rb +2 -2
- data/lib/datadog/tracing/writer.rb +26 -28
- data/lib/datadog/version.rb +1 -1
- metadata +40 -15
- data/lib/datadog/tracing/sampling/rate_limiter.rb +0 -185
@@ -0,0 +1,183 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'utils/time'
|
4
|
+
|
5
|
+
module Datadog
|
6
|
+
module Core
|
7
|
+
# Checks for rate limiting on a resource.
|
8
|
+
class RateLimiter
|
9
|
+
# Checks if resource of specified size can be
|
10
|
+
# conforms with the current limit.
|
11
|
+
#
|
12
|
+
# Implementations of this method are not guaranteed
|
13
|
+
# to be side-effect free.
|
14
|
+
#
|
15
|
+
# @return [Boolean] whether a resource conforms with the current limit
|
16
|
+
def allow?(size = 1); end
|
17
|
+
|
18
|
+
# The effective rate limiting ratio based on
|
19
|
+
# recent calls to `allow?`.
|
20
|
+
#
|
21
|
+
# @return [Float] recent allowance ratio
|
22
|
+
def effective_rate; end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Implementation of the Token Bucket metering algorithm
|
26
|
+
# for rate limiting.
|
27
|
+
#
|
28
|
+
# @see https://en.wikipedia.org/wiki/Token_bucket Token bucket
|
29
|
+
class TokenBucket < RateLimiter
|
30
|
+
attr_reader :rate, :max_tokens
|
31
|
+
|
32
|
+
# @param rate [Numeric] Allowance rate, in units per second
|
33
|
+
# if rate is negative, always allow
|
34
|
+
# if rate is zero, never allow
|
35
|
+
# @param max_tokens [Numeric] Limit of available tokens
|
36
|
+
def initialize(rate, max_tokens = rate)
|
37
|
+
super()
|
38
|
+
|
39
|
+
raise ArgumentError, "rate must be a number: #{rate}" unless rate.is_a?(Numeric)
|
40
|
+
raise ArgumentError, "max_tokens must be a number: #{max_tokens}" unless max_tokens.is_a?(Numeric)
|
41
|
+
|
42
|
+
@rate = rate
|
43
|
+
@max_tokens = max_tokens
|
44
|
+
|
45
|
+
@tokens = max_tokens
|
46
|
+
@total_messages = 0
|
47
|
+
@conforming_messages = 0
|
48
|
+
@prev_conforming_messages = nil
|
49
|
+
@prev_total_messages = nil
|
50
|
+
@current_window = nil
|
51
|
+
|
52
|
+
@last_refill = Core::Utils::Time.get_time
|
53
|
+
end
|
54
|
+
|
55
|
+
# Checks if a message of provided +size+
|
56
|
+
# conforms with the current bucket limit.
|
57
|
+
#
|
58
|
+
# If it does, return +true+ and remove +size+
|
59
|
+
# tokens from the bucket.
|
60
|
+
# If it does not, return +false+ without affecting
|
61
|
+
# the tokens from the bucket.
|
62
|
+
#
|
63
|
+
# @return [Boolean] +true+ if message conforms with current bucket limit
|
64
|
+
def allow?(size = 1)
|
65
|
+
allowed = should_allow?(size)
|
66
|
+
update_rate_counts(allowed)
|
67
|
+
allowed
|
68
|
+
end
|
69
|
+
|
70
|
+
# Ratio of 'conformance' per 'total messages' checked
|
71
|
+
# averaged for the past 2 buckets
|
72
|
+
#
|
73
|
+
# Returns +1.0+ when no messages have been checked yet.
|
74
|
+
#
|
75
|
+
# @return [Float] Conformance ratio, between +[0,1]+
|
76
|
+
def effective_rate
|
77
|
+
return 0.0 if @rate.zero?
|
78
|
+
return 1.0 if @rate < 0 || @total_messages.zero?
|
79
|
+
|
80
|
+
return current_window_rate if @prev_conforming_messages.nil? || @prev_total_messages.nil?
|
81
|
+
|
82
|
+
(@conforming_messages.to_f + @prev_conforming_messages.to_f) / (@total_messages + @prev_total_messages)
|
83
|
+
end
|
84
|
+
|
85
|
+
# Ratio of 'conformance' per 'total messages' checked
|
86
|
+
# on this bucket
|
87
|
+
#
|
88
|
+
# Returns +1.0+ when no messages have been checked yet.
|
89
|
+
#
|
90
|
+
# @return [Float] Conformance ratio, between +[0,1]+
|
91
|
+
def current_window_rate
|
92
|
+
return 1.0 if @total_messages.zero?
|
93
|
+
|
94
|
+
@conforming_messages.to_f / @total_messages
|
95
|
+
end
|
96
|
+
|
97
|
+
# @return [Numeric] number of tokens currently available
|
98
|
+
def available_tokens
|
99
|
+
@tokens
|
100
|
+
end
|
101
|
+
|
102
|
+
private
|
103
|
+
|
104
|
+
def refill_since_last_message
|
105
|
+
now = Core::Utils::Time.get_time
|
106
|
+
elapsed = now - @last_refill
|
107
|
+
|
108
|
+
# Update the number of available tokens, but ensure we do not exceed the max
|
109
|
+
# we return the min of tokens + rate*elapsed, or max tokens
|
110
|
+
refill_tokens(@rate * elapsed)
|
111
|
+
|
112
|
+
@last_refill = now
|
113
|
+
end
|
114
|
+
|
115
|
+
def refill_tokens(size)
|
116
|
+
@tokens += size
|
117
|
+
@tokens = @max_tokens if @tokens > @max_tokens
|
118
|
+
end
|
119
|
+
|
120
|
+
def increment_total_count
|
121
|
+
@total_messages += 1
|
122
|
+
end
|
123
|
+
|
124
|
+
def increment_conforming_count
|
125
|
+
@conforming_messages += 1
|
126
|
+
end
|
127
|
+
|
128
|
+
def should_allow?(size = 1)
|
129
|
+
# rate limit of 0 blocks everything
|
130
|
+
return false if @rate.zero?
|
131
|
+
|
132
|
+
# negative rate limit disables rate limiting
|
133
|
+
return true if @rate < 0
|
134
|
+
|
135
|
+
refill_since_last_message
|
136
|
+
|
137
|
+
# if tokens < 1 we don't allow?
|
138
|
+
return false if @tokens < size
|
139
|
+
|
140
|
+
@tokens -= size
|
141
|
+
|
142
|
+
true
|
143
|
+
end
|
144
|
+
|
145
|
+
# Sets and Updates the past two 1 second windows for which
|
146
|
+
# the rate limiter must compute it's rate over and updates
|
147
|
+
# the total count, and conforming message count if +allowed+
|
148
|
+
def update_rate_counts(allowed)
|
149
|
+
now = Core::Utils::Time.get_time
|
150
|
+
|
151
|
+
# No tokens have been seen yet, start a new window
|
152
|
+
if @current_window.nil?
|
153
|
+
@current_window = now
|
154
|
+
# If more than 1 second has past since last window, reset
|
155
|
+
elsif now - @current_window >= 1
|
156
|
+
@prev_conforming_messages = @conforming_messages
|
157
|
+
@prev_total_messages = @total_messages
|
158
|
+
@conforming_messages = 0
|
159
|
+
@total_messages = 0
|
160
|
+
@current_window = now
|
161
|
+
end
|
162
|
+
|
163
|
+
increment_conforming_count if allowed
|
164
|
+
|
165
|
+
increment_total_count
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
# {Datadog::Core::RateLimiter} that accepts all resources,
|
170
|
+
# with no limits.
|
171
|
+
class UnlimitedLimiter < RateLimiter
|
172
|
+
# @return [Boolean] always +true+
|
173
|
+
def allow?(_ = 1)
|
174
|
+
true
|
175
|
+
end
|
176
|
+
|
177
|
+
# @return [Float] always 100%
|
178
|
+
def effective_rate
|
179
|
+
1.0
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
@@ -12,10 +12,11 @@ module Datadog
|
|
12
12
|
class Capabilities
|
13
13
|
attr_reader :products, :capabilities, :receivers, :base64_capabilities
|
14
14
|
|
15
|
-
def initialize(settings)
|
15
|
+
def initialize(settings, telemetry)
|
16
16
|
@capabilities = []
|
17
17
|
@products = []
|
18
18
|
@receivers = []
|
19
|
+
@telemetry = telemetry
|
19
20
|
|
20
21
|
register(settings)
|
21
22
|
|
@@ -28,12 +29,12 @@ module Datadog
|
|
28
29
|
if settings.respond_to?(:appsec) && settings.appsec.enabled
|
29
30
|
register_capabilities(Datadog::AppSec::Remote.capabilities)
|
30
31
|
register_products(Datadog::AppSec::Remote.products)
|
31
|
-
register_receivers(Datadog::AppSec::Remote.receivers)
|
32
|
+
register_receivers(Datadog::AppSec::Remote.receivers(@telemetry))
|
32
33
|
end
|
33
34
|
|
34
35
|
register_capabilities(Datadog::Tracing::Remote.capabilities)
|
35
36
|
register_products(Datadog::Tracing::Remote.products)
|
36
|
-
register_receivers(Datadog::Tracing::Remote.receivers)
|
37
|
+
register_receivers(Datadog::Tracing::Remote.receivers(@telemetry))
|
37
38
|
end
|
38
39
|
|
39
40
|
def register_capabilities(capabilities)
|
@@ -39,6 +39,7 @@ module Datadog
|
|
39
39
|
@client.sync
|
40
40
|
@healthy ||= true
|
41
41
|
rescue Client::SyncError => e
|
42
|
+
# Transient errors due to network or agent. Logged the error but not via telemetry
|
42
43
|
Datadog.logger.error do
|
43
44
|
"remote worker client sync error: #{e.message} location: #{Array(e.backtrace).first}. skipping sync"
|
44
45
|
end
|
@@ -48,6 +49,7 @@ module Datadog
|
|
48
49
|
# negotiation object stores error logging state that should be reset.
|
49
50
|
negotiation = Negotiation.new(settings, agent_settings)
|
50
51
|
|
52
|
+
# Transient errors due to network or agent. Logged the error but not via telemetry
|
51
53
|
Datadog.logger.error do
|
52
54
|
"remote worker error: #{e.class.name} #{e.message} location: #{Array(e.backtrace).first}. "\
|
53
55
|
'reseting client state'
|
@@ -150,10 +152,10 @@ module Datadog
|
|
150
152
|
#
|
151
153
|
# Those checks are instead performed inside the worker loop.
|
152
154
|
# This allows users to upgrade their agent while keeping their application running.
|
153
|
-
def build(settings, agent_settings)
|
155
|
+
def build(settings, agent_settings, telemetry:)
|
154
156
|
return unless settings.remote.enabled
|
155
157
|
|
156
|
-
new(settings, Client::Capabilities.new(settings), agent_settings)
|
158
|
+
new(settings, Client::Capabilities.new(settings, telemetry), agent_settings)
|
157
159
|
end
|
158
160
|
end
|
159
161
|
end
|
@@ -20,7 +20,7 @@ module Datadog
|
|
20
20
|
|
21
21
|
if res.internal_error? && network_error?(res.error)
|
22
22
|
unless @logged[:agent_unreachable]
|
23
|
-
Datadog.logger.
|
23
|
+
Datadog.logger.warn { "agent unreachable: cannot negotiate #{path}" }
|
24
24
|
@logged[:agent_unreachable] = true
|
25
25
|
end
|
26
26
|
|
@@ -29,7 +29,7 @@ module Datadog
|
|
29
29
|
|
30
30
|
if res.not_found?
|
31
31
|
unless @logged[:no_info_endpoint]
|
32
|
-
Datadog.logger.
|
32
|
+
Datadog.logger.warn { "agent reachable but has no /info endpoint: cannot negotiate #{path}" }
|
33
33
|
@logged[:no_info_endpoint] = true
|
34
34
|
end
|
35
35
|
|
@@ -38,7 +38,7 @@ module Datadog
|
|
38
38
|
|
39
39
|
unless res.ok?
|
40
40
|
unless @logged[:unexpected_response]
|
41
|
-
Datadog.logger.
|
41
|
+
Datadog.logger.warn { "agent reachable but unexpected response: cannot negotiate #{path}" }
|
42
42
|
@logged[:unexpected_response] = true
|
43
43
|
end
|
44
44
|
|
@@ -47,7 +47,7 @@ module Datadog
|
|
47
47
|
|
48
48
|
unless res.endpoints.include?(path)
|
49
49
|
unless @logged[:no_config_endpoint]
|
50
|
-
Datadog.logger.
|
50
|
+
Datadog.logger.warn { "agent reachable but does not report #{path}" }
|
51
51
|
@logged[:no_config_endpoint] = true
|
52
52
|
end
|
53
53
|
|
@@ -120,6 +120,11 @@ module Datadog
|
|
120
120
|
# Add container ID, if present.
|
121
121
|
container_id = Datadog::Core::Environment::Container.container_id
|
122
122
|
headers[Datadog::Core::Transport::Ext::HTTP::HEADER_CONTAINER_ID] = container_id unless container_id.nil?
|
123
|
+
# Sending this header to the agent will disable metrics computation (and billing) on the agent side
|
124
|
+
# by pretending it has already been done on the library side.
|
125
|
+
if Datadog.configuration.appsec.standalone.enabled
|
126
|
+
headers[Datadog::Core::Transport::Ext::HTTP::HEADER_CLIENT_COMPUTED_STATS] = 'yes'
|
127
|
+
end
|
123
128
|
end
|
124
129
|
end
|
125
130
|
|
@@ -34,7 +34,7 @@ module Datadog
|
|
34
34
|
@starting = true
|
35
35
|
|
36
36
|
thread = Thread.new { poll(@interval) }
|
37
|
-
thread.name = self.class.name
|
37
|
+
thread.name = self.class.name
|
38
38
|
thread.thread_variable_set(:fork_safe, true)
|
39
39
|
@thr = thread
|
40
40
|
|
@@ -31,6 +31,7 @@ module Datadog
|
|
31
31
|
METRIC_YJIT_OBJECT_SHAPE_COUNT = 'runtime.ruby.yjit.object_shape_count'
|
32
32
|
METRIC_YJIT_OUTLINED_CODE_SIZE = 'runtime.ruby.yjit.outlined_code_size'
|
33
33
|
METRIC_YJIT_YJIT_ALLOC_SIZE = 'runtime.ruby.yjit.yjit_alloc_size'
|
34
|
+
METRIC_YJIT_RATIO_IN_YJIT = 'runtime.ruby.yjit.ratio_in_yjit'
|
34
35
|
|
35
36
|
TAG_SERVICE = 'service'
|
36
37
|
end
|
@@ -94,7 +94,7 @@ module Datadog
|
|
94
94
|
def try_flush
|
95
95
|
yield
|
96
96
|
rescue StandardError => e
|
97
|
-
Datadog.logger.
|
97
|
+
Datadog.logger.warn("Error while sending runtime metric. Cause: #{e.class.name} #{e.message}")
|
98
98
|
end
|
99
99
|
|
100
100
|
def default_metric_options
|
@@ -181,6 +181,10 @@ module Datadog
|
|
181
181
|
Core::Runtime::Ext::Metrics::METRIC_YJIT_YJIT_ALLOC_SIZE,
|
182
182
|
Core::Environment::YJIT.yjit_alloc_size
|
183
183
|
)
|
184
|
+
gauge_if_not_nil(
|
185
|
+
Core::Runtime::Ext::Metrics::METRIC_YJIT_RATIO_IN_YJIT,
|
186
|
+
Core::Environment::YJIT.ratio_in_yjit
|
187
|
+
)
|
184
188
|
end
|
185
189
|
end
|
186
190
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Datadog
|
4
|
+
module Core
|
5
|
+
# Semaphore pattern implementation, as described in documentation for
|
6
|
+
# ConditionVariable.
|
7
|
+
#
|
8
|
+
# @api private
|
9
|
+
class Semaphore
|
10
|
+
def initialize
|
11
|
+
@wake_lock = Mutex.new
|
12
|
+
@wake = ConditionVariable.new
|
13
|
+
end
|
14
|
+
|
15
|
+
def signal
|
16
|
+
wake_lock.synchronize do
|
17
|
+
wake.signal
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def wait(timeout = nil)
|
22
|
+
wake_lock.synchronize do
|
23
|
+
# steep specifies that the second argument to wait is of type
|
24
|
+
# ::Time::_Timeout which for some reason is not Numeric and is not
|
25
|
+
# castable from Numeric.
|
26
|
+
wake.wait(wake_lock, timeout) # steep:ignore
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
attr_reader :wake_lock, :wake
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -5,6 +5,7 @@ require_relative 'event'
|
|
5
5
|
require_relative 'http/transport'
|
6
6
|
require_relative 'metrics_manager'
|
7
7
|
require_relative 'worker'
|
8
|
+
require_relative 'logging'
|
8
9
|
|
9
10
|
require_relative '../configuration/ext'
|
10
11
|
require_relative '../utils/forking'
|
@@ -17,6 +18,7 @@ module Datadog
|
|
17
18
|
attr_reader :enabled
|
18
19
|
|
19
20
|
include Core::Utils::Forking
|
21
|
+
include Telemetry::Logging
|
20
22
|
|
21
23
|
def self.build(settings, agent_settings, logger)
|
22
24
|
enabled = settings.telemetry.enabled
|
@@ -1,5 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative '../utils/forking'
|
4
|
+
require_relative '../utils/sequence'
|
5
|
+
|
3
6
|
module Datadog
|
4
7
|
module Core
|
5
8
|
module Telemetry
|
@@ -338,7 +341,6 @@ module Datadog
|
|
338
341
|
class Log < Base
|
339
342
|
LEVELS = {
|
340
343
|
error: 'ERROR',
|
341
|
-
debug: 'DEBUG',
|
342
344
|
warn: 'WARN',
|
343
345
|
}.freeze
|
344
346
|
|
@@ -346,19 +348,22 @@ module Datadog
|
|
346
348
|
'logs'
|
347
349
|
end
|
348
350
|
|
349
|
-
def initialize(message:, level:)
|
351
|
+
def initialize(message:, level:, stack_trace: nil)
|
350
352
|
super()
|
351
353
|
@message = message
|
354
|
+
@stack_trace = stack_trace
|
352
355
|
@level = LEVELS.fetch(level) { |k| raise ArgumentError, "Invalid log level :#{k}" }
|
353
356
|
end
|
354
357
|
|
355
358
|
def payload
|
356
359
|
{
|
357
|
-
logs: [
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
360
|
+
logs: [
|
361
|
+
{
|
362
|
+
message: @message,
|
363
|
+
level: @level,
|
364
|
+
stack_trace: @stack_trace,
|
365
|
+
}.compact
|
366
|
+
]
|
362
367
|
}
|
363
368
|
end
|
364
369
|
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Datadog
|
4
|
+
module Core
|
5
|
+
module Telemetry
|
6
|
+
# === INTERNAL USAGE ONLY ===
|
7
|
+
#
|
8
|
+
# Report telemetry logs via delegating to the telemetry component instance via mutex.
|
9
|
+
#
|
10
|
+
# IMPORTANT: Invoking this method during the lifecycle of component initialization will
|
11
|
+
# be no-op instead.
|
12
|
+
#
|
13
|
+
# For developer using this module:
|
14
|
+
# read: lib/datadog/core/telemetry/logging.rb
|
15
|
+
module Logger
|
16
|
+
class << self
|
17
|
+
def report(exception, level: :error, description: nil)
|
18
|
+
instance&.report(exception, level: level, description: description)
|
19
|
+
end
|
20
|
+
|
21
|
+
def error(description)
|
22
|
+
instance&.error(description)
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def instance
|
28
|
+
# Component initialization uses a mutex to avoid having concurrent initialization.
|
29
|
+
# Trying to access the telemetry component during initialization (specifically:
|
30
|
+
# from the thread that's actually doing the initialization) would cause a deadlock,
|
31
|
+
# since accessing the components would try to recursively lock the mutex.
|
32
|
+
#
|
33
|
+
# To work around this, we use allow_initialization: false to avoid triggering this issue.
|
34
|
+
#
|
35
|
+
# The downside is: this leaves us unable to report telemetry during component initialization.
|
36
|
+
components = Datadog.send(:components, allow_initialization: false)
|
37
|
+
|
38
|
+
if components && components.telemetry
|
39
|
+
components.telemetry
|
40
|
+
else
|
41
|
+
Datadog.logger.warn(
|
42
|
+
'Failed to send telemetry before components initialization or within components lifecycle'
|
43
|
+
)
|
44
|
+
nil
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -2,32 +2,68 @@
|
|
2
2
|
|
3
3
|
require_relative 'event'
|
4
4
|
|
5
|
+
require 'pathname'
|
6
|
+
|
5
7
|
module Datadog
|
6
8
|
module Core
|
7
9
|
module Telemetry
|
8
|
-
#
|
10
|
+
# === INTERNAL USAGE ONLY ===
|
11
|
+
#
|
12
|
+
# Logging interface for sending telemetry logs... so we can fix them.
|
13
|
+
#
|
14
|
+
# For developer using this module:
|
15
|
+
# - MUST NOT provide any sensitive information (PII)
|
16
|
+
# - SHOULD reduce the data cardinality for batching/aggregation
|
17
|
+
#
|
18
|
+
# Before using it, ask yourself:
|
19
|
+
# - Do we need to know about this (ie. internal error or client error)?
|
20
|
+
# - How severe/critical is this error? (ie. error, warning, fatal)
|
21
|
+
# - What information needed to make it actionable?
|
9
22
|
#
|
10
|
-
# Reporting internal error so that we can fix them.
|
11
|
-
# IMPORTANT: Make sure to not log any sensitive information.
|
12
23
|
module Logging
|
13
|
-
|
24
|
+
# Extract datadog stack trace from the exception
|
25
|
+
module DatadogStackTrace
|
26
|
+
GEM_ROOT = Pathname.new("#{__dir__}/../../../..").cleanpath.to_s
|
27
|
+
|
28
|
+
def self.from(exception)
|
29
|
+
backtrace = exception.backtrace
|
30
|
+
|
31
|
+
return unless backtrace
|
32
|
+
return if backtrace.empty?
|
33
|
+
|
34
|
+
# vendored deps
|
35
|
+
vendored_deps = Gem.path.any? { |p| p.start_with?(GEM_ROOT) }
|
14
36
|
|
15
|
-
|
37
|
+
backtrace.map do |line|
|
38
|
+
if !vendored_deps && line.start_with?(GEM_ROOT) ||
|
39
|
+
vendored_deps && line.start_with?(GEM_ROOT) && Gem.path.none? { |p| line.start_with?(p) }
|
40
|
+
line[GEM_ROOT.length..-1] || ''
|
41
|
+
else
|
42
|
+
'REDACTED'
|
43
|
+
end
|
44
|
+
end.join(',')
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def report(exception, level: :error, description: nil)
|
16
49
|
# Annoymous exceptions to be logged as <Class:0x00007f8b1c0b3b40>
|
17
|
-
message =
|
50
|
+
message = +''
|
51
|
+
message << (exception.class.name || exception.class.inspect)
|
52
|
+
message << ':' << description if description
|
18
53
|
|
19
54
|
event = Event::Log.new(
|
20
55
|
message: message,
|
21
|
-
level: level
|
56
|
+
level: level,
|
57
|
+
stack_trace: DatadogStackTrace.from(exception)
|
22
58
|
)
|
23
59
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
60
|
+
log!(event)
|
61
|
+
end
|
62
|
+
|
63
|
+
def error(description)
|
64
|
+
event = Event::Log.new(message: description, level: :error)
|
65
|
+
|
66
|
+
log!(event)
|
31
67
|
end
|
32
68
|
end
|
33
69
|
end
|
@@ -31,6 +31,18 @@ module Datadog
|
|
31
31
|
|
32
32
|
def application
|
33
33
|
config = Datadog.configuration
|
34
|
+
|
35
|
+
tracer_version = Core::Environment::Identity.gem_datadog_version_semver2
|
36
|
+
|
37
|
+
# We need some to distinguish datadog-ci gem versions
|
38
|
+
# when examining telemetry metrics emitted from the datadog-ci gem.
|
39
|
+
#
|
40
|
+
# This code checks that Datadog::CI is loaded and ci mode is enabled and adds
|
41
|
+
# "-ci-X.Y.Z" suffix to the tracer version.
|
42
|
+
if defined?(::Datadog::CI::VERSION) && config.respond_to?(:ci) && config.ci.enabled
|
43
|
+
tracer_version = "#{tracer_version}-ci-#{::Datadog::CI::VERSION::STRING}"
|
44
|
+
end
|
45
|
+
|
34
46
|
{
|
35
47
|
env: config.env,
|
36
48
|
language_name: Core::Environment::Ext::LANG,
|
@@ -39,7 +51,7 @@ module Datadog
|
|
39
51
|
runtime_version: Core::Environment::Ext::ENGINE_VERSION,
|
40
52
|
service_name: config.service,
|
41
53
|
service_version: config.version,
|
42
|
-
tracer_version:
|
54
|
+
tracer_version: tracer_version
|
43
55
|
}
|
44
56
|
end
|
45
57
|
|
@@ -16,6 +16,7 @@ module Datadog
|
|
16
16
|
#
|
17
17
|
# Setting this header to any non-empty value enables this feature.
|
18
18
|
HEADER_CLIENT_COMPUTED_TOP_LEVEL = 'Datadog-Client-Computed-Top-Level'
|
19
|
+
HEADER_CLIENT_COMPUTED_STATS = 'Datadog-Client-Computed-Stats'
|
19
20
|
HEADER_META_LANG = 'Datadog-Meta-Lang'
|
20
21
|
HEADER_META_LANG_VERSION = 'Datadog-Meta-Lang-Version'
|
21
22
|
HEADER_META_LANG_INTERPRETER = 'Datadog-Meta-Lang-Interpreter'
|
@@ -34,6 +34,18 @@ module Datadog
|
|
34
34
|
define_singleton_method(:now, &block)
|
35
35
|
end
|
36
36
|
|
37
|
+
# Overrides the implementation of `#get_time
|
38
|
+
# with the provided callable.
|
39
|
+
#
|
40
|
+
# Overriding the method `#get_time` instead of
|
41
|
+
# indirectly calling `block` removes
|
42
|
+
# one level of method call overhead.
|
43
|
+
#
|
44
|
+
# @param block [Proc] block that accepts unit and returns timestamp in the requested unit
|
45
|
+
def get_time_provider=(block)
|
46
|
+
define_singleton_method(:get_time, &block)
|
47
|
+
end
|
48
|
+
|
37
49
|
def measure(unit = :float_second)
|
38
50
|
before = get_time(unit)
|
39
51
|
yield
|
@@ -148,7 +148,7 @@ module Datadog
|
|
148
148
|
end
|
149
149
|
# rubocop:enable Lint/RescueException
|
150
150
|
end
|
151
|
-
@worker.name = self.class.name
|
151
|
+
@worker.name = self.class.name
|
152
152
|
@worker.thread_variable_set(:fork_safe, true)
|
153
153
|
|
154
154
|
nil
|