datadog 2.22.0 → 2.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +100 -1
- data/ext/LIBDATADOG_DEVELOPMENT.md +1 -58
- data/ext/datadog_profiling_native_extension/collectors_stack.c +21 -5
- data/ext/datadog_profiling_native_extension/crashtracking_runtime_stacks.c +239 -0
- data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +1 -1
- data/ext/datadog_profiling_native_extension/extconf.rb +9 -4
- data/ext/datadog_profiling_native_extension/heap_recorder.c +1 -1
- data/ext/datadog_profiling_native_extension/private_vm_api_access.c +12 -0
- data/ext/datadog_profiling_native_extension/private_vm_api_access.h +4 -0
- data/ext/datadog_profiling_native_extension/profiling.c +2 -0
- data/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/context.rb +2 -1
- data/lib/datadog/appsec/remote.rb +5 -9
- data/lib/datadog/appsec/response.rb +18 -4
- data/lib/datadog/appsec/security_engine/result.rb +2 -1
- data/lib/datadog/core/configuration/components.rb +30 -3
- data/lib/datadog/core/configuration/config_helper.rb +2 -2
- data/lib/datadog/core/configuration/deprecations.rb +2 -2
- data/lib/datadog/core/configuration/option_definition.rb +4 -2
- data/lib/datadog/core/configuration/options.rb +8 -5
- data/lib/datadog/core/configuration/settings.rb +28 -3
- data/lib/datadog/core/configuration/supported_configurations.rb +332 -302
- data/lib/datadog/core/ddsketch.rb +0 -2
- data/lib/datadog/core/environment/cgroup.rb +52 -25
- data/lib/datadog/core/environment/container.rb +140 -46
- data/lib/datadog/core/environment/ext.rb +7 -0
- data/lib/datadog/core/environment/process.rb +87 -0
- data/lib/datadog/core/feature_flags.rb +61 -0
- data/lib/datadog/core/rate_limiter.rb +9 -1
- data/lib/datadog/core/remote/client/capabilities.rb +7 -0
- data/lib/datadog/core/remote/client.rb +14 -6
- data/lib/datadog/core/remote/component.rb +6 -4
- data/lib/datadog/core/remote/configuration/content.rb +15 -2
- data/lib/datadog/core/remote/configuration/digest.rb +14 -7
- data/lib/datadog/core/remote/configuration/repository.rb +1 -1
- data/lib/datadog/core/remote/configuration/target.rb +13 -6
- data/lib/datadog/core/remote/transport/config.rb +4 -25
- data/lib/datadog/core/remote/transport/http/config.rb +10 -50
- data/lib/datadog/core/remote/transport/http/negotiation.rb +14 -44
- data/lib/datadog/core/remote/transport/http.rb +15 -24
- data/lib/datadog/core/remote/transport/negotiation.rb +8 -33
- 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 +59 -16
- data/lib/datadog/core/telemetry/event/app_started.rb +86 -49
- data/lib/datadog/core/telemetry/event/synth_app_client_configuration_change.rb +27 -4
- data/lib/datadog/core/telemetry/logger.rb +2 -2
- data/lib/datadog/core/telemetry/logging.rb +2 -8
- data/lib/datadog/core/telemetry/metrics_manager.rb +9 -0
- data/lib/datadog/core/telemetry/request.rb +17 -3
- data/lib/datadog/core/telemetry/transport/http/telemetry.rb +3 -34
- data/lib/datadog/core/telemetry/transport/http.rb +21 -16
- data/lib/datadog/core/telemetry/transport/telemetry.rb +3 -11
- data/lib/datadog/core/telemetry/worker.rb +88 -32
- data/lib/datadog/core/transport/ext.rb +2 -0
- data/lib/datadog/core/transport/http/api/endpoint.rb +9 -4
- data/lib/datadog/core/transport/http/api/instance.rb +4 -21
- data/lib/datadog/core/transport/http/builder.rb +9 -5
- data/lib/datadog/core/transport/http/client.rb +80 -0
- data/lib/datadog/core/transport/http.rb +22 -19
- data/lib/datadog/core/transport/response.rb +9 -0
- data/lib/datadog/core/transport/transport.rb +90 -0
- data/lib/datadog/core/utils/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 +8 -2
- data/lib/datadog/core/utils/time.rb +1 -1
- data/lib/datadog/core/utils.rb +2 -0
- data/lib/datadog/core/workers/async.rb +10 -1
- data/lib/datadog/core/workers/interval_loop.rb +44 -3
- data/lib/datadog/core/workers/polling.rb +2 -0
- data/lib/datadog/core/workers/queue.rb +100 -1
- data/lib/datadog/data_streams/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/stats.rb +52 -0
- data/lib/datadog/data_streams/transport/http.rb +40 -0
- data/lib/datadog/data_streams/transport/stats.rb +46 -0
- data/lib/datadog/data_streams.rb +100 -0
- data/lib/datadog/di/component.rb +0 -16
- data/lib/datadog/di/contrib/active_record.rb +31 -5
- data/lib/datadog/di/el/compiler.rb +8 -4
- data/lib/datadog/di/el/evaluator.rb +1 -1
- data/lib/datadog/di/error.rb +9 -0
- data/lib/datadog/di/instrumenter.rb +93 -34
- data/lib/datadog/di/probe.rb +20 -0
- data/lib/datadog/di/probe_builder.rb +2 -1
- data/lib/datadog/di/probe_manager.rb +47 -33
- data/lib/datadog/di/probe_notification_builder.rb +77 -25
- data/lib/datadog/di/proc_responder.rb +32 -0
- data/lib/datadog/di/remote.rb +89 -84
- data/lib/datadog/di/transport/diagnostics.rb +8 -36
- data/lib/datadog/di/transport/http/diagnostics.rb +1 -33
- data/lib/datadog/di/transport/http/input.rb +1 -33
- data/lib/datadog/di/transport/http.rb +32 -17
- data/lib/datadog/di/transport/input.rb +67 -34
- data/lib/datadog/di.rb +61 -5
- 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 +70 -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 +67 -0
- data/lib/datadog/open_feature/resolution_details.rb +35 -0
- data/lib/datadog/open_feature/transport.rb +70 -0
- data/lib/datadog/open_feature.rb +19 -0
- data/lib/datadog/opentelemetry/api/baggage.rb +1 -1
- data/lib/datadog/opentelemetry/configuration/settings.rb +159 -0
- data/lib/datadog/opentelemetry/metrics.rb +117 -0
- data/lib/datadog/opentelemetry/sdk/configurator.rb +25 -1
- data/lib/datadog/opentelemetry/sdk/metrics_exporter.rb +35 -0
- data/lib/datadog/opentelemetry.rb +3 -0
- data/lib/datadog/profiling/collectors/code_provenance.rb +41 -7
- 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/collectors/info.rb +2 -1
- data/lib/datadog/profiling/component.rb +12 -11
- data/lib/datadog/profiling/http_transport.rb +4 -1
- data/lib/datadog/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/extensions.rb +10 -2
- 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 +35 -4
- 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 +9 -1
- data/lib/datadog/tracing/contrib/utils/quantization/hash.rb +3 -1
- 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 +49 -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/diagnostics/environment_logger.rb +1 -1
- data/lib/datadog/tracing/metadata/ext.rb +1 -1
- data/lib/datadog/tracing/remote.rb +1 -9
- data/lib/datadog/tracing/span_event.rb +2 -2
- data/lib/datadog/tracing/span_operation.rb +9 -4
- data/lib/datadog/tracing/trace_operation.rb +44 -6
- data/lib/datadog/tracing/tracer.rb +42 -16
- data/lib/datadog/tracing/transport/http/client.rb +12 -26
- data/lib/datadog/tracing/transport/http/traces.rb +2 -50
- data/lib/datadog/tracing/transport/http.rb +15 -9
- data/lib/datadog/tracing/transport/io/client.rb +1 -1
- data/lib/datadog/tracing/transport/trace_formatter.rb +11 -0
- data/lib/datadog/tracing/transport/traces.rb +9 -71
- data/lib/datadog/tracing/workers/trace_writer.rb +5 -0
- data/lib/datadog/tracing/writer.rb +1 -0
- data/lib/datadog/version.rb +2 -2
- data/lib/datadog.rb +2 -0
- metadata +78 -21
- data/lib/datadog/core/remote/transport/http/api.rb +0 -53
- data/lib/datadog/core/remote/transport/http/client.rb +0 -49
- data/lib/datadog/core/telemetry/transport/http/api.rb +0 -43
- data/lib/datadog/core/telemetry/transport/http/client.rb +0 -49
- data/lib/datadog/core/transport/http/api/spec.rb +0 -36
- data/lib/datadog/di/transport/http/api.rb +0 -42
- data/lib/datadog/di/transport/http/client.rb +0 -47
- data/lib/datadog/opentelemetry/api/baggage.rbs +0 -26
- data/lib/datadog/tracing/transport/http/api.rb +0 -44
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../stats'
|
|
4
|
+
require_relative '../../../core/transport/http/api/endpoint'
|
|
5
|
+
require_relative '../../../core/transport/http/response'
|
|
6
|
+
|
|
7
|
+
module Datadog
|
|
8
|
+
module DataStreams
|
|
9
|
+
module Transport
|
|
10
|
+
module HTTP
|
|
11
|
+
# HTTP transport behavior for Data Streams stats
|
|
12
|
+
module Stats
|
|
13
|
+
# Response from HTTP transport for DSM stats
|
|
14
|
+
class Response
|
|
15
|
+
include Datadog::Core::Transport::HTTP::Response
|
|
16
|
+
|
|
17
|
+
def initialize(http_response)
|
|
18
|
+
super
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
module API
|
|
23
|
+
# Endpoint for submitting DSM stats data
|
|
24
|
+
class Endpoint < Core::Transport::HTTP::API::Endpoint
|
|
25
|
+
def initialize(path)
|
|
26
|
+
super(:post, path)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def call(env, &block)
|
|
30
|
+
# Build request
|
|
31
|
+
env.verb = verb
|
|
32
|
+
env.path = path
|
|
33
|
+
env.body = env.request.parcel.data
|
|
34
|
+
|
|
35
|
+
# Send request
|
|
36
|
+
http_response = yield(env)
|
|
37
|
+
|
|
38
|
+
# Build response
|
|
39
|
+
Response.new(http_response)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def encoder
|
|
43
|
+
# DSM handles encoding in the transport layer
|
|
44
|
+
nil
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../../core/transport/http'
|
|
4
|
+
require_relative 'http/stats'
|
|
5
|
+
require_relative 'stats'
|
|
6
|
+
|
|
7
|
+
module Datadog
|
|
8
|
+
module DataStreams
|
|
9
|
+
module Transport
|
|
10
|
+
# HTTP transport for Data Streams Monitoring
|
|
11
|
+
module HTTP
|
|
12
|
+
V01 = Stats::API::Endpoint.new(
|
|
13
|
+
'/v0.1/pipeline_stats'
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
module_function
|
|
17
|
+
|
|
18
|
+
# Builds a new Transport::HTTP::Client with default settings
|
|
19
|
+
def default(
|
|
20
|
+
agent_settings:,
|
|
21
|
+
logger:
|
|
22
|
+
)
|
|
23
|
+
Core::Transport::HTTP.build(
|
|
24
|
+
agent_settings: agent_settings,
|
|
25
|
+
logger: logger,
|
|
26
|
+
headers: {
|
|
27
|
+
'Content-Type' => 'application/msgpack',
|
|
28
|
+
'Content-Encoding' => 'gzip'
|
|
29
|
+
}
|
|
30
|
+
) do |transport|
|
|
31
|
+
transport.api 'v0.1', V01, default: true
|
|
32
|
+
|
|
33
|
+
# Call block to apply any customization, if provided
|
|
34
|
+
yield(transport) if block_given?
|
|
35
|
+
end.to_transport(Transport::Stats::Transport)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
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
|
+
require_relative '../../core/transport/transport'
|
|
8
|
+
|
|
9
|
+
module Datadog
|
|
10
|
+
module DataStreams
|
|
11
|
+
module Transport
|
|
12
|
+
module Stats
|
|
13
|
+
# Parcel for encoded DSM stats payload
|
|
14
|
+
class EncodedParcel
|
|
15
|
+
include Datadog::Core::Transport::Parcel
|
|
16
|
+
|
|
17
|
+
def initialize(data)
|
|
18
|
+
@data = data
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
attr_reader :data
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Request for DSM stats
|
|
25
|
+
class Request < Datadog::Core::Transport::Request
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Transport for Data Streams Monitoring stats
|
|
29
|
+
class Transport < Core::Transport::Transport
|
|
30
|
+
def send_stats(payload)
|
|
31
|
+
# MessagePack encode and gzip compress the payload
|
|
32
|
+
msgpack_data = MessagePack.pack(payload)
|
|
33
|
+
compressed_data = Zlib.gzip(msgpack_data)
|
|
34
|
+
|
|
35
|
+
# Create parcel and request
|
|
36
|
+
parcel = EncodedParcel.new(compressed_data)
|
|
37
|
+
request = Request.new(parcel)
|
|
38
|
+
|
|
39
|
+
# Send to agent
|
|
40
|
+
client.send_request(:stats, request)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
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
|
|
@@ -1,12 +1,38 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
# steep thinks all of the arguments are nil here and does not know what ActiveRecord is.
|
|
4
|
+
# steep:ignore:start
|
|
5
|
+
|
|
6
|
+
Datadog::DI::Serializer.register(
|
|
7
|
+
# This serializer uses a dynamic condition to determine its applicability
|
|
8
|
+
# to a particular value. A simpler case could have been a serializer for
|
|
9
|
+
# a particular class, but in this case any ActiveRecord model is covered
|
|
10
|
+
# and they all have different classes.
|
|
11
|
+
#
|
|
12
|
+
# An alternative could have been to make DI specifically provide lookup
|
|
13
|
+
# logic for "instances of classes derived from X", but a condition Proc
|
|
14
|
+
# is more universal.
|
|
15
|
+
condition: lambda { |value| ActiveRecord::Base === value }
|
|
16
|
+
) do |serializer, value, name:, depth:|
|
|
17
|
+
# +serializer+ is an instance of DI::Serializer.
|
|
18
|
+
# Use it to perform the serialization to primitive values.
|
|
19
|
+
#
|
|
20
|
+
# +value+ is the value to serialize. It should match the condition
|
|
21
|
+
# provided above, meaning it would be an ActiveRecord::Base instance.
|
|
22
|
+
#
|
|
23
|
+
# +name+ is the name of the (local/instance) variable being serialized.
|
|
24
|
+
# The name is used by DI for redaction (upstream of serialization logic),
|
|
25
|
+
# and could potentially be used for redaction here also.
|
|
26
|
+
#
|
|
27
|
+
# +depth+ is the remaining depth for serializing collections and objects.
|
|
28
|
+
# It should always be an integer.
|
|
29
|
+
# Reduce it by 1 when invoking +serialize_value+ on the contents of +value+.
|
|
30
|
+
# This serializer could also potentially do its own depth limiting.
|
|
6
31
|
value_to_serialize = {
|
|
7
32
|
attributes: value.attributes,
|
|
8
33
|
new_record: value.new_record?,
|
|
9
34
|
}
|
|
10
|
-
serializer.serialize_value(value_to_serialize, depth: depth
|
|
11
|
-
# steep:ignore:end
|
|
35
|
+
serializer.serialize_value(value_to_serialize, depth: depth - 1, type: value.class)
|
|
12
36
|
end
|
|
37
|
+
|
|
38
|
+
# steep:ignore:end
|
|
@@ -22,7 +22,8 @@ module Datadog
|
|
|
22
22
|
|
|
23
23
|
private
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
# Steep: https://github.com/soutaro/steep/issues/363
|
|
26
|
+
OPERATORS = { # steep:ignore IncompatibleAssignment
|
|
26
27
|
'eq' => '==',
|
|
27
28
|
'ne' => '!=',
|
|
28
29
|
'ge' => '>=',
|
|
@@ -31,16 +32,19 @@ module Datadog
|
|
|
31
32
|
'lt' => '<',
|
|
32
33
|
}.freeze
|
|
33
34
|
|
|
35
|
+
# Steep: https://github.com/soutaro/steep/issues/363
|
|
34
36
|
SINGLE_ARG_METHODS = %w[
|
|
35
37
|
len isEmpty isUndefined
|
|
36
|
-
].freeze
|
|
38
|
+
].freeze # steep:ignore IncompatibleAssignment
|
|
37
39
|
|
|
40
|
+
# Steep: https://github.com/soutaro/steep/issues/363
|
|
38
41
|
TWO_ARG_METHODS = %w[
|
|
39
42
|
startsWith endsWith contains matches
|
|
40
43
|
getmember index instanceof
|
|
41
|
-
].freeze
|
|
44
|
+
].freeze # steep:ignore IncompatibleAssignment
|
|
42
45
|
|
|
43
|
-
|
|
46
|
+
# Steep: https://github.com/soutaro/steep/issues/363
|
|
47
|
+
MULTI_ARG_METHODS = { # steep:ignore IncompatibleAssignment
|
|
44
48
|
'and' => '&&',
|
|
45
49
|
'or' => '||',
|
|
46
50
|
}.freeze
|
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
|
|
@@ -38,6 +42,11 @@ module Datadog
|
|
|
38
42
|
class ProbePreviouslyFailed < Error
|
|
39
43
|
end
|
|
40
44
|
|
|
45
|
+
# Raised when trying to instrument a probe when there is existing
|
|
46
|
+
# instrumentation for the same probe id.
|
|
47
|
+
class AlreadyInstrumented < Error
|
|
48
|
+
end
|
|
49
|
+
|
|
41
50
|
# Raised when installing a line probe and multiple files match the
|
|
42
51
|
# specified path suffix.
|
|
43
52
|
# A probe must be installed into one file only, since UI only
|
|
@@ -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
|
|
@@ -146,7 +166,10 @@ module Datadog
|
|
|
146
166
|
depth: probe.max_capture_depth || settings.dynamic_instrumentation.max_capture_depth,
|
|
147
167
|
attribute_count: probe.max_capture_attribute_count || settings.dynamic_instrumentation.max_capture_attribute_count)
|
|
148
168
|
end
|
|
149
|
-
|
|
169
|
+
# We intentionally do not use Core::Utils::Time.get_time
|
|
170
|
+
# here because the time provider may be overridden by the
|
|
171
|
+
# customer, and DI is not allowed to invoke customer code.
|
|
172
|
+
start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
150
173
|
|
|
151
174
|
rv = nil
|
|
152
175
|
begin
|
|
@@ -170,7 +193,7 @@ module Datadog
|
|
|
170
193
|
# the instrumentation callback runs.
|
|
171
194
|
end
|
|
172
195
|
|
|
173
|
-
duration =
|
|
196
|
+
duration = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start_time
|
|
174
197
|
# The method itself is not part of the stack trace because
|
|
175
198
|
# we are getting the stack trace from outside of the method.
|
|
176
199
|
# Add the method in manually as the top frame.
|
|
@@ -195,8 +218,7 @@ module Datadog
|
|
|
195
218
|
caller_locations: caller_locs,
|
|
196
219
|
return_value: rv, duration: duration, exception: exc,)
|
|
197
220
|
|
|
198
|
-
|
|
199
|
-
block&.call(context)
|
|
221
|
+
responder.probe_executed_callback(context)
|
|
200
222
|
if exc
|
|
201
223
|
raise exc
|
|
202
224
|
else
|
|
@@ -237,6 +259,8 @@ module Datadog
|
|
|
237
259
|
|
|
238
260
|
probe.instrumentation_module = mod
|
|
239
261
|
cls.send(:prepend, mod)
|
|
262
|
+
|
|
263
|
+
DI.instrumented_count_inc(:method)
|
|
240
264
|
end
|
|
241
265
|
end
|
|
242
266
|
|
|
@@ -249,6 +273,8 @@ module Datadog
|
|
|
249
273
|
if mod = probe.instrumentation_module
|
|
250
274
|
mod.send(:remove_method, probe.method_name)
|
|
251
275
|
probe.instrumentation_module = nil
|
|
276
|
+
|
|
277
|
+
DI.instrumented_count_dec(:method)
|
|
252
278
|
end
|
|
253
279
|
end
|
|
254
280
|
end
|
|
@@ -258,11 +284,7 @@ module Datadog
|
|
|
258
284
|
# not for eval'd code, unless the eval'd code is associated with
|
|
259
285
|
# a file name and client invokes this method with the correct
|
|
260
286
|
# 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
|
-
|
|
287
|
+
def hook_line(probe, responder)
|
|
266
288
|
lock.synchronize do
|
|
267
289
|
if probe.instrumentation_trace_point
|
|
268
290
|
# Already instrumented, warn?
|
|
@@ -367,14 +389,44 @@ module Datadog
|
|
|
367
389
|
|
|
368
390
|
if continue
|
|
369
391
|
if condition = probe.condition
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
392
|
+
begin
|
|
393
|
+
context = Context.new(
|
|
394
|
+
locals: Instrumenter.get_local_variables(tp),
|
|
395
|
+
target_self: tp.self,
|
|
396
|
+
probe: probe, settings: settings, serializer: serializer,
|
|
397
|
+
path: tp.path,
|
|
398
|
+
caller_locations: caller_locations,
|
|
399
|
+
)
|
|
400
|
+
continue = condition.satisfied?(context)
|
|
401
|
+
rescue => exc
|
|
402
|
+
# Evaluation error exception can be raised for "expected"
|
|
403
|
+
# errors, we probably need another setting to control whether
|
|
404
|
+
# these exceptions are propagated.
|
|
405
|
+
raise if settings.dynamic_instrumentation.internal.propagate_all_exceptions &&
|
|
406
|
+
!exc.is_a?(DI::Error::ExpressionEvaluationError)
|
|
407
|
+
|
|
408
|
+
continue = false
|
|
409
|
+
if context
|
|
410
|
+
# We want to report evaluation errors for conditions
|
|
411
|
+
# as probe snapshots. However, if we failed to create
|
|
412
|
+
# the context, we won't be able to report anything as
|
|
413
|
+
# the probe notifier builder requires a context.
|
|
414
|
+
begin
|
|
415
|
+
responder.probe_condition_evaluation_failed_callback(context, condition, exc)
|
|
416
|
+
rescue
|
|
417
|
+
raise if settings.dynamic_instrumentation.internal.propagate_all_exceptions
|
|
418
|
+
|
|
419
|
+
# TODO log / report via telemetry?
|
|
420
|
+
end
|
|
421
|
+
else
|
|
422
|
+
_ = 42 # stop standard from wrecking this code
|
|
423
|
+
|
|
424
|
+
raise if settings.dynamic_instrumentation.internal.propagate_all_exceptions
|
|
425
|
+
|
|
426
|
+
# TODO log / report via telemetry?
|
|
427
|
+
# If execution gets here, there is probably a bug in the tracer.
|
|
428
|
+
end
|
|
429
|
+
end
|
|
378
430
|
end
|
|
379
431
|
end
|
|
380
432
|
|
|
@@ -393,8 +445,7 @@ module Datadog
|
|
|
393
445
|
caller_locations: caller_locations,
|
|
394
446
|
)
|
|
395
447
|
|
|
396
|
-
|
|
397
|
-
block&.call(context)
|
|
448
|
+
responder.probe_executed_callback(context)
|
|
398
449
|
end
|
|
399
450
|
rescue => exc
|
|
400
451
|
raise if settings.dynamic_instrumentation.internal.propagate_all_exceptions
|
|
@@ -409,9 +460,11 @@ module Datadog
|
|
|
409
460
|
# TODO test this path
|
|
410
461
|
end
|
|
411
462
|
|
|
412
|
-
#
|
|
463
|
+
# Internal sanity check - untargeted trace points create a huge
|
|
464
|
+
# performance impact, and we absolutely do not want to set them
|
|
465
|
+
# accidentally.
|
|
413
466
|
if !iseq && !permit_untargeted_trace_points
|
|
414
|
-
raise "Trying to use an untargeted trace point when user did not permit it"
|
|
467
|
+
raise Error::InternalError, "Trying to use an untargeted trace point when user did not permit it"
|
|
415
468
|
end
|
|
416
469
|
|
|
417
470
|
lock.synchronize do
|
|
@@ -424,12 +477,16 @@ module Datadog
|
|
|
424
477
|
# actual_path could be nil if we don't use targeted trace points.
|
|
425
478
|
probe.instrumented_path = actual_path
|
|
426
479
|
|
|
427
|
-
|
|
480
|
+
# TracePoint#enable returns false when it succeeds.
|
|
481
|
+
rv = if iseq
|
|
428
482
|
tp.enable(target: iseq, target_line: line_no)
|
|
429
483
|
else
|
|
430
484
|
tp.enable
|
|
431
485
|
end
|
|
432
|
-
|
|
486
|
+
|
|
487
|
+
DI.instrumented_count_inc(:line)
|
|
488
|
+
|
|
489
|
+
rv
|
|
433
490
|
end
|
|
434
491
|
true
|
|
435
492
|
end
|
|
@@ -439,15 +496,17 @@ module Datadog
|
|
|
439
496
|
if tp = probe.instrumentation_trace_point
|
|
440
497
|
tp.disable
|
|
441
498
|
probe.instrumentation_trace_point = nil
|
|
499
|
+
|
|
500
|
+
DI.instrumented_count_dec(:line)
|
|
442
501
|
end
|
|
443
502
|
end
|
|
444
503
|
end
|
|
445
504
|
|
|
446
|
-
def hook(probe,
|
|
505
|
+
def hook(probe, responder)
|
|
447
506
|
if probe.method?
|
|
448
|
-
hook_method(probe,
|
|
507
|
+
hook_method(probe, responder)
|
|
449
508
|
elsif probe.line?
|
|
450
|
-
hook_line(probe,
|
|
509
|
+
hook_line(probe, responder)
|
|
451
510
|
else
|
|
452
511
|
# TODO add test coverage for this path
|
|
453
512
|
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
|