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
@@ -34,19 +34,17 @@ module Datadog
|
|
34
34
|
end
|
35
35
|
|
36
36
|
def post(env)
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
http.request(post)
|
43
|
-
end
|
44
|
-
|
45
|
-
Response.new(http_response)
|
46
|
-
rescue StandardError => e
|
47
|
-
Datadog.logger.debug("Unable to send telemetry event to agent: #{e}")
|
48
|
-
Telemetry::Http::InternalErrorResponse.new(e)
|
37
|
+
post = ::Net::HTTP::Post.new(env.path, env.headers)
|
38
|
+
post.body = env.body
|
39
|
+
|
40
|
+
http_response = open do |http|
|
41
|
+
http.request(post)
|
49
42
|
end
|
43
|
+
|
44
|
+
Response.new(http_response)
|
45
|
+
rescue StandardError => e
|
46
|
+
Datadog.logger.debug("Unable to send telemetry event to agent: #{e}")
|
47
|
+
Telemetry::Http::InternalErrorResponse.new(e)
|
50
48
|
end
|
51
49
|
|
52
50
|
# Data structure for an HTTP Response
|
@@ -17,7 +17,10 @@ module Datadog
|
|
17
17
|
CONTENT_TYPE_APPLICATION_JSON = 'application/json'
|
18
18
|
API_VERSION = 'v2'
|
19
19
|
|
20
|
+
AGENTLESS_HOST_PREFIX = 'instrumentation-telemetry-intake'
|
21
|
+
|
20
22
|
AGENT_ENDPOINT = '/telemetry/proxy/api/v2/apmtelemetry'
|
23
|
+
AGENTLESS_ENDPOINT = '/api/v2/apmtelemetry'
|
21
24
|
end
|
22
25
|
end
|
23
26
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative '../../configuration/settings'
|
4
|
+
require_relative '../../environment/ext'
|
4
5
|
require_relative '../../transport/ext'
|
5
6
|
require_relative 'env'
|
6
7
|
require_relative 'ext'
|
@@ -13,18 +14,42 @@ module Datadog
|
|
13
14
|
# Class to send telemetry data to Telemetry API
|
14
15
|
# Currently only supports the HTTP protocol.
|
15
16
|
class Transport
|
17
|
+
def self.build_agent_transport(agent_settings)
|
18
|
+
Transport.new(
|
19
|
+
host: agent_settings.hostname,
|
20
|
+
port: agent_settings.port,
|
21
|
+
path: Http::Ext::AGENT_ENDPOINT
|
22
|
+
)
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.build_agentless_transport(api_key:, dd_site:, url_override: nil)
|
26
|
+
url = url_override || "https://#{Http::Ext::AGENTLESS_HOST_PREFIX}.#{dd_site}:443"
|
27
|
+
|
28
|
+
uri = URI.parse(url)
|
29
|
+
raise "Invalid agentless mode URL: #{url}" if uri.host.nil?
|
30
|
+
|
31
|
+
Transport.new(
|
32
|
+
host: uri.host,
|
33
|
+
port: uri.port || 80,
|
34
|
+
path: Http::Ext::AGENTLESS_ENDPOINT,
|
35
|
+
ssl: uri.scheme == 'https' || uri.port == 443,
|
36
|
+
api_key: api_key
|
37
|
+
)
|
38
|
+
end
|
39
|
+
|
16
40
|
attr_reader \
|
17
41
|
:host,
|
18
42
|
:port,
|
19
43
|
:ssl,
|
20
|
-
:path
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
@host =
|
25
|
-
@port =
|
26
|
-
@ssl =
|
27
|
-
@path =
|
44
|
+
:path,
|
45
|
+
:api_key
|
46
|
+
|
47
|
+
def initialize(host:, port:, path:, ssl: false, api_key: nil)
|
48
|
+
@host = host
|
49
|
+
@port = port
|
50
|
+
@ssl = ssl
|
51
|
+
@path = path
|
52
|
+
@api_key = api_key
|
28
53
|
end
|
29
54
|
|
30
55
|
def request(request_type:, payload:)
|
@@ -38,7 +63,7 @@ module Datadog
|
|
38
63
|
private
|
39
64
|
|
40
65
|
def headers(request_type:, api_version: Http::Ext::API_VERSION)
|
41
|
-
{
|
66
|
+
result = {
|
42
67
|
Core::Transport::Ext::HTTP::HEADER_DD_INTERNAL_UNTRACED_REQUEST => '1',
|
43
68
|
Ext::HEADER_CONTENT_TYPE => Http::Ext::CONTENT_TYPE_APPLICATION_JSON,
|
44
69
|
Ext::HEADER_DD_TELEMETRY_API_VERSION => api_version,
|
@@ -49,6 +74,10 @@ module Datadog
|
|
49
74
|
# Enable debug mode for telemetry
|
50
75
|
# HEADER_TELEMETRY_DEBUG_ENABLED => 'true',
|
51
76
|
}
|
77
|
+
|
78
|
+
result[Ext::HEADER_DD_API_KEY] = api_key unless api_key.nil?
|
79
|
+
|
80
|
+
result
|
52
81
|
end
|
53
82
|
|
54
83
|
def adapter
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Datadog
|
4
|
+
module Core
|
5
|
+
module Telemetry
|
6
|
+
# === INTERNAL USAGE ONLY ===
|
7
|
+
#
|
8
|
+
# Report telemetry logs via delegating to the telemetry component instance via mutex.
|
9
|
+
#
|
10
|
+
# IMPORTANT: Invoking this method during the lifecycle of component initialization will
|
11
|
+
# be no-op instead.
|
12
|
+
#
|
13
|
+
# For developer using this module:
|
14
|
+
# read: lib/datadog/core/telemetry/logging.rb
|
15
|
+
module Logger
|
16
|
+
class << self
|
17
|
+
def report(exception, level: :error, description: nil)
|
18
|
+
instance&.report(exception, level: level, description: description)
|
19
|
+
end
|
20
|
+
|
21
|
+
def error(description)
|
22
|
+
instance&.error(description)
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def instance
|
28
|
+
# Component initialization uses a mutex to avoid having concurrent initialization.
|
29
|
+
# Trying to access the telemetry component during initialization (specifically:
|
30
|
+
# from the thread that's actually doing the initialization) would cause a deadlock,
|
31
|
+
# since accessing the components would try to recursively lock the mutex.
|
32
|
+
#
|
33
|
+
# To work around this, we use allow_initialization: false to avoid triggering this issue.
|
34
|
+
#
|
35
|
+
# The downside is: this leaves us unable to report telemetry during component initialization.
|
36
|
+
components = Datadog.send(:components, allow_initialization: false)
|
37
|
+
|
38
|
+
if components && components.telemetry
|
39
|
+
components.telemetry
|
40
|
+
else
|
41
|
+
Datadog.logger.warn(
|
42
|
+
'Failed to send telemetry before components initialization or within components lifecycle'
|
43
|
+
)
|
44
|
+
nil
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'event'
|
4
|
+
|
5
|
+
require 'pathname'
|
6
|
+
|
7
|
+
module Datadog
|
8
|
+
module Core
|
9
|
+
module Telemetry
|
10
|
+
# === INTERNAL USAGE ONLY ===
|
11
|
+
#
|
12
|
+
# Logging interface for sending telemetry logs... so we can fix them.
|
13
|
+
#
|
14
|
+
# For developer using this module:
|
15
|
+
# - MUST NOT provide any sensitive information (PII)
|
16
|
+
# - SHOULD reduce the data cardinality for batching/aggregation
|
17
|
+
#
|
18
|
+
# Before using it, ask yourself:
|
19
|
+
# - Do we need to know about this (ie. internal error or client error)?
|
20
|
+
# - How severe/critical is this error? (ie. error, warning, fatal)
|
21
|
+
# - What information needed to make it actionable?
|
22
|
+
#
|
23
|
+
module Logging
|
24
|
+
# Extract datadog stack trace from the exception
|
25
|
+
module DatadogStackTrace
|
26
|
+
GEM_ROOT = Pathname.new("#{__dir__}/../../../..").cleanpath.to_s
|
27
|
+
|
28
|
+
def self.from(exception)
|
29
|
+
backtrace = exception.backtrace
|
30
|
+
|
31
|
+
return unless backtrace
|
32
|
+
return if backtrace.empty?
|
33
|
+
|
34
|
+
stack_trace = +''
|
35
|
+
backtrace.each do |line|
|
36
|
+
stack_trace << if line.start_with?(GEM_ROOT)
|
37
|
+
line[GEM_ROOT.length..-1] || ''
|
38
|
+
else
|
39
|
+
'REDACTED'
|
40
|
+
end
|
41
|
+
stack_trace << ','
|
42
|
+
end
|
43
|
+
|
44
|
+
stack_trace.chomp(',')
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def report(exception, level: :error, description: nil)
|
49
|
+
# Annoymous exceptions to be logged as <Class:0x00007f8b1c0b3b40>
|
50
|
+
message = +''
|
51
|
+
message << (exception.class.name || exception.class.inspect)
|
52
|
+
message << ':' << description if description
|
53
|
+
|
54
|
+
event = Event::Log.new(
|
55
|
+
message: message,
|
56
|
+
level: level,
|
57
|
+
stack_trace: DatadogStackTrace.from(exception)
|
58
|
+
)
|
59
|
+
|
60
|
+
log!(event)
|
61
|
+
end
|
62
|
+
|
63
|
+
def error(description)
|
64
|
+
event = Event::Log.new(message: description, level: :error)
|
65
|
+
|
66
|
+
log!(event)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -31,6 +31,18 @@ module Datadog
|
|
31
31
|
|
32
32
|
def application
|
33
33
|
config = Datadog.configuration
|
34
|
+
|
35
|
+
tracer_version = Core::Environment::Identity.gem_datadog_version_semver2
|
36
|
+
|
37
|
+
# We need some to distinguish datadog-ci gem versions
|
38
|
+
# when examining telemetry metrics emitted from the datadog-ci gem.
|
39
|
+
#
|
40
|
+
# This code checks that Datadog::CI is loaded and ci mode is enabled and adds
|
41
|
+
# "-ci-X.Y.Z" suffix to the tracer version.
|
42
|
+
if defined?(::Datadog::CI::VERSION) && config.respond_to?(:ci) && config.ci.enabled
|
43
|
+
tracer_version = "#{tracer_version}-ci-#{::Datadog::CI::VERSION::STRING}"
|
44
|
+
end
|
45
|
+
|
34
46
|
{
|
35
47
|
env: config.env,
|
36
48
|
language_name: Core::Environment::Ext::LANG,
|
@@ -39,7 +51,7 @@ module Datadog
|
|
39
51
|
runtime_version: Core::Environment::Ext::ENGINE_VERSION,
|
40
52
|
service_name: config.service,
|
41
53
|
service_version: config.version,
|
42
|
-
tracer_version:
|
54
|
+
tracer_version: tracer_version
|
43
55
|
}
|
44
56
|
end
|
45
57
|
|
@@ -0,0 +1,102 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Datadog
|
4
|
+
module Core
|
5
|
+
module Utils
|
6
|
+
# Monkey patches `Kernel#fork` and similar functions, adding an `at_fork` callback mechanism which
|
7
|
+
# is used to restart observability after the VM forks (e.g. in multiprocess Ruby apps).
|
8
|
+
module AtForkMonkeyPatch
|
9
|
+
AT_FORK_CHILD_BLOCKS = [] # rubocop:disable Style/MutableConstant Used to store blocks to run, mutable by design.
|
10
|
+
private_constant :AT_FORK_CHILD_BLOCKS
|
11
|
+
|
12
|
+
def self.supported?
|
13
|
+
Process.respond_to?(:fork)
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.apply!
|
17
|
+
return false unless supported?
|
18
|
+
|
19
|
+
if RUBY_VERSION < '3.1'
|
20
|
+
[
|
21
|
+
::Process.singleton_class, # Process.fork
|
22
|
+
::Kernel.singleton_class, # Kernel.fork
|
23
|
+
::Object, # fork without explicit receiver (it's defined as a method in ::Kernel)
|
24
|
+
# Note: Modifying Object as we do here is irreversible. During tests, this
|
25
|
+
# change will stick around even if we otherwise stub `Process` and `Kernel`
|
26
|
+
].each { |target| target.prepend(KernelMonkeyPatch) }
|
27
|
+
end
|
28
|
+
|
29
|
+
::Process.singleton_class.prepend(ProcessMonkeyPatch)
|
30
|
+
|
31
|
+
true
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.run_at_fork_blocks(stage)
|
35
|
+
raise(ArgumentError, "Unsupported stage #{stage}") unless stage == :child
|
36
|
+
|
37
|
+
AT_FORK_CHILD_BLOCKS.each(&:call)
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.at_fork(stage, &block)
|
41
|
+
raise(ArgumentError, "Unsupported stage #{stage}") unless stage == :child
|
42
|
+
raise(ArgumentError, 'Missing block argument') unless block
|
43
|
+
|
44
|
+
AT_FORK_CHILD_BLOCKS << block
|
45
|
+
|
46
|
+
true
|
47
|
+
end
|
48
|
+
|
49
|
+
# Adds `at_fork` behavior; see parent module for details.
|
50
|
+
module KernelMonkeyPatch
|
51
|
+
def fork
|
52
|
+
# If a block is provided, it must be wrapped to trigger callbacks.
|
53
|
+
child_block = if block_given?
|
54
|
+
proc do
|
55
|
+
AtForkMonkeyPatch.run_at_fork_blocks(:child)
|
56
|
+
|
57
|
+
# Invoke original block
|
58
|
+
yield
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Start fork
|
63
|
+
# If a block is provided, use the wrapped version.
|
64
|
+
result = child_block.nil? ? super : super(&child_block)
|
65
|
+
|
66
|
+
# When fork gets called without a block, it returns twice:
|
67
|
+
# If we're in the fork, result = nil: trigger child callbacks.
|
68
|
+
# If we're in the parent, result = pid: we do nothing.
|
69
|
+
# (If it gets called with a block, it only returns on the parent)
|
70
|
+
AtForkMonkeyPatch.run_at_fork_blocks(:child) if result.nil?
|
71
|
+
|
72
|
+
result
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# Adds `at_fork` behavior; see parent module for details.
|
77
|
+
module ProcessMonkeyPatch
|
78
|
+
# Hook provided by Ruby 3.1+ for observability libraries that want to know about fork, see
|
79
|
+
# https://github.com/ruby/ruby/pull/5017 and https://bugs.ruby-lang.org/issues/17795
|
80
|
+
def _fork
|
81
|
+
pid = super
|
82
|
+
|
83
|
+
AtForkMonkeyPatch.run_at_fork_blocks(:child) if pid == 0
|
84
|
+
|
85
|
+
pid
|
86
|
+
end
|
87
|
+
|
88
|
+
# A call to Process.daemon ( https://rubyapi.org/3.1/o/process#method-c-daemon ) forks the current process and
|
89
|
+
# keeps executing code in the child process, killing off the parent, thus effectively replacing it.
|
90
|
+
# This is not covered by `_fork` and thus we have some extra code for it.
|
91
|
+
def daemon(*args)
|
92
|
+
result = super
|
93
|
+
|
94
|
+
AtForkMonkeyPatch.run_at_fork_blocks(:child)
|
95
|
+
|
96
|
+
result
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -34,6 +34,18 @@ module Datadog
|
|
34
34
|
define_singleton_method(:now, &block)
|
35
35
|
end
|
36
36
|
|
37
|
+
# Overrides the implementation of `#get_time
|
38
|
+
# with the provided callable.
|
39
|
+
#
|
40
|
+
# Overriding the method `#get_time` instead of
|
41
|
+
# indirectly calling `block` removes
|
42
|
+
# one level of method call overhead.
|
43
|
+
#
|
44
|
+
# @param block [Proc] block that accepts unit and returns timestamp in the requested unit
|
45
|
+
def get_time_provider=(block)
|
46
|
+
define_singleton_method(:get_time, &block)
|
47
|
+
end
|
48
|
+
|
37
49
|
def measure(unit = :float_second)
|
38
50
|
before = get_time(unit)
|
39
51
|
yield
|
@@ -0,0 +1,168 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Datadog
|
4
|
+
module DI
|
5
|
+
# Tracks loaded Ruby code by source file and maintains a map from
|
6
|
+
# source file to the loaded code (instruction sequences).
|
7
|
+
# Also arranges for code in the loaded files to be instrumented by
|
8
|
+
# line probes that have already been received by the library.
|
9
|
+
#
|
10
|
+
# The loaded code is used to target line trace points when installing
|
11
|
+
# line probes which dramatically improves efficiency of line trace points.
|
12
|
+
#
|
13
|
+
# Note that, since most files will only be loaded one time (via the
|
14
|
+
# "require" mechanism), the code tracker needs to be global and not be
|
15
|
+
# recreated when the DI component is created.
|
16
|
+
#
|
17
|
+
# @api private
|
18
|
+
class CodeTracker
|
19
|
+
def initialize
|
20
|
+
@registry = {}
|
21
|
+
@trace_point_lock = Mutex.new
|
22
|
+
@registry_lock = Mutex.new
|
23
|
+
@compiled_trace_point = nil
|
24
|
+
end
|
25
|
+
|
26
|
+
# Starts tracking loaded code.
|
27
|
+
#
|
28
|
+
# This method should generally be called early in application boot
|
29
|
+
# process, because any code loaded before code tracking is enabled
|
30
|
+
# will not be instrumentable via line probes.
|
31
|
+
#
|
32
|
+
# Normally tracking should remain active for the lifetime of the
|
33
|
+
# process and would not be ever stopped.
|
34
|
+
def start
|
35
|
+
trace_point_lock.synchronize do
|
36
|
+
# If this code tracker is already running, we can do nothing or
|
37
|
+
# restart it (by disabling the trace point and recreating it).
|
38
|
+
# It is likely that some applications will attempt to activate
|
39
|
+
# DI more than once where the intention is to just activate DI;
|
40
|
+
# do not break such applications by clearing out the registry.
|
41
|
+
# For now, until there is a use case for recreating the trace point,
|
42
|
+
# do nothing if the code tracker has already started.
|
43
|
+
return if @compiled_trace_point
|
44
|
+
|
45
|
+
# Note: .trace enables the trace point.
|
46
|
+
@compiled_trace_point = TracePoint.trace(:script_compiled) do |tp|
|
47
|
+
# Useful attributes of the trace point object here:
|
48
|
+
# .instruction_sequence
|
49
|
+
# .instruction_sequence.path (either absolute file path for
|
50
|
+
# loaded or required code, or for eval'd code, if filename
|
51
|
+
# is specified as argument to eval, then this is the provided
|
52
|
+
# filename, otherwise this is a synthesized
|
53
|
+
# "(eval at <definition-file>:<line>)" string)
|
54
|
+
# .instruction_sequence.absolute_path (absolute file path when
|
55
|
+
# load or require are used to load code, nil for eval'd code
|
56
|
+
# regardless of whether filename was specified as an argument
|
57
|
+
# to eval on ruby 3.1+, same as path for eval'd code on ruby 3.0
|
58
|
+
# and lower)
|
59
|
+
# .method_id
|
60
|
+
# .path (refers to the code location that called the require/eval/etc.,
|
61
|
+
# not where the loaded code is; use .path on the instruction sequence
|
62
|
+
# to obtain the location of the compiled code)
|
63
|
+
# .eval_script
|
64
|
+
#
|
65
|
+
# For now just map the path to the instruction sequence.
|
66
|
+
path = tp.instruction_sequence.absolute_path
|
67
|
+
# Do not store mapping for eval'd code, since there is no way
|
68
|
+
# to target such code from dynamic instrumentation UI.
|
69
|
+
# eval'd code always sets tp.eval_script.
|
70
|
+
# When tp.eval_script is nil, code is either 'load'ed or 'require'd.
|
71
|
+
# steep, of course, complains about indexing with +path+
|
72
|
+
# without checking that it is not nil, so here, maybe there is
|
73
|
+
# some situation where path would in fact be nil and
|
74
|
+
# steep would end up saving the day.
|
75
|
+
if path && !tp.eval_script
|
76
|
+
registry_lock.synchronize do
|
77
|
+
registry[path] = tp.instruction_sequence
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# Returns whether this code tracker has been activated and is
|
85
|
+
# tracking.
|
86
|
+
def active?
|
87
|
+
trace_point_lock.synchronize do
|
88
|
+
!!@compiled_trace_point
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# Returns an array of RubVM::InstructionSequence (i.e. the compiled code)
|
93
|
+
# for the provided path.
|
94
|
+
#
|
95
|
+
# The argument can be a full path to a Ruby source code file or a
|
96
|
+
# suffix (basename + one or more directories preceding the basename).
|
97
|
+
# The idea with suffix matches is that file paths are likely to
|
98
|
+
# be different between development and production environments and
|
99
|
+
# the source control system uses relative paths and doesn't have
|
100
|
+
# absolute paths at all.
|
101
|
+
#
|
102
|
+
# Suffix matches are not guaranteed to be correct, meaning there may
|
103
|
+
# be multiple files with the same basename and they may all match a
|
104
|
+
# given suffix. In such cases, this method will return all matching
|
105
|
+
# paths (and all of these paths will be attempted to be instrumented
|
106
|
+
# by upstream code).
|
107
|
+
#
|
108
|
+
# If the suffix matches one of the paths completely (which requires it
|
109
|
+
# to be an absolute path), only the exactly matching path is returned.
|
110
|
+
# Otherwise all known paths that end in the suffix are returned.
|
111
|
+
# If no paths match, an empty array is returned.
|
112
|
+
def iseqs_for_path(suffix)
|
113
|
+
registry_lock.synchronize do
|
114
|
+
exact = registry[suffix]
|
115
|
+
return [exact] if exact
|
116
|
+
|
117
|
+
inexact = []
|
118
|
+
registry.each do |path, iseq|
|
119
|
+
# Exact match is not possible here, meaning any matching path
|
120
|
+
# has to be longer than the suffix. Require full component matches,
|
121
|
+
# meaning either the first character of the suffix is a slash
|
122
|
+
# or the previous character in the path is a slash.
|
123
|
+
# For now only check for forward slashes for Unix-like OSes;
|
124
|
+
# backslash is a legitimate character of a file name in Unix
|
125
|
+
# therefore simply permitting forward or back slash is not
|
126
|
+
# sufficient, we need to perform an OS check to know which
|
127
|
+
# path separator to use.
|
128
|
+
if path.length > suffix.length && path.end_with?(suffix)
|
129
|
+
previous_char = path[path.length - suffix.length - 1]
|
130
|
+
inexact << iseq if previous_char == "/" || suffix[0] == "/"
|
131
|
+
end
|
132
|
+
end
|
133
|
+
inexact
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
# Stops tracking code that is being loaded.
|
138
|
+
#
|
139
|
+
# This method should ordinarily never be called - if a file is loaded
|
140
|
+
# when code tracking is not active, this file will not be instrumentable
|
141
|
+
# by line probes.
|
142
|
+
#
|
143
|
+
# This method is intended for test suite use only, where multiple
|
144
|
+
# code tracker instances are created, to fully clean up the old instances.
|
145
|
+
def stop
|
146
|
+
# Permit multiple stop calls.
|
147
|
+
trace_point_lock.synchronize do
|
148
|
+
@compiled_trace_point&.disable
|
149
|
+
# Clear the instance variable so that the trace point may be
|
150
|
+
# reinstated in the future.
|
151
|
+
@compiled_trace_point = nil
|
152
|
+
end
|
153
|
+
registry_lock.synchronize do
|
154
|
+
registry.clear
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
private
|
159
|
+
|
160
|
+
# Mapping from paths of loaded files to RubyVM::InstructionSequence
|
161
|
+
# objects representing compiled code of those files.
|
162
|
+
attr_reader :registry
|
163
|
+
|
164
|
+
attr_reader :trace_point_lock
|
165
|
+
attr_reader :registry_lock
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|