datadog 2.22.0 → 2.23.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 +59 -2
- data/ext/LIBDATADOG_DEVELOPMENT.md +1 -58
- data/ext/datadog_profiling_native_extension/collectors_stack.c +4 -0
- data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +1 -1
- data/ext/datadog_profiling_native_extension/extconf.rb +6 -4
- data/ext/datadog_profiling_native_extension/heap_recorder.c +1 -1
- data/ext/libdatadog_api/datadog_ruby_common.h +1 -1
- data/ext/libdatadog_api/feature_flags.c +554 -0
- data/ext/libdatadog_api/feature_flags.h +5 -0
- data/ext/libdatadog_api/init.c +2 -0
- data/ext/libdatadog_api/library_config.c +12 -11
- data/ext/libdatadog_extconf_helpers.rb +1 -1
- data/lib/datadog/appsec/api_security/route_extractor.rb +23 -6
- data/lib/datadog/appsec/api_security/sampler.rb +7 -4
- data/lib/datadog/appsec/assets/blocked.html +8 -0
- data/lib/datadog/appsec/assets/blocked.json +1 -1
- data/lib/datadog/appsec/assets/blocked.text +3 -1
- data/lib/datadog/appsec/assets.rb +1 -1
- data/lib/datadog/appsec/remote.rb +4 -0
- data/lib/datadog/appsec/response.rb +18 -4
- data/lib/datadog/core/configuration/components.rb +30 -3
- data/lib/datadog/core/configuration/config_helper.rb +1 -1
- data/lib/datadog/core/configuration/settings.rb +14 -0
- data/lib/datadog/core/configuration/supported_configurations.rb +330 -301
- data/lib/datadog/core/ddsketch.rb +0 -2
- data/lib/datadog/core/environment/ext.rb +6 -0
- data/lib/datadog/core/environment/process.rb +79 -0
- data/lib/datadog/core/feature_flags.rb +61 -0
- data/lib/datadog/core/remote/client/capabilities.rb +7 -0
- data/lib/datadog/core/remote/transport/config.rb +2 -10
- data/lib/datadog/core/remote/transport/http/config.rb +9 -9
- data/lib/datadog/core/remote/transport/http/negotiation.rb +17 -8
- data/lib/datadog/core/remote/transport/http.rb +2 -0
- data/lib/datadog/core/remote/transport/negotiation.rb +2 -18
- data/lib/datadog/core/remote/worker.rb +25 -37
- data/lib/datadog/core/tag_builder.rb +0 -4
- data/lib/datadog/core/tag_normalizer.rb +84 -0
- data/lib/datadog/core/telemetry/component.rb +7 -3
- data/lib/datadog/core/telemetry/event/app_started.rb +52 -49
- data/lib/datadog/core/telemetry/event/synth_app_client_configuration_change.rb +1 -1
- data/lib/datadog/core/telemetry/logger.rb +2 -2
- data/lib/datadog/core/telemetry/logging.rb +2 -8
- data/lib/datadog/core/telemetry/transport/http/telemetry.rb +5 -6
- data/lib/datadog/core/telemetry/transport/telemetry.rb +1 -2
- data/lib/datadog/core/transport/http/client.rb +69 -0
- data/lib/datadog/core/utils/array.rb +29 -0
- data/lib/datadog/{appsec/api_security → core/utils}/lru_cache.rb +10 -21
- data/lib/datadog/core/utils/network.rb +3 -1
- data/lib/datadog/core/utils/only_once_successful.rb +6 -2
- data/lib/datadog/core/utils.rb +2 -0
- data/lib/datadog/data_streams/configuration/settings.rb +49 -0
- data/lib/datadog/data_streams/configuration.rb +11 -0
- data/lib/datadog/data_streams/ext.rb +11 -0
- data/lib/datadog/data_streams/extensions.rb +16 -0
- data/lib/datadog/data_streams/pathway_context.rb +169 -0
- data/lib/datadog/data_streams/processor.rb +509 -0
- data/lib/datadog/data_streams/transport/http/api.rb +33 -0
- data/lib/datadog/data_streams/transport/http/client.rb +21 -0
- data/lib/datadog/data_streams/transport/http/stats.rb +87 -0
- data/lib/datadog/data_streams/transport/http.rb +41 -0
- data/lib/datadog/data_streams/transport/stats.rb +60 -0
- data/lib/datadog/data_streams.rb +100 -0
- data/lib/datadog/di/component.rb +0 -16
- data/lib/datadog/di/el/evaluator.rb +1 -1
- data/lib/datadog/di/error.rb +4 -0
- data/lib/datadog/di/instrumenter.rb +76 -30
- data/lib/datadog/di/probe.rb +20 -0
- data/lib/datadog/di/probe_manager.rb +10 -2
- data/lib/datadog/di/probe_notification_builder.rb +62 -23
- data/lib/datadog/di/proc_responder.rb +32 -0
- data/lib/datadog/di/transport/diagnostics.rb +2 -2
- data/lib/datadog/di/transport/http/diagnostics.rb +2 -4
- data/lib/datadog/di/transport/http/input.rb +2 -4
- data/lib/datadog/di/transport/http.rb +6 -2
- data/lib/datadog/di/transport/input.rb +64 -4
- data/lib/datadog/open_feature/component.rb +60 -0
- data/lib/datadog/open_feature/configuration.rb +27 -0
- data/lib/datadog/open_feature/evaluation_engine.rb +69 -0
- data/lib/datadog/open_feature/exposures/batch_builder.rb +32 -0
- data/lib/datadog/open_feature/exposures/buffer.rb +43 -0
- data/lib/datadog/open_feature/exposures/deduplicator.rb +30 -0
- data/lib/datadog/open_feature/exposures/event.rb +60 -0
- data/lib/datadog/open_feature/exposures/reporter.rb +40 -0
- data/lib/datadog/open_feature/exposures/worker.rb +116 -0
- data/lib/datadog/open_feature/ext.rb +14 -0
- data/lib/datadog/open_feature/native_evaluator.rb +38 -0
- data/lib/datadog/open_feature/noop_evaluator.rb +26 -0
- data/lib/datadog/open_feature/provider.rb +141 -0
- data/lib/datadog/open_feature/remote.rb +74 -0
- data/lib/datadog/open_feature/resolution_details.rb +35 -0
- data/lib/datadog/open_feature/transport.rb +72 -0
- data/lib/datadog/open_feature.rb +19 -0
- data/lib/datadog/opentelemetry/configuration/settings.rb +159 -0
- data/lib/datadog/opentelemetry/metrics.rb +110 -0
- data/lib/datadog/opentelemetry/sdk/configurator.rb +25 -1
- data/lib/datadog/opentelemetry/sdk/metrics_exporter.rb +38 -0
- data/lib/datadog/opentelemetry.rb +3 -0
- data/lib/datadog/profiling/collectors/code_provenance.rb +15 -6
- data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +1 -1
- data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +1 -1
- data/lib/datadog/profiling/profiler.rb +4 -0
- data/lib/datadog/profiling/tag_builder.rb +36 -3
- data/lib/datadog/profiling.rb +1 -2
- data/lib/datadog/single_step_instrument.rb +1 -1
- data/lib/datadog/tracing/configuration/ext.rb +9 -0
- data/lib/datadog/tracing/configuration/settings.rb +74 -0
- data/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb +4 -4
- data/lib/datadog/tracing/contrib/action_pack/utils.rb +1 -2
- data/lib/datadog/tracing/contrib/active_job/log_injection.rb +21 -7
- data/lib/datadog/tracing/contrib/active_job/patcher.rb +5 -1
- data/lib/datadog/tracing/contrib/aws/instrumentation.rb +4 -2
- data/lib/datadog/tracing/contrib/ethon/easy_patch.rb +4 -1
- data/lib/datadog/tracing/contrib/excon/configuration/settings.rb +11 -3
- data/lib/datadog/tracing/contrib/faraday/configuration/settings.rb +11 -7
- data/lib/datadog/tracing/contrib/grape/configuration/settings.rb +7 -3
- data/lib/datadog/tracing/contrib/graphql/unified_trace.rb +22 -17
- data/lib/datadog/tracing/contrib/http/configuration/settings.rb +11 -3
- data/lib/datadog/tracing/contrib/httpclient/configuration/settings.rb +11 -3
- data/lib/datadog/tracing/contrib/httprb/configuration/settings.rb +11 -3
- data/lib/datadog/tracing/contrib/kafka/instrumentation/consumer.rb +66 -0
- data/lib/datadog/tracing/contrib/kafka/instrumentation/producer.rb +66 -0
- data/lib/datadog/tracing/contrib/kafka/patcher.rb +14 -0
- data/lib/datadog/tracing/contrib/karafka/framework.rb +30 -0
- data/lib/datadog/tracing/contrib/karafka/monitor.rb +11 -0
- data/lib/datadog/tracing/contrib/karafka/patcher.rb +32 -0
- data/lib/datadog/tracing/contrib/rack/middlewares.rb +59 -27
- data/lib/datadog/tracing/contrib/rack/route_inference.rb +53 -0
- data/lib/datadog/tracing/contrib/rails/middlewares.rb +2 -2
- data/lib/datadog/tracing/contrib/rest_client/request_patch.rb +4 -1
- data/lib/datadog/tracing/contrib/roda/instrumentation.rb +3 -1
- data/lib/datadog/tracing/contrib/sinatra/tracer_middleware.rb +3 -1
- data/lib/datadog/tracing/contrib/status_range_matcher.rb +7 -0
- data/lib/datadog/tracing/contrib/waterdrop/configuration/settings.rb +27 -0
- data/lib/datadog/tracing/contrib/waterdrop/distributed/propagation.rb +48 -0
- data/lib/datadog/tracing/contrib/waterdrop/ext.rb +17 -0
- data/lib/datadog/tracing/contrib/waterdrop/integration.rb +43 -0
- data/lib/datadog/tracing/contrib/waterdrop/middleware.rb +46 -0
- data/lib/datadog/tracing/contrib/waterdrop/patcher.rb +46 -0
- data/lib/datadog/tracing/contrib/waterdrop/producer.rb +50 -0
- data/lib/datadog/tracing/contrib/waterdrop.rb +37 -0
- data/lib/datadog/tracing/contrib.rb +1 -0
- data/lib/datadog/tracing/metadata/ext.rb +1 -1
- data/lib/datadog/tracing/transport/http/client.rb +12 -26
- data/lib/datadog/tracing/transport/trace_formatter.rb +11 -0
- data/lib/datadog/tracing/transport/traces.rb +3 -5
- data/lib/datadog/version.rb +2 -2
- data/lib/datadog.rb +2 -0
- metadata +78 -15
- data/lib/datadog/core/remote/transport/http/client.rb +0 -49
- data/lib/datadog/core/telemetry/transport/http/client.rb +0 -49
- data/lib/datadog/di/transport/http/client.rb +0 -47
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../../../core/transport/http/client'
|
|
4
|
+
|
|
5
|
+
module Datadog
|
|
6
|
+
module DataStreams
|
|
7
|
+
module Transport
|
|
8
|
+
module HTTP
|
|
9
|
+
# HTTP client for Data Streams Monitoring
|
|
10
|
+
class Client < Core::Transport::HTTP::Client
|
|
11
|
+
def send_stats_payload(request)
|
|
12
|
+
send_request(request) do |api, env|
|
|
13
|
+
# TODO how to make api have the derived type for steep?
|
|
14
|
+
api.send_stats(env) # steep:ignore
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../stats'
|
|
4
|
+
require_relative 'client'
|
|
5
|
+
require_relative '../../../core/transport/http/response'
|
|
6
|
+
require_relative '../../../core/transport/http/api/endpoint'
|
|
7
|
+
require_relative '../../../core/transport/http/api/spec'
|
|
8
|
+
require_relative '../../../core/transport/http/api/instance'
|
|
9
|
+
|
|
10
|
+
module Datadog
|
|
11
|
+
module DataStreams
|
|
12
|
+
module Transport
|
|
13
|
+
module HTTP
|
|
14
|
+
# HTTP transport behavior for Data Streams stats
|
|
15
|
+
module Stats
|
|
16
|
+
# Response from HTTP transport for DSM stats
|
|
17
|
+
class Response
|
|
18
|
+
include Datadog::Core::Transport::HTTP::Response
|
|
19
|
+
|
|
20
|
+
def initialize(http_response)
|
|
21
|
+
super
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
module API
|
|
26
|
+
# HTTP API Spec for DSM
|
|
27
|
+
class Spec < Core::Transport::HTTP::API::Spec
|
|
28
|
+
attr_accessor :stats
|
|
29
|
+
|
|
30
|
+
def send_stats(env, &block)
|
|
31
|
+
raise Core::Transport::HTTP::API::Spec::EndpointNotDefinedError.new('stats', self) if stats.nil?
|
|
32
|
+
|
|
33
|
+
stats.call(env, &block)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def encoder
|
|
37
|
+
# DSM handles encoding in the transport layer (MessagePack + gzip)
|
|
38
|
+
# so we don't need an encoder at the API level
|
|
39
|
+
nil
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# HTTP API Instance for DSM
|
|
44
|
+
class Instance < Core::Transport::HTTP::API::Instance
|
|
45
|
+
def send_stats(env)
|
|
46
|
+
unless spec.is_a?(Stats::API::Spec)
|
|
47
|
+
raise Core::Transport::HTTP::API::Instance::EndpointNotSupportedError.new(
|
|
48
|
+
'stats', self
|
|
49
|
+
)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
spec.send_stats(env) do |request_env|
|
|
53
|
+
call(request_env)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Endpoint for submitting DSM stats data
|
|
59
|
+
class Endpoint < Core::Transport::HTTP::API::Endpoint
|
|
60
|
+
def initialize(path)
|
|
61
|
+
super(:post, path)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def call(env, &block)
|
|
65
|
+
# Build request
|
|
66
|
+
env.verb = verb
|
|
67
|
+
env.path = path
|
|
68
|
+
env.body = env.request.parcel.data
|
|
69
|
+
|
|
70
|
+
# Send request
|
|
71
|
+
http_response = yield(env)
|
|
72
|
+
|
|
73
|
+
# Build response
|
|
74
|
+
Response.new(http_response)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def encoder
|
|
78
|
+
# DSM handles encoding in the transport layer
|
|
79
|
+
nil
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../../core/transport/http'
|
|
4
|
+
require_relative 'http/api'
|
|
5
|
+
require_relative 'http/client'
|
|
6
|
+
require_relative 'http/stats'
|
|
7
|
+
require_relative 'stats'
|
|
8
|
+
|
|
9
|
+
module Datadog
|
|
10
|
+
module DataStreams
|
|
11
|
+
module Transport
|
|
12
|
+
# HTTP transport for Data Streams Monitoring
|
|
13
|
+
module HTTP
|
|
14
|
+
module_function
|
|
15
|
+
|
|
16
|
+
# Builds a new Transport::HTTP::Client with default settings
|
|
17
|
+
def default(
|
|
18
|
+
agent_settings:,
|
|
19
|
+
logger:
|
|
20
|
+
)
|
|
21
|
+
Core::Transport::HTTP.build(
|
|
22
|
+
api_instance_class: Stats::API::Instance,
|
|
23
|
+
agent_settings: agent_settings,
|
|
24
|
+
logger: logger,
|
|
25
|
+
headers: {
|
|
26
|
+
'Content-Type' => 'application/msgpack',
|
|
27
|
+
'Content-Encoding' => 'gzip'
|
|
28
|
+
}
|
|
29
|
+
) do |transport|
|
|
30
|
+
apis = API.defaults
|
|
31
|
+
|
|
32
|
+
transport.api API::V01, apis[API::V01], default: true
|
|
33
|
+
|
|
34
|
+
# Call block to apply any customization, if provided
|
|
35
|
+
yield(transport) if block_given?
|
|
36
|
+
end.to_transport(Transport::Stats::Transport)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'msgpack'
|
|
4
|
+
require 'zlib'
|
|
5
|
+
require_relative '../../core/transport/parcel'
|
|
6
|
+
require_relative '../../core/transport/request'
|
|
7
|
+
|
|
8
|
+
module Datadog
|
|
9
|
+
module DataStreams
|
|
10
|
+
module Transport
|
|
11
|
+
module Stats
|
|
12
|
+
# Parcel for encoded DSM stats payload
|
|
13
|
+
class EncodedParcel
|
|
14
|
+
include Datadog::Core::Transport::Parcel
|
|
15
|
+
|
|
16
|
+
def initialize(data)
|
|
17
|
+
@data = data
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
attr_reader :data
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Request for DSM stats
|
|
24
|
+
class Request < Datadog::Core::Transport::Request
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Transport for Data Streams Monitoring stats
|
|
28
|
+
class Transport
|
|
29
|
+
attr_reader :client, :apis, :current_api_id, :logger
|
|
30
|
+
|
|
31
|
+
def initialize(apis, default_api, logger:)
|
|
32
|
+
@apis = apis
|
|
33
|
+
@logger = logger
|
|
34
|
+
@default_api = default_api
|
|
35
|
+
@current_api_id = default_api
|
|
36
|
+
|
|
37
|
+
@client = DataStreams::Transport::HTTP::Client.new(current_api, logger: @logger)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def send_stats(payload)
|
|
41
|
+
# MessagePack encode and gzip compress the payload
|
|
42
|
+
msgpack_data = MessagePack.pack(payload)
|
|
43
|
+
compressed_data = Zlib.gzip(msgpack_data)
|
|
44
|
+
|
|
45
|
+
# Create parcel and request
|
|
46
|
+
parcel = EncodedParcel.new(compressed_data)
|
|
47
|
+
request = Request.new(parcel)
|
|
48
|
+
|
|
49
|
+
# Send to agent
|
|
50
|
+
client.send_stats_payload(request)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def current_api
|
|
54
|
+
apis[@current_api_id]
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'data_streams/processor'
|
|
4
|
+
require_relative 'data_streams/pathway_context'
|
|
5
|
+
require_relative 'data_streams/configuration/settings'
|
|
6
|
+
require_relative 'data_streams/extensions'
|
|
7
|
+
require_relative 'core/utils/time'
|
|
8
|
+
|
|
9
|
+
module Datadog
|
|
10
|
+
# Datadog Data Streams Monitoring public API.
|
|
11
|
+
#
|
|
12
|
+
# The Datadog team ensures that public methods in this module
|
|
13
|
+
# only receive backwards compatible changes, and breaking changes
|
|
14
|
+
# will only occur in new major versions releases.
|
|
15
|
+
# @public_api
|
|
16
|
+
module DataStreams
|
|
17
|
+
class << self
|
|
18
|
+
# Set a produce checkpoint for Data Streams Monitoring
|
|
19
|
+
#
|
|
20
|
+
# @param type [String] The type of the checkpoint (e.g., 'kafka', 'kinesis', 'sns')
|
|
21
|
+
# @param destination [String] The destination (e.g., topic, exchange, stream name)
|
|
22
|
+
# @param auto_instrumentation [Boolean] Whether this checkpoint was set by auto-instrumentation (default: false)
|
|
23
|
+
# @param tags [Hash] Additional tags to include
|
|
24
|
+
# @yield [key, value] Block to inject context into carrier
|
|
25
|
+
# @return [String, nil] Base64 encoded pathway context or nil if disabled
|
|
26
|
+
# @public_api
|
|
27
|
+
def set_produce_checkpoint(type:, destination:, auto_instrumentation: false, tags: {}, &block)
|
|
28
|
+
processor&.set_produce_checkpoint(
|
|
29
|
+
type: type,
|
|
30
|
+
destination: destination,
|
|
31
|
+
manual_checkpoint: !auto_instrumentation,
|
|
32
|
+
tags: tags,
|
|
33
|
+
&block
|
|
34
|
+
)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Set a consume checkpoint for Data Streams Monitoring
|
|
38
|
+
#
|
|
39
|
+
# @param type [String] The type of the checkpoint (e.g., 'kafka', 'kinesis', 'sns')
|
|
40
|
+
# @param source [String] The source (e.g., topic, exchange, stream name)
|
|
41
|
+
# @param auto_instrumentation [Boolean] Whether this checkpoint was set by auto-instrumentation (default: false)
|
|
42
|
+
# @param tags [Hash] Additional tags to include
|
|
43
|
+
# @yield [key] Block to extract context from carrier
|
|
44
|
+
# @return [String, nil] Base64 encoded pathway context or nil if disabled
|
|
45
|
+
# @public_api
|
|
46
|
+
def set_consume_checkpoint(type:, source:, auto_instrumentation: false, tags: {}, &block)
|
|
47
|
+
processor&.set_consume_checkpoint(
|
|
48
|
+
type: type,
|
|
49
|
+
source: source,
|
|
50
|
+
manual_checkpoint: !auto_instrumentation,
|
|
51
|
+
tags: tags,
|
|
52
|
+
&block
|
|
53
|
+
)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Track Kafka produce offset for lag monitoring
|
|
57
|
+
#
|
|
58
|
+
# @param topic [String] The Kafka topic name
|
|
59
|
+
# @param partition [Integer] The partition number
|
|
60
|
+
# @param offset [Integer] The offset of the produced message
|
|
61
|
+
# @return [Boolean, nil] true if tracking succeeded, nil if disabled
|
|
62
|
+
# @!visibility private
|
|
63
|
+
def track_kafka_produce(topic, partition, offset)
|
|
64
|
+
processor&.track_kafka_produce(topic, partition, offset, Core::Utils::Time.now)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Track Kafka message consumption for consumer lag monitoring
|
|
68
|
+
#
|
|
69
|
+
# @param topic [String] The Kafka topic name
|
|
70
|
+
# @param partition [Integer] The partition number
|
|
71
|
+
# @param offset [Integer] The offset of the consumed message
|
|
72
|
+
# @return [Boolean, nil] true if tracking succeeded, nil if disabled
|
|
73
|
+
# @!visibility private
|
|
74
|
+
def track_kafka_consume(topic, partition, offset)
|
|
75
|
+
processor&.track_kafka_consume(topic, partition, offset, Core::Utils::Time.now)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Check if Data Streams Monitoring is enabled and available
|
|
79
|
+
#
|
|
80
|
+
# @return [Boolean] true if the processor is available
|
|
81
|
+
# @public_api
|
|
82
|
+
def enabled?
|
|
83
|
+
!processor.nil?
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
private
|
|
87
|
+
|
|
88
|
+
def processor
|
|
89
|
+
components.data_streams
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def components
|
|
93
|
+
Datadog.send(:components)
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# Expose Data Streams to global shared objects
|
|
98
|
+
Extensions.activate!
|
|
99
|
+
end
|
|
100
|
+
end
|
data/lib/datadog/di/component.rb
CHANGED
|
@@ -29,22 +29,6 @@ module Datadog
|
|
|
29
29
|
end
|
|
30
30
|
end
|
|
31
31
|
|
|
32
|
-
def build!(settings, agent_settings, logger, telemetry: nil)
|
|
33
|
-
unless settings.respond_to?(:dynamic_instrumentation) && settings.dynamic_instrumentation.enabled
|
|
34
|
-
raise "Requested DI component but DI is not enabled in settings"
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
unless settings.respond_to?(:remote) && settings.remote.enabled
|
|
38
|
-
raise "Requested DI component but remote config is not enabled in settings"
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
unless environment_supported?(settings, logger)
|
|
42
|
-
raise "DI does not support the environment (development or Ruby version too low or not MRI)"
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
new(settings, agent_settings, logger, code_tracker: DI.code_tracker, telemetry: telemetry)
|
|
46
|
-
end
|
|
47
|
-
|
|
48
32
|
# Checks whether the runtime environment is supported by
|
|
49
33
|
# dynamic instrumentation. Currently we only require that, if Rails
|
|
50
34
|
# is used, that Rails environment is not development because
|
data/lib/datadog/di/error.rb
CHANGED
|
@@ -10,6 +10,10 @@ module Datadog
|
|
|
10
10
|
#
|
|
11
11
|
# @api private
|
|
12
12
|
class Error < StandardError
|
|
13
|
+
# Internal Dynamic Instrumentation error ("should never happen").
|
|
14
|
+
class InternalError < Error
|
|
15
|
+
end
|
|
16
|
+
|
|
13
17
|
# Probe does not contain a line number (i.e., is not a line probe).
|
|
14
18
|
class MissingLineNumber < Error
|
|
15
19
|
end
|
|
@@ -89,11 +89,7 @@ module Datadog
|
|
|
89
89
|
# from the method but from outside of the method).
|
|
90
90
|
Location = Struct.new(:path, :lineno, :label)
|
|
91
91
|
|
|
92
|
-
def hook_method(probe,
|
|
93
|
-
unless block
|
|
94
|
-
raise ArgumentError, 'block is required'
|
|
95
|
-
end
|
|
96
|
-
|
|
92
|
+
def hook_method(probe, responder)
|
|
97
93
|
lock.synchronize do
|
|
98
94
|
if probe.instrumentation_module
|
|
99
95
|
# Already instrumented, warn?
|
|
@@ -130,10 +126,34 @@ module Datadog
|
|
|
130
126
|
caller_locations: caller_locations,
|
|
131
127
|
)
|
|
132
128
|
continue = condition.satisfied?(context)
|
|
133
|
-
rescue
|
|
134
|
-
|
|
129
|
+
rescue => exc
|
|
130
|
+
# Evaluation error exception can be raised for "expected"
|
|
131
|
+
# errors, we probably need another setting to control whether
|
|
132
|
+
# these exceptions are propagated.
|
|
133
|
+
raise if settings.dynamic_instrumentation.internal.propagate_all_exceptions &&
|
|
134
|
+
!exc.is_a?(DI::Error::ExpressionEvaluationError)
|
|
135
|
+
|
|
136
|
+
if context
|
|
137
|
+
# We want to report evaluation errors for conditions
|
|
138
|
+
# as probe snapshots. However, if we failed to create
|
|
139
|
+
# the context, we won't be able to report anything as
|
|
140
|
+
# the probe notifier builder requires a context.
|
|
141
|
+
begin
|
|
142
|
+
responder.probe_condition_evaluation_failed_callback(context, exc)
|
|
143
|
+
rescue
|
|
144
|
+
raise if settings.dynamic_instrumentation.internal.propagate_all_exceptions
|
|
145
|
+
|
|
146
|
+
# TODO log / report via telemetry?
|
|
147
|
+
end
|
|
148
|
+
else
|
|
149
|
+
_ = 42 # stop standard from wrecking this code
|
|
150
|
+
|
|
151
|
+
raise if settings.dynamic_instrumentation.internal.propagate_all_exceptions
|
|
152
|
+
|
|
153
|
+
# TODO log / report via telemetry?
|
|
154
|
+
# If execution gets here, there is probably a bug in the tracer.
|
|
155
|
+
end
|
|
135
156
|
|
|
136
|
-
# TODO log / report via telemetry?
|
|
137
157
|
continue = false
|
|
138
158
|
end
|
|
139
159
|
end
|
|
@@ -195,8 +215,7 @@ module Datadog
|
|
|
195
215
|
caller_locations: caller_locs,
|
|
196
216
|
return_value: rv, duration: duration, exception: exc,)
|
|
197
217
|
|
|
198
|
-
|
|
199
|
-
block&.call(context)
|
|
218
|
+
responder.probe_executed_callback(context)
|
|
200
219
|
if exc
|
|
201
220
|
raise exc
|
|
202
221
|
else
|
|
@@ -258,11 +277,7 @@ module Datadog
|
|
|
258
277
|
# not for eval'd code, unless the eval'd code is associated with
|
|
259
278
|
# a file name and client invokes this method with the correct
|
|
260
279
|
# file name for the eval'd code.
|
|
261
|
-
def hook_line(probe,
|
|
262
|
-
unless block
|
|
263
|
-
raise ArgumentError, 'No block given to hook_line'
|
|
264
|
-
end
|
|
265
|
-
|
|
280
|
+
def hook_line(probe, responder)
|
|
266
281
|
lock.synchronize do
|
|
267
282
|
if probe.instrumentation_trace_point
|
|
268
283
|
# Already instrumented, warn?
|
|
@@ -367,14 +382,44 @@ module Datadog
|
|
|
367
382
|
|
|
368
383
|
if continue
|
|
369
384
|
if condition = probe.condition
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
385
|
+
begin
|
|
386
|
+
context = Context.new(
|
|
387
|
+
locals: Instrumenter.get_local_variables(tp),
|
|
388
|
+
target_self: tp.self,
|
|
389
|
+
probe: probe, settings: settings, serializer: serializer,
|
|
390
|
+
path: tp.path,
|
|
391
|
+
caller_locations: caller_locations,
|
|
392
|
+
)
|
|
393
|
+
continue = condition.satisfied?(context)
|
|
394
|
+
rescue => exc
|
|
395
|
+
# Evaluation error exception can be raised for "expected"
|
|
396
|
+
# errors, we probably need another setting to control whether
|
|
397
|
+
# these exceptions are propagated.
|
|
398
|
+
raise if settings.dynamic_instrumentation.internal.propagate_all_exceptions &&
|
|
399
|
+
!exc.is_a?(DI::Error::ExpressionEvaluationError)
|
|
400
|
+
|
|
401
|
+
continue = false
|
|
402
|
+
if context
|
|
403
|
+
# We want to report evaluation errors for conditions
|
|
404
|
+
# as probe snapshots. However, if we failed to create
|
|
405
|
+
# the context, we won't be able to report anything as
|
|
406
|
+
# the probe notifier builder requires a context.
|
|
407
|
+
begin
|
|
408
|
+
responder.probe_condition_evaluation_failed_callback(context, condition, exc)
|
|
409
|
+
rescue
|
|
410
|
+
raise if settings.dynamic_instrumentation.internal.propagate_all_exceptions
|
|
411
|
+
|
|
412
|
+
# TODO log / report via telemetry?
|
|
413
|
+
end
|
|
414
|
+
else
|
|
415
|
+
_ = 42 # stop standard from wrecking this code
|
|
416
|
+
|
|
417
|
+
raise if settings.dynamic_instrumentation.internal.propagate_all_exceptions
|
|
418
|
+
|
|
419
|
+
# TODO log / report via telemetry?
|
|
420
|
+
# If execution gets here, there is probably a bug in the tracer.
|
|
421
|
+
end
|
|
422
|
+
end
|
|
378
423
|
end
|
|
379
424
|
end
|
|
380
425
|
|
|
@@ -393,8 +438,7 @@ module Datadog
|
|
|
393
438
|
caller_locations: caller_locations,
|
|
394
439
|
)
|
|
395
440
|
|
|
396
|
-
|
|
397
|
-
block&.call(context)
|
|
441
|
+
responder.probe_executed_callback(context)
|
|
398
442
|
end
|
|
399
443
|
rescue => exc
|
|
400
444
|
raise if settings.dynamic_instrumentation.internal.propagate_all_exceptions
|
|
@@ -409,9 +453,11 @@ module Datadog
|
|
|
409
453
|
# TODO test this path
|
|
410
454
|
end
|
|
411
455
|
|
|
412
|
-
#
|
|
456
|
+
# Internal sanity check - untargeted trace points create a huge
|
|
457
|
+
# performance impact, and we absolutely do not want to set them
|
|
458
|
+
# accidentally.
|
|
413
459
|
if !iseq && !permit_untargeted_trace_points
|
|
414
|
-
raise "Trying to use an untargeted trace point when user did not permit it"
|
|
460
|
+
raise Error::InternalError, "Trying to use an untargeted trace point when user did not permit it"
|
|
415
461
|
end
|
|
416
462
|
|
|
417
463
|
lock.synchronize do
|
|
@@ -443,11 +489,11 @@ module Datadog
|
|
|
443
489
|
end
|
|
444
490
|
end
|
|
445
491
|
|
|
446
|
-
def hook(probe,
|
|
492
|
+
def hook(probe, responder)
|
|
447
493
|
if probe.method?
|
|
448
|
-
hook_method(probe,
|
|
494
|
+
hook_method(probe, responder)
|
|
449
495
|
elsif probe.line?
|
|
450
|
-
hook_line(probe,
|
|
496
|
+
hook_line(probe, responder)
|
|
451
497
|
else
|
|
452
498
|
# TODO add test coverage for this path
|
|
453
499
|
logger.debug { "di: unknown probe type to hook: #{probe}" }
|
data/lib/datadog/di/probe.rb
CHANGED
|
@@ -86,6 +86,16 @@ module Datadog
|
|
|
86
86
|
@rate_limit = rate_limit || (@capture_snapshot ? 1 : 5000)
|
|
87
87
|
@rate_limiter = Datadog::Core::TokenBucket.new(@rate_limit)
|
|
88
88
|
|
|
89
|
+
# At most one report per second.
|
|
90
|
+
# We create the rate limiter here even though it may never be used,
|
|
91
|
+
# to avoid having to synchronize the creation since method probes
|
|
92
|
+
# can be executed on multiple threads concurrently (even if line
|
|
93
|
+
# probes are never executed concurrently since those are done in a
|
|
94
|
+
# trace point).
|
|
95
|
+
if condition
|
|
96
|
+
@condition_evaluation_failed_rate_limiter = Datadog::Core::TokenBucket.new(1)
|
|
97
|
+
end
|
|
98
|
+
|
|
89
99
|
@emitting_notified = false
|
|
90
100
|
end
|
|
91
101
|
|
|
@@ -115,6 +125,16 @@ module Datadog
|
|
|
115
125
|
# Rate limiter object. For internal DI use only.
|
|
116
126
|
attr_reader :rate_limiter
|
|
117
127
|
|
|
128
|
+
# Rate limiter object for sending snapshots with evaluation errors
|
|
129
|
+
# for when probe condition evaluation fails.
|
|
130
|
+
# This rate limit is separate from the "base" rate limit for the probe
|
|
131
|
+
# because when the condition evaluation succeeds we want the "base"
|
|
132
|
+
# rate limit applied, not tainted by any evaluation errors
|
|
133
|
+
# (for example, the condition can be highly selective, and when it
|
|
134
|
+
# does not hold the evaluation may fail - we don't want to use up the
|
|
135
|
+
# probe rate limit for the errors).
|
|
136
|
+
attr_reader :condition_evaluation_failed_rate_limiter
|
|
137
|
+
|
|
118
138
|
def capture_snapshot?
|
|
119
139
|
@capture_snapshot
|
|
120
140
|
end
|
|
@@ -101,7 +101,7 @@ module Datadog
|
|
|
101
101
|
end
|
|
102
102
|
|
|
103
103
|
begin
|
|
104
|
-
instrumenter.hook(probe,
|
|
104
|
+
instrumenter.hook(probe, self)
|
|
105
105
|
|
|
106
106
|
@installed_probes[probe.id] = probe
|
|
107
107
|
payload = probe_notification_builder.build_installed(probe)
|
|
@@ -184,7 +184,7 @@ module Datadog
|
|
|
184
184
|
begin
|
|
185
185
|
# TODO is it OK to hook from trace point handler?
|
|
186
186
|
# TODO the class is now defined, but can hooking still fail?
|
|
187
|
-
instrumenter.hook(probe,
|
|
187
|
+
instrumenter.hook(probe, self)
|
|
188
188
|
@pending_probes.delete(probe.id)
|
|
189
189
|
break
|
|
190
190
|
rescue Error::DITargetNotDefined
|
|
@@ -242,6 +242,14 @@ module Datadog
|
|
|
242
242
|
probe_notifier_worker.add_snapshot(payload)
|
|
243
243
|
end
|
|
244
244
|
|
|
245
|
+
def probe_condition_evaluation_failed_callback(context, expr, exc)
|
|
246
|
+
probe = context.probe
|
|
247
|
+
if probe.condition_evaluation_failed_rate_limiter&.allow?
|
|
248
|
+
payload = probe_notification_builder.build_condition_evaluation_failed(context, expr, exc)
|
|
249
|
+
probe_notifier_worker.add_snapshot(payload)
|
|
250
|
+
end
|
|
251
|
+
end
|
|
252
|
+
|
|
245
253
|
# Class/module definition trace point (:end type).
|
|
246
254
|
# Used to install hooks when the target classes/modules aren't yet
|
|
247
255
|
# defined when the hook request is received.
|