datadog 2.2.0 → 2.4.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 +87 -2
- data/ext/datadog_profiling_loader/datadog_profiling_loader.c +9 -1
- data/ext/datadog_profiling_loader/extconf.rb +14 -26
- data/ext/datadog_profiling_native_extension/clock_id.h +1 -0
- data/ext/datadog_profiling_native_extension/clock_id_from_pthread.c +1 -2
- data/ext/datadog_profiling_native_extension/clock_id_noop.c +1 -2
- data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +257 -69
- data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.c +53 -28
- data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.h +34 -4
- data/ext/datadog_profiling_native_extension/collectors_idle_sampling_helper.c +4 -0
- data/ext/datadog_profiling_native_extension/collectors_stack.c +136 -81
- data/ext/datadog_profiling_native_extension/collectors_stack.h +2 -2
- data/ext/datadog_profiling_native_extension/collectors_thread_context.c +661 -48
- data/ext/datadog_profiling_native_extension/collectors_thread_context.h +10 -1
- data/ext/datadog_profiling_native_extension/datadog_ruby_common.c +83 -0
- data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +53 -0
- data/ext/datadog_profiling_native_extension/extconf.rb +91 -69
- 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 +54 -12
- data/ext/datadog_profiling_native_extension/heap_recorder.h +3 -1
- data/ext/datadog_profiling_native_extension/helpers.h +6 -17
- data/ext/datadog_profiling_native_extension/http_transport.c +41 -9
- data/ext/datadog_profiling_native_extension/libdatadog_helpers.c +0 -86
- data/ext/datadog_profiling_native_extension/libdatadog_helpers.h +2 -23
- data/ext/datadog_profiling_native_extension/native_extension_helpers.rb +61 -172
- data/ext/datadog_profiling_native_extension/private_vm_api_access.c +116 -139
- data/ext/datadog_profiling_native_extension/private_vm_api_access.h +20 -11
- data/ext/datadog_profiling_native_extension/profiling.c +1 -3
- data/ext/datadog_profiling_native_extension/ruby_helpers.c +0 -33
- data/ext/datadog_profiling_native_extension/ruby_helpers.h +1 -26
- data/ext/datadog_profiling_native_extension/setup_signal_handler.h +1 -0
- data/ext/datadog_profiling_native_extension/stack_recorder.c +14 -2
- data/ext/datadog_profiling_native_extension/stack_recorder.h +2 -0
- data/ext/datadog_profiling_native_extension/time_helpers.c +0 -15
- data/ext/datadog_profiling_native_extension/time_helpers.h +36 -6
- data/ext/{datadog_profiling_native_extension → libdatadog_api}/crashtracker.c +37 -22
- data/ext/libdatadog_api/datadog_ruby_common.c +83 -0
- data/ext/libdatadog_api/datadog_ruby_common.h +53 -0
- data/ext/libdatadog_api/extconf.rb +108 -0
- data/ext/libdatadog_api/macos_development.md +26 -0
- data/ext/libdatadog_extconf_helpers.rb +130 -0
- 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 +2 -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 +35 -0
- data/lib/datadog/appsec/contrib/graphql/gateway/multiplex.rb +109 -0
- data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +71 -0
- data/lib/datadog/appsec/contrib/graphql/integration.rb +54 -0
- data/lib/datadog/appsec/contrib/graphql/patcher.rb +37 -0
- data/lib/datadog/appsec/contrib/graphql/reactive/multiplex.rb +59 -0
- data/lib/datadog/appsec/contrib/rack/gateway/request.rb +3 -6
- data/lib/datadog/appsec/event.rb +1 -1
- data/lib/datadog/appsec/processor/actions.rb +1 -1
- 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 +36 -37
- data/lib/datadog/appsec/rate_limiter.rb +25 -40
- data/lib/datadog/appsec/remote.rb +7 -3
- data/lib/datadog/appsec/response.rb +15 -1
- data/lib/datadog/appsec.rb +3 -2
- data/lib/datadog/core/configuration/components.rb +18 -15
- data/lib/datadog/core/configuration/settings.rb +135 -9
- data/lib/datadog/core/crashtracking/agent_base_url.rb +21 -0
- data/lib/datadog/core/crashtracking/component.rb +111 -0
- data/lib/datadog/core/crashtracking/tag_builder.rb +39 -0
- data/lib/datadog/core/diagnostics/environment_logger.rb +8 -11
- data/lib/datadog/core/environment/execution.rb +5 -5
- 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/runtime/metrics.rb +1 -1
- data/lib/datadog/core/telemetry/component.rb +51 -2
- data/lib/datadog/core/telemetry/emitter.rb +9 -11
- data/lib/datadog/core/telemetry/event.rb +37 -1
- data/lib/datadog/core/telemetry/ext.rb +1 -0
- data/lib/datadog/core/telemetry/http/adapters/net.rb +10 -12
- data/lib/datadog/core/telemetry/http/ext.rb +3 -0
- data/lib/datadog/core/telemetry/http/transport.rb +38 -9
- data/lib/datadog/core/telemetry/logger.rb +51 -0
- data/lib/datadog/core/telemetry/logging.rb +71 -0
- data/lib/datadog/core/telemetry/request.rb +13 -1
- data/lib/datadog/core/utils/at_fork_monkey_patch.rb +102 -0
- data/lib/datadog/core/utils/time.rb +12 -0
- data/lib/datadog/di/code_tracker.rb +168 -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/probe.rb +133 -0
- data/lib/datadog/di/probe_builder.rb +41 -0
- data/lib/datadog/di/redactor.rb +188 -0
- data/lib/datadog/di/serializer.rb +193 -0
- data/lib/datadog/di.rb +14 -0
- data/lib/datadog/kit/appsec/events.rb +2 -4
- data/lib/datadog/opentelemetry/sdk/propagator.rb +2 -0
- data/lib/datadog/opentelemetry/sdk/span_processor.rb +10 -0
- data/lib/datadog/opentelemetry/sdk/trace/span.rb +23 -0
- data/lib/datadog/profiling/collectors/code_provenance.rb +7 -7
- data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +28 -26
- data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +11 -13
- data/lib/datadog/profiling/collectors/info.rb +15 -6
- data/lib/datadog/profiling/collectors/thread_context.rb +30 -2
- data/lib/datadog/profiling/component.rb +89 -95
- data/lib/datadog/profiling/exporter.rb +3 -3
- data/lib/datadog/profiling/ext/dir_monkey_patches.rb +3 -3
- data/lib/datadog/profiling/ext.rb +21 -21
- data/lib/datadog/profiling/flush.rb +1 -1
- data/lib/datadog/profiling/http_transport.rb +14 -7
- data/lib/datadog/profiling/load_native_extension.rb +5 -5
- data/lib/datadog/profiling/preload.rb +1 -1
- data/lib/datadog/profiling/profiler.rb +5 -8
- data/lib/datadog/profiling/scheduler.rb +33 -25
- data/lib/datadog/profiling/stack_recorder.rb +3 -0
- data/lib/datadog/profiling/tag_builder.rb +2 -2
- data/lib/datadog/profiling/tasks/exec.rb +5 -5
- data/lib/datadog/profiling/tasks/setup.rb +16 -35
- data/lib/datadog/profiling.rb +4 -5
- data/lib/datadog/single_step_instrument.rb +12 -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 +4 -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/ext.rb +14 -0
- data/lib/datadog/tracing/contrib/faraday/middleware.rb +9 -0
- data/lib/datadog/tracing/contrib/grape/endpoint.rb +19 -0
- 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 +14 -10
- data/lib/datadog/tracing/contrib/graphql/unified_trace_patcher.rb +10 -4
- data/lib/datadog/tracing/contrib/http/instrumentation.rb +18 -15
- data/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +6 -5
- data/lib/datadog/tracing/contrib/httpclient/patcher.rb +1 -14
- data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +5 -0
- data/lib/datadog/tracing/contrib/httprb/patcher.rb +1 -14
- data/lib/datadog/tracing/contrib/lograge/patcher.rb +15 -0
- data/lib/datadog/tracing/contrib/mongodb/subscribers.rb +2 -0
- data/lib/datadog/tracing/contrib/mysql2/configuration/settings.rb +5 -0
- data/lib/datadog/tracing/contrib/mysql2/instrumentation.rb +17 -13
- data/lib/datadog/tracing/contrib/opensearch/patcher.rb +13 -6
- data/lib/datadog/tracing/contrib/patcher.rb +2 -1
- data/lib/datadog/tracing/contrib/pg/configuration/settings.rb +5 -0
- data/lib/datadog/tracing/contrib/pg/instrumentation.rb +4 -1
- data/lib/datadog/tracing/contrib/presto/patcher.rb +1 -13
- data/lib/datadog/tracing/contrib/propagation/sql_comment/ext.rb +28 -0
- data/lib/datadog/tracing/contrib/propagation/sql_comment/mode.rb +5 -1
- data/lib/datadog/tracing/contrib/propagation/sql_comment.rb +22 -10
- data/lib/datadog/tracing/contrib/rack/middlewares.rb +27 -0
- data/lib/datadog/tracing/contrib/redis/tags.rb +4 -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/contrib/trilogy/configuration/settings.rb +5 -0
- data/lib/datadog/tracing/contrib/trilogy/instrumentation.rb +4 -1
- data/lib/datadog/tracing/diagnostics/environment_logger.rb +14 -16
- data/lib/datadog/tracing/distributed/propagation.rb +7 -0
- data/lib/datadog/tracing/metadata/errors.rb +9 -1
- data/lib/datadog/tracing/metadata/ext.rb +6 -0
- data/lib/datadog/tracing/pipeline/span_filter.rb +2 -2
- 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 +9 -5
- data/lib/datadog/tracing/sampling/span/ext.rb +1 -1
- data/lib/datadog/tracing/sampling/span/rule.rb +2 -2
- data/lib/datadog/tracing/span.rb +9 -2
- data/lib/datadog/tracing/span_event.rb +41 -0
- data/lib/datadog/tracing/span_operation.rb +6 -2
- data/lib/datadog/tracing/trace_operation.rb +26 -2
- data/lib/datadog/tracing/tracer.rb +14 -12
- data/lib/datadog/tracing/transport/http/client.rb +1 -0
- data/lib/datadog/tracing/transport/io/client.rb +1 -0
- data/lib/datadog/tracing/transport/serializable_trace.rb +3 -0
- data/lib/datadog/tracing/workers/trace_writer.rb +1 -1
- data/lib/datadog/tracing/workers.rb +1 -1
- data/lib/datadog/version.rb +1 -1
- metadata +46 -11
- data/lib/datadog/profiling/crashtracker.rb +0 -91
- data/lib/datadog/profiling/ext/forking.rb +0 -98
- data/lib/datadog/tracing/sampling/rate_limiter.rb +0 -185
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../utils'
|
4
|
+
require_relative '../environment/socket'
|
5
|
+
require_relative '../environment/identity'
|
6
|
+
require_relative '../environment/git'
|
7
|
+
|
8
|
+
module Datadog
|
9
|
+
module Core
|
10
|
+
module Crashtracking
|
11
|
+
# This module builds a hash of tags
|
12
|
+
module TagBuilder
|
13
|
+
def self.call(settings)
|
14
|
+
hash = {
|
15
|
+
'host' => Environment::Socket.hostname,
|
16
|
+
'process_id' => Process.pid.to_s,
|
17
|
+
'runtime_engine' => Environment::Identity.lang_engine,
|
18
|
+
'runtime-id' => Environment::Identity.id,
|
19
|
+
'runtime_platform' => Environment::Identity.lang_platform,
|
20
|
+
'runtime_version' => Environment::Identity.lang_version,
|
21
|
+
'env' => settings.env,
|
22
|
+
'service' => settings.service,
|
23
|
+
'version' => settings.version,
|
24
|
+
'git.repository_url' => Environment::Git.git_repository_url,
|
25
|
+
'git.commit.sha' => Environment::Git.git_commit_sha,
|
26
|
+
'is_crash' => 'true',
|
27
|
+
'language' => 'ruby',
|
28
|
+
'library_version' => Core::Environment::Identity.gem_datadog_version,
|
29
|
+
}.compact
|
30
|
+
|
31
|
+
# Make sure everything is an utf-8 string, to avoid encoding issues in downstream
|
32
|
+
settings.tags.merge(hash).each_with_object({}) do |(key, value), h|
|
33
|
+
h[Utils.utf8_encode(key)] = Utils.utf8_encode(value)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -8,11 +8,17 @@ module Datadog
|
|
8
8
|
module Core
|
9
9
|
module Diagnostics
|
10
10
|
# Base class for EnvironmentLoggers - should allow for easy reporting by users to Datadog support.
|
11
|
+
#
|
12
|
+
# The EnvironmentLogger should not pollute the logs in a development environment.
|
11
13
|
module EnvironmentLogging
|
12
14
|
def log_configuration!(prefix, data)
|
13
15
|
logger.info("DATADOG CONFIGURATION - #{prefix} - #{data}")
|
14
16
|
end
|
15
17
|
|
18
|
+
def log_debug!(prefix, data)
|
19
|
+
logger.debug("DATADOG CONFIGURATION - #{prefix} - #{data}")
|
20
|
+
end
|
21
|
+
|
16
22
|
def log_error!(prefix, type, error)
|
17
23
|
logger.warn("DATADOG ERROR - #{prefix} - #{type}: #{error}")
|
18
24
|
end
|
@@ -27,21 +33,12 @@ module Datadog
|
|
27
33
|
def log?
|
28
34
|
startup_logs_enabled = Datadog.configuration.diagnostics.startup_logs.enabled
|
29
35
|
if startup_logs_enabled.nil?
|
30
|
-
|
36
|
+
# Do not pollute the logs in a development environment.
|
37
|
+
!Datadog::Core::Environment::Execution.development?
|
31
38
|
else
|
32
39
|
startup_logs_enabled
|
33
40
|
end
|
34
41
|
end
|
35
|
-
|
36
|
-
REPL_PROGRAM_NAMES = %w[irb pry].freeze
|
37
|
-
|
38
|
-
def repl?
|
39
|
-
REPL_PROGRAM_NAMES.include?($PROGRAM_NAME)
|
40
|
-
end
|
41
|
-
|
42
|
-
def rspec?
|
43
|
-
$PROGRAM_NAME.end_with?('rspec')
|
44
|
-
end
|
45
42
|
end
|
46
43
|
|
47
44
|
# Collects and logs Core diagnostic information
|
@@ -25,9 +25,9 @@ module Datadog
|
|
25
25
|
# 2. Checking if `Net::HTTP` is referring to the original one
|
26
26
|
# => ::Net::HTTP.equal?(::WebMock::HttpLibAdapters::NetHttpAdapter::OriginalNetHTTP)
|
27
27
|
def webmock_enabled?
|
28
|
-
defined?(::WebMock::HttpLibAdapters::NetHttpAdapter) &&
|
28
|
+
!!(defined?(::WebMock::HttpLibAdapters::NetHttpAdapter) &&
|
29
29
|
defined?(::Net::HTTP) &&
|
30
|
-
::Net::HTTP.equal?(::WebMock::HttpLibAdapters::NetHttpAdapter.instance_variable_get(:@webMockNetHTTP))
|
30
|
+
::Net::HTTP.equal?(::WebMock::HttpLibAdapters::NetHttpAdapter.instance_variable_get(:@webMockNetHTTP)))
|
31
31
|
end
|
32
32
|
|
33
33
|
private
|
@@ -68,7 +68,7 @@ module Datadog
|
|
68
68
|
|
69
69
|
# Check if we are running from `bin/cucumber` or `cucumber/rake/task`.
|
70
70
|
def cucumber?
|
71
|
-
defined?(::Cucumber::Cli)
|
71
|
+
!!defined?(::Cucumber::Cli)
|
72
72
|
end
|
73
73
|
|
74
74
|
# If this is a Rails application, use different heuristics to detect
|
@@ -80,7 +80,7 @@ module Datadog
|
|
80
80
|
# detecting its presence is enough to deduct if this is a development environment.
|
81
81
|
#
|
82
82
|
# @see https://github.com/rails/spring/blob/48b299348ace2188444489a0c216a6f3e9687281/README.md?plain=1#L204-L207
|
83
|
-
defined?(::Spring) || rails_env_development?
|
83
|
+
!!defined?(::Spring) || rails_env_development?
|
84
84
|
end
|
85
85
|
|
86
86
|
RAILS_ENV_DEVELOPMENT = Set['development', 'test'].freeze
|
@@ -94,7 +94,7 @@ module Datadog
|
|
94
94
|
# it's common to have a custom "staging" environment, and such environment normally want to run as close
|
95
95
|
# to production as possible.
|
96
96
|
def rails_env_development?
|
97
|
-
defined?(::Rails.env) && RAILS_ENV_DEVELOPMENT.include?(::Rails.env)
|
97
|
+
!!defined?(::Rails.env) && RAILS_ENV_DEVELOPMENT.include?(::Rails.env)
|
98
98
|
end
|
99
99
|
end
|
100
100
|
end
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require_relative '../utils/time'
|
4
4
|
require_relative '../utils/only_once'
|
5
|
+
require_relative '../telemetry/logger'
|
5
6
|
require_relative '../configuration/ext'
|
6
7
|
|
7
8
|
require_relative 'ext'
|
@@ -100,6 +101,7 @@ module Datadog
|
|
100
101
|
Datadog.logger.error(
|
101
102
|
"Failed to send count stat. Cause: #{e.class.name} #{e.message} Source: #{Array(e.backtrace).first}"
|
102
103
|
)
|
104
|
+
Telemetry::Logger.report(e, description: 'Failed to send count stat')
|
103
105
|
end
|
104
106
|
|
105
107
|
def distribution(stat, value = nil, options = nil, &block)
|
@@ -113,6 +115,7 @@ module Datadog
|
|
113
115
|
Datadog.logger.error(
|
114
116
|
"Failed to send distribution stat. Cause: #{e.class.name} #{e.message} Source: #{Array(e.backtrace).first}"
|
115
117
|
)
|
118
|
+
Telemetry::Logger.report(e, description: 'Failed to send distribution stat')
|
116
119
|
end
|
117
120
|
|
118
121
|
def increment(stat, options = nil)
|
@@ -125,6 +128,7 @@ module Datadog
|
|
125
128
|
Datadog.logger.error(
|
126
129
|
"Failed to send increment stat. Cause: #{e.class.name} #{e.message} Source: #{Array(e.backtrace).first}"
|
127
130
|
)
|
131
|
+
Telemetry::Logger.report(e, description: 'Failed to send increment stat')
|
128
132
|
end
|
129
133
|
|
130
134
|
def gauge(stat, value = nil, options = nil, &block)
|
@@ -138,6 +142,7 @@ module Datadog
|
|
138
142
|
Datadog.logger.error(
|
139
143
|
"Failed to send gauge stat. Cause: #{e.class.name} #{e.message} Source: #{Array(e.backtrace).first}"
|
140
144
|
)
|
145
|
+
Telemetry::Logger.report(e, description: 'Failed to send gauge stat')
|
141
146
|
end
|
142
147
|
|
143
148
|
def time(stat, options = nil)
|
@@ -153,9 +158,11 @@ module Datadog
|
|
153
158
|
distribution(stat, ((finished - start) * 1000), options)
|
154
159
|
end
|
155
160
|
rescue StandardError => e
|
161
|
+
# TODO: Likely to be redundant, since `distribution` handles its own errors.
|
156
162
|
Datadog.logger.error(
|
157
163
|
"Failed to send time stat. Cause: #{e.class.name} #{e.message} Source: #{Array(e.backtrace).first}"
|
158
164
|
)
|
165
|
+
Telemetry::Logger.report(e, description: 'Failed to send time stat')
|
159
166
|
end
|
160
167
|
end
|
161
168
|
|
@@ -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
|
|
@@ -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
|
@@ -2,8 +2,12 @@
|
|
2
2
|
|
3
3
|
require_relative 'emitter'
|
4
4
|
require_relative 'event'
|
5
|
+
require_relative 'http/transport'
|
5
6
|
require_relative 'metrics_manager'
|
6
7
|
require_relative 'worker'
|
8
|
+
require_relative 'logging'
|
9
|
+
|
10
|
+
require_relative '../configuration/ext'
|
7
11
|
require_relative '../utils/forking'
|
8
12
|
|
9
13
|
module Datadog
|
@@ -14,6 +18,42 @@ module Datadog
|
|
14
18
|
attr_reader :enabled
|
15
19
|
|
16
20
|
include Core::Utils::Forking
|
21
|
+
include Telemetry::Logging
|
22
|
+
|
23
|
+
def self.build(settings, agent_settings, logger)
|
24
|
+
enabled = settings.telemetry.enabled
|
25
|
+
agentless_enabled = settings.telemetry.agentless_enabled
|
26
|
+
|
27
|
+
if !agentless_enabled && agent_settings.adapter != Datadog::Core::Configuration::Ext::Agent::HTTP::ADAPTER
|
28
|
+
enabled = false
|
29
|
+
logger.debug { "Telemetry disabled. Agent network adapter not supported: #{agent_settings.adapter}" }
|
30
|
+
end
|
31
|
+
|
32
|
+
if agentless_enabled && settings.api_key.nil?
|
33
|
+
enabled = false
|
34
|
+
logger.debug { 'Telemetry disabled. Agentless telemetry requires an DD_API_KEY variable to be set.' }
|
35
|
+
end
|
36
|
+
|
37
|
+
transport = if agentless_enabled
|
38
|
+
Datadog::Core::Telemetry::Http::Transport.build_agentless_transport(
|
39
|
+
api_key: settings.api_key,
|
40
|
+
dd_site: settings.site,
|
41
|
+
url_override: settings.telemetry.agentless_url_override
|
42
|
+
)
|
43
|
+
else
|
44
|
+
Datadog::Core::Telemetry::Http::Transport.build_agent_transport(agent_settings)
|
45
|
+
end
|
46
|
+
|
47
|
+
Telemetry::Component.new(
|
48
|
+
http_transport: transport,
|
49
|
+
enabled: enabled,
|
50
|
+
metrics_enabled: enabled && settings.telemetry.metrics_enabled,
|
51
|
+
heartbeat_interval_seconds: settings.telemetry.heartbeat_interval_seconds,
|
52
|
+
metrics_aggregation_interval_seconds: settings.telemetry.metrics_aggregation_interval_seconds,
|
53
|
+
dependency_collection: settings.telemetry.dependency_collection,
|
54
|
+
shutdown_timeout_seconds: settings.telemetry.shutdown_timeout_seconds,
|
55
|
+
)
|
56
|
+
end
|
17
57
|
|
18
58
|
# @param enabled [Boolean] Determines whether telemetry events should be sent to the API
|
19
59
|
# @param metrics_enabled [Boolean] Determines whether telemetry metrics should be sent to the API
|
@@ -24,6 +64,8 @@ module Datadog
|
|
24
64
|
heartbeat_interval_seconds:,
|
25
65
|
metrics_aggregation_interval_seconds:,
|
26
66
|
dependency_collection:,
|
67
|
+
http_transport:,
|
68
|
+
shutdown_timeout_seconds:,
|
27
69
|
enabled: true,
|
28
70
|
metrics_enabled: true
|
29
71
|
)
|
@@ -39,9 +81,10 @@ module Datadog
|
|
39
81
|
enabled: @enabled,
|
40
82
|
heartbeat_interval_seconds: heartbeat_interval_seconds,
|
41
83
|
metrics_aggregation_interval_seconds: metrics_aggregation_interval_seconds,
|
42
|
-
emitter: Emitter.new,
|
84
|
+
emitter: Emitter.new(http_transport: http_transport),
|
43
85
|
metrics_manager: @metrics_manager,
|
44
|
-
dependency_collection: dependency_collection
|
86
|
+
dependency_collection: dependency_collection,
|
87
|
+
shutdown_timeout: shutdown_timeout_seconds
|
45
88
|
)
|
46
89
|
@worker.start
|
47
90
|
end
|
@@ -70,6 +113,12 @@ module Datadog
|
|
70
113
|
@worker.enqueue(Event::AppIntegrationsChange.new)
|
71
114
|
end
|
72
115
|
|
116
|
+
def log!(event)
|
117
|
+
return unless @enabled || forked?
|
118
|
+
|
119
|
+
@worker.enqueue(event)
|
120
|
+
end
|
121
|
+
|
73
122
|
# Report configuration changes caused by Remote Configuration.
|
74
123
|
def client_configuration_change!(changes)
|
75
124
|
return if !@enabled || forked?
|
@@ -16,22 +16,20 @@ module Datadog
|
|
16
16
|
|
17
17
|
# @param http_transport [Datadog::Core::Telemetry::Http::Transport] Transport object that can be used to send
|
18
18
|
# telemetry requests via the agent
|
19
|
-
def initialize(http_transport:
|
19
|
+
def initialize(http_transport:)
|
20
20
|
@http_transport = http_transport
|
21
21
|
end
|
22
22
|
|
23
23
|
# Retrieves and emits a TelemetryRequest object based on the request type specified
|
24
24
|
def request(event)
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
rescue
|
32
|
-
|
33
|
-
Telemetry::Http::InternalErrorResponse.new(e)
|
34
|
-
end
|
25
|
+
seq_id = self.class.sequence.next
|
26
|
+
payload = Request.build_payload(event, seq_id)
|
27
|
+
res = @http_transport.request(request_type: event.type, payload: payload.to_json)
|
28
|
+
Datadog.logger.debug { "Telemetry sent for event `#{event.type}` (code: #{res.code.inspect})" }
|
29
|
+
res
|
30
|
+
rescue => e
|
31
|
+
Datadog.logger.debug("Unable to send telemetry request for event `#{event.type rescue 'unknown'}`: #{e}")
|
32
|
+
Telemetry::Http::InternalErrorResponse.new(e)
|
35
33
|
end
|
36
34
|
|
37
35
|
# Initializes a Sequence object to track seq_id if not already initialized; else returns stored
|
@@ -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
|
@@ -18,7 +21,9 @@ module Datadog
|
|
18
21
|
# The type of the event.
|
19
22
|
# It must be one of the stings defined in the Telemetry V2
|
20
23
|
# specification for event names.
|
21
|
-
def type
|
24
|
+
def type
|
25
|
+
raise NotImplementedError, 'Must be implemented by subclass'
|
26
|
+
end
|
22
27
|
|
23
28
|
# The JSON payload for the event.
|
24
29
|
def payload
|
@@ -332,6 +337,37 @@ module Datadog
|
|
332
337
|
end
|
333
338
|
end
|
334
339
|
|
340
|
+
# Telemetry class for the 'logs' event
|
341
|
+
class Log < Base
|
342
|
+
LEVELS = {
|
343
|
+
error: 'ERROR',
|
344
|
+
warn: 'WARN',
|
345
|
+
}.freeze
|
346
|
+
|
347
|
+
def type
|
348
|
+
'logs'
|
349
|
+
end
|
350
|
+
|
351
|
+
def initialize(message:, level:, stack_trace: nil)
|
352
|
+
super()
|
353
|
+
@message = message
|
354
|
+
@stack_trace = stack_trace
|
355
|
+
@level = LEVELS.fetch(level) { |k| raise ArgumentError, "Invalid log level :#{k}" }
|
356
|
+
end
|
357
|
+
|
358
|
+
def payload
|
359
|
+
{
|
360
|
+
logs: [
|
361
|
+
{
|
362
|
+
message: @message,
|
363
|
+
level: @level,
|
364
|
+
stack_trace: @stack_trace,
|
365
|
+
}.compact
|
366
|
+
]
|
367
|
+
}
|
368
|
+
end
|
369
|
+
end
|
370
|
+
|
335
371
|
# Telemetry class for the 'distributions' event
|
336
372
|
class Distributions < GenerateMetrics
|
337
373
|
def type
|