datadog 2.2.0 → 2.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +51 -2
- data/ext/datadog_profiling_loader/extconf.rb +15 -15
- 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 +113 -43
- data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.c +49 -26
- 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 +49 -37
- data/ext/datadog_profiling_native_extension/collectors_stack.h +2 -2
- data/ext/datadog_profiling_native_extension/collectors_thread_context.c +81 -19
- data/ext/datadog_profiling_native_extension/collectors_thread_context.h +1 -0
- data/ext/datadog_profiling_native_extension/datadog_ruby_common.c +110 -0
- data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +57 -0
- data/ext/datadog_profiling_native_extension/extconf.rb +65 -60
- data/ext/datadog_profiling_native_extension/heap_recorder.c +34 -6
- 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 +3 -3
- 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 +64 -138
- data/ext/datadog_profiling_native_extension/private_vm_api_access.h +17 -11
- data/ext/datadog_profiling_native_extension/profiling.c +0 -2
- 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 +1 -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 +19 -6
- data/ext/libdatadog_api/datadog_ruby_common.c +110 -0
- data/ext/libdatadog_api/datadog_ruby_common.h +57 -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/contrib/graphql/appsec_trace.rb +49 -0
- data/lib/datadog/appsec/contrib/graphql/gateway/multiplex.rb +73 -0
- data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +68 -0
- data/lib/datadog/appsec/contrib/graphql/integration.rb +41 -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 +1 -1
- data/lib/datadog/appsec/processor/actions.rb +1 -1
- data/lib/datadog/appsec/response.rb +15 -1
- data/lib/datadog/appsec.rb +1 -0
- data/lib/datadog/core/configuration/components.rb +14 -12
- data/lib/datadog/core/configuration/settings.rb +54 -7
- 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/telemetry/component.rb +49 -2
- data/lib/datadog/core/telemetry/emitter.rb +9 -11
- data/lib/datadog/core/telemetry/event.rb +32 -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/logging.rb +35 -0
- data/lib/datadog/core/utils/at_fork_monkey_patch.rb +102 -0
- data/lib/datadog/kit/appsec/events.rb +2 -4
- 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 +17 -17
- data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +11 -13
- data/lib/datadog/profiling/collectors/info.rb +3 -3
- data/lib/datadog/profiling/collectors/thread_context.rb +4 -2
- data/lib/datadog/profiling/component.rb +69 -91
- 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 +8 -6
- 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 +31 -25
- 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/tracing/contrib/active_record/events/sql.rb +1 -0
- data/lib/datadog/tracing/contrib/ext.rb +14 -0
- data/lib/datadog/tracing/contrib/graphql/unified_trace.rb +1 -1
- data/lib/datadog/tracing/contrib/graphql/unified_trace_patcher.rb +4 -1
- data/lib/datadog/tracing/contrib/lograge/patcher.rb +16 -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/pg/configuration/settings.rb +5 -0
- data/lib/datadog/tracing/contrib/pg/instrumentation.rb +4 -1
- 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/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/metadata/errors.rb +9 -1
- data/lib/datadog/tracing/metadata/ext.rb +4 -0
- data/lib/datadog/tracing/pipeline/span_filter.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/transport/serializable_trace.rb +3 -0
- data/lib/datadog/version.rb +1 -1
- metadata +28 -10
- data/lib/datadog/profiling/crashtracker.rb +0 -91
- data/lib/datadog/profiling/ext/forking.rb +0 -98
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../configuration/ext'
|
4
|
+
|
5
|
+
module Datadog
|
6
|
+
module Core
|
7
|
+
module Crashtracking
|
8
|
+
# This module provides a method to resolve the base URL of the agent
|
9
|
+
module AgentBaseUrl
|
10
|
+
def self.resolve(agent_settings)
|
11
|
+
case agent_settings.adapter
|
12
|
+
when Datadog::Core::Configuration::Ext::Agent::HTTP::ADAPTER
|
13
|
+
"#{agent_settings.ssl ? 'https' : 'http'}://#{agent_settings.hostname}:#{agent_settings.port}/"
|
14
|
+
when Datadog::Core::Configuration::Ext::Agent::UnixSocket::ADAPTER
|
15
|
+
"unix://#{agent_settings.uds_path}"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'libdatadog'
|
4
|
+
|
5
|
+
require_relative 'tag_builder'
|
6
|
+
require_relative 'agent_base_url'
|
7
|
+
require_relative '../utils/only_once'
|
8
|
+
require_relative '../utils/at_fork_monkey_patch'
|
9
|
+
|
10
|
+
module Datadog
|
11
|
+
module Core
|
12
|
+
module Crashtracking
|
13
|
+
# Used to report Ruby VM crashes.
|
14
|
+
#
|
15
|
+
# NOTE: The crashtracker native state is a singleton;
|
16
|
+
# so even if you create multiple instances of `Crashtracking::Component` and start them,
|
17
|
+
# it only works as "last writer wins". Same for stop -- there's only one state, so calling stop
|
18
|
+
# on it will stop the crash tracker, regardless of which instance started it.
|
19
|
+
#
|
20
|
+
# Methods prefixed with _native_ are implemented in `crashtracker.c`
|
21
|
+
class Component
|
22
|
+
LIBDATADOG_API_FAILURE =
|
23
|
+
begin
|
24
|
+
require "libdatadog_api.#{RUBY_VERSION[/\d+.\d+/]}_#{RUBY_PLATFORM}"
|
25
|
+
nil
|
26
|
+
rescue LoadError => e
|
27
|
+
e.message
|
28
|
+
end
|
29
|
+
|
30
|
+
ONLY_ONCE = Core::Utils::OnlyOnce.new
|
31
|
+
|
32
|
+
def self.build(settings, agent_settings, logger:)
|
33
|
+
tags = TagBuilder.call(settings)
|
34
|
+
agent_base_url = AgentBaseUrl.resolve(agent_settings)
|
35
|
+
logger.warn('Missing agent base URL; cannot enable crash tracking') unless agent_base_url
|
36
|
+
|
37
|
+
ld_library_path = ::Libdatadog.ld_library_path
|
38
|
+
logger.warn('Missing ld_library_path; cannot enable crash tracking') unless ld_library_path
|
39
|
+
|
40
|
+
path_to_crashtracking_receiver_binary = ::Libdatadog.path_to_crashtracking_receiver_binary
|
41
|
+
unless path_to_crashtracking_receiver_binary
|
42
|
+
logger.warn('Missing path_to_crashtracking_receiver_binary; cannot enable crash tracking')
|
43
|
+
end
|
44
|
+
|
45
|
+
return unless agent_base_url
|
46
|
+
return unless ld_library_path
|
47
|
+
return unless path_to_crashtracking_receiver_binary
|
48
|
+
|
49
|
+
new(
|
50
|
+
tags: tags,
|
51
|
+
agent_base_url: agent_base_url,
|
52
|
+
ld_library_path: ld_library_path,
|
53
|
+
path_to_crashtracking_receiver_binary: path_to_crashtracking_receiver_binary,
|
54
|
+
logger: logger
|
55
|
+
).tap(&:start)
|
56
|
+
end
|
57
|
+
|
58
|
+
def initialize(tags:, agent_base_url:, ld_library_path:, path_to_crashtracking_receiver_binary:, logger:)
|
59
|
+
@tags = tags
|
60
|
+
@agent_base_url = agent_base_url
|
61
|
+
@ld_library_path = ld_library_path
|
62
|
+
@path_to_crashtracking_receiver_binary = path_to_crashtracking_receiver_binary
|
63
|
+
@logger = logger
|
64
|
+
end
|
65
|
+
|
66
|
+
def start
|
67
|
+
Utils::AtForkMonkeyPatch.apply!
|
68
|
+
|
69
|
+
start_or_update_on_fork(action: :start)
|
70
|
+
ONLY_ONCE.run do
|
71
|
+
Utils::AtForkMonkeyPatch.at_fork(:child) do
|
72
|
+
# Must NOT reference `self` here, as only the first instance will
|
73
|
+
# be captured by the ONLY_ONCE and we want to pick the latest active one
|
74
|
+
# (which may have different tags or agent config)
|
75
|
+
Datadog.send(:components).crashtracker&.update_on_fork
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def update_on_fork
|
81
|
+
start_or_update_on_fork(action: :update_on_fork)
|
82
|
+
end
|
83
|
+
|
84
|
+
def stop
|
85
|
+
self.class._native_stop
|
86
|
+
logger.debug('Crash tracking stopped successfully')
|
87
|
+
rescue => e
|
88
|
+
logger.error("Failed to stop crash tracking: #{e.message}")
|
89
|
+
end
|
90
|
+
|
91
|
+
private
|
92
|
+
|
93
|
+
attr_reader :tags, :agent_base_url, :ld_library_path, :path_to_crashtracking_receiver_binary, :logger
|
94
|
+
|
95
|
+
def start_or_update_on_fork(action:)
|
96
|
+
self.class._native_start_or_update_on_fork(
|
97
|
+
action: action,
|
98
|
+
exporter_configuration: [:agent, agent_base_url],
|
99
|
+
path_to_crashtracking_receiver_binary: path_to_crashtracking_receiver_binary,
|
100
|
+
ld_library_path: ld_library_path,
|
101
|
+
tags_as_array: tags.to_a,
|
102
|
+
upload_timeout_seconds: 1
|
103
|
+
)
|
104
|
+
logger.debug("Crash tracking #{action} successfully")
|
105
|
+
rescue => e
|
106
|
+
logger.error("Failed to #{action} crash tracking: #{e.message}")
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../utils'
|
4
|
+
require_relative '../environment/socket'
|
5
|
+
require_relative '../environment/identity'
|
6
|
+
require_relative '../environment/git'
|
7
|
+
|
8
|
+
module Datadog
|
9
|
+
module Core
|
10
|
+
module Crashtracking
|
11
|
+
# This module builds a hash of tags
|
12
|
+
module TagBuilder
|
13
|
+
def self.call(settings)
|
14
|
+
hash = {
|
15
|
+
'host' => Environment::Socket.hostname,
|
16
|
+
'process_id' => Process.pid.to_s,
|
17
|
+
'runtime_engine' => Environment::Identity.lang_engine,
|
18
|
+
'runtime-id' => Environment::Identity.id,
|
19
|
+
'runtime_platform' => Environment::Identity.lang_platform,
|
20
|
+
'runtime_version' => Environment::Identity.lang_version,
|
21
|
+
'env' => settings.env,
|
22
|
+
'service' => settings.service,
|
23
|
+
'version' => settings.version,
|
24
|
+
'git.repository_url' => Environment::Git.git_repository_url,
|
25
|
+
'git.commit.sha' => Environment::Git.git_commit_sha,
|
26
|
+
'is_crash' => 'true',
|
27
|
+
'language' => 'ruby',
|
28
|
+
'library_version' => Core::Environment::Identity.gem_datadog_version,
|
29
|
+
}.compact
|
30
|
+
|
31
|
+
# Make sure everything is an utf-8 string, to avoid encoding issues in downstream
|
32
|
+
settings.tags.merge(hash).each_with_object({}) do |(key, value), h|
|
33
|
+
h[Utils.utf8_encode(key)] = Utils.utf8_encode(value)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -8,11 +8,17 @@ module Datadog
|
|
8
8
|
module Core
|
9
9
|
module Diagnostics
|
10
10
|
# Base class for EnvironmentLoggers - should allow for easy reporting by users to Datadog support.
|
11
|
+
#
|
12
|
+
# The EnvironmentLogger should not pollute the logs in a development environment.
|
11
13
|
module EnvironmentLogging
|
12
14
|
def log_configuration!(prefix, data)
|
13
15
|
logger.info("DATADOG CONFIGURATION - #{prefix} - #{data}")
|
14
16
|
end
|
15
17
|
|
18
|
+
def log_debug!(prefix, data)
|
19
|
+
logger.debug("DATADOG CONFIGURATION - #{prefix} - #{data}")
|
20
|
+
end
|
21
|
+
|
16
22
|
def log_error!(prefix, type, error)
|
17
23
|
logger.warn("DATADOG ERROR - #{prefix} - #{type}: #{error}")
|
18
24
|
end
|
@@ -27,21 +33,12 @@ module Datadog
|
|
27
33
|
def log?
|
28
34
|
startup_logs_enabled = Datadog.configuration.diagnostics.startup_logs.enabled
|
29
35
|
if startup_logs_enabled.nil?
|
30
|
-
|
36
|
+
# Do not pollute the logs in a development environment.
|
37
|
+
!Datadog::Core::Environment::Execution.development?
|
31
38
|
else
|
32
39
|
startup_logs_enabled
|
33
40
|
end
|
34
41
|
end
|
35
|
-
|
36
|
-
REPL_PROGRAM_NAMES = %w[irb pry].freeze
|
37
|
-
|
38
|
-
def repl?
|
39
|
-
REPL_PROGRAM_NAMES.include?($PROGRAM_NAME)
|
40
|
-
end
|
41
|
-
|
42
|
-
def rspec?
|
43
|
-
$PROGRAM_NAME.end_with?('rspec')
|
44
|
-
end
|
45
42
|
end
|
46
43
|
|
47
44
|
# Collects and logs Core diagnostic information
|
@@ -2,8 +2,11 @@
|
|
2
2
|
|
3
3
|
require_relative 'emitter'
|
4
4
|
require_relative 'event'
|
5
|
+
require_relative 'http/transport'
|
5
6
|
require_relative 'metrics_manager'
|
6
7
|
require_relative 'worker'
|
8
|
+
|
9
|
+
require_relative '../configuration/ext'
|
7
10
|
require_relative '../utils/forking'
|
8
11
|
|
9
12
|
module Datadog
|
@@ -15,6 +18,41 @@ module Datadog
|
|
15
18
|
|
16
19
|
include Core::Utils::Forking
|
17
20
|
|
21
|
+
def self.build(settings, agent_settings, logger)
|
22
|
+
enabled = settings.telemetry.enabled
|
23
|
+
agentless_enabled = settings.telemetry.agentless_enabled
|
24
|
+
|
25
|
+
if !agentless_enabled && agent_settings.adapter != Datadog::Core::Configuration::Ext::Agent::HTTP::ADAPTER
|
26
|
+
enabled = false
|
27
|
+
logger.debug { "Telemetry disabled. Agent network adapter not supported: #{agent_settings.adapter}" }
|
28
|
+
end
|
29
|
+
|
30
|
+
if agentless_enabled && settings.api_key.nil?
|
31
|
+
enabled = false
|
32
|
+
logger.debug { 'Telemetry disabled. Agentless telemetry requires an DD_API_KEY variable to be set.' }
|
33
|
+
end
|
34
|
+
|
35
|
+
transport = if agentless_enabled
|
36
|
+
Datadog::Core::Telemetry::Http::Transport.build_agentless_transport(
|
37
|
+
api_key: settings.api_key,
|
38
|
+
dd_site: settings.site,
|
39
|
+
url_override: settings.telemetry.agentless_url_override
|
40
|
+
)
|
41
|
+
else
|
42
|
+
Datadog::Core::Telemetry::Http::Transport.build_agent_transport(agent_settings)
|
43
|
+
end
|
44
|
+
|
45
|
+
Telemetry::Component.new(
|
46
|
+
http_transport: transport,
|
47
|
+
enabled: enabled,
|
48
|
+
metrics_enabled: enabled && settings.telemetry.metrics_enabled,
|
49
|
+
heartbeat_interval_seconds: settings.telemetry.heartbeat_interval_seconds,
|
50
|
+
metrics_aggregation_interval_seconds: settings.telemetry.metrics_aggregation_interval_seconds,
|
51
|
+
dependency_collection: settings.telemetry.dependency_collection,
|
52
|
+
shutdown_timeout_seconds: settings.telemetry.shutdown_timeout_seconds,
|
53
|
+
)
|
54
|
+
end
|
55
|
+
|
18
56
|
# @param enabled [Boolean] Determines whether telemetry events should be sent to the API
|
19
57
|
# @param metrics_enabled [Boolean] Determines whether telemetry metrics should be sent to the API
|
20
58
|
# @param heartbeat_interval_seconds [Float] How frequently heartbeats will be reported, in seconds.
|
@@ -24,6 +62,8 @@ module Datadog
|
|
24
62
|
heartbeat_interval_seconds:,
|
25
63
|
metrics_aggregation_interval_seconds:,
|
26
64
|
dependency_collection:,
|
65
|
+
http_transport:,
|
66
|
+
shutdown_timeout_seconds:,
|
27
67
|
enabled: true,
|
28
68
|
metrics_enabled: true
|
29
69
|
)
|
@@ -39,9 +79,10 @@ module Datadog
|
|
39
79
|
enabled: @enabled,
|
40
80
|
heartbeat_interval_seconds: heartbeat_interval_seconds,
|
41
81
|
metrics_aggregation_interval_seconds: metrics_aggregation_interval_seconds,
|
42
|
-
emitter: Emitter.new,
|
82
|
+
emitter: Emitter.new(http_transport: http_transport),
|
43
83
|
metrics_manager: @metrics_manager,
|
44
|
-
dependency_collection: dependency_collection
|
84
|
+
dependency_collection: dependency_collection,
|
85
|
+
shutdown_timeout: shutdown_timeout_seconds
|
45
86
|
)
|
46
87
|
@worker.start
|
47
88
|
end
|
@@ -70,6 +111,12 @@ module Datadog
|
|
70
111
|
@worker.enqueue(Event::AppIntegrationsChange.new)
|
71
112
|
end
|
72
113
|
|
114
|
+
def log!(event)
|
115
|
+
return unless @enabled || forked?
|
116
|
+
|
117
|
+
@worker.enqueue(event)
|
118
|
+
end
|
119
|
+
|
73
120
|
# Report configuration changes caused by Remote Configuration.
|
74
121
|
def client_configuration_change!(changes)
|
75
122
|
return if !@enabled || forked?
|
@@ -16,22 +16,20 @@ module Datadog
|
|
16
16
|
|
17
17
|
# @param http_transport [Datadog::Core::Telemetry::Http::Transport] Transport object that can be used to send
|
18
18
|
# telemetry requests via the agent
|
19
|
-
def initialize(http_transport:
|
19
|
+
def initialize(http_transport:)
|
20
20
|
@http_transport = http_transport
|
21
21
|
end
|
22
22
|
|
23
23
|
# Retrieves and emits a TelemetryRequest object based on the request type specified
|
24
24
|
def request(event)
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
rescue
|
32
|
-
|
33
|
-
Telemetry::Http::InternalErrorResponse.new(e)
|
34
|
-
end
|
25
|
+
seq_id = self.class.sequence.next
|
26
|
+
payload = Request.build_payload(event, seq_id)
|
27
|
+
res = @http_transport.request(request_type: event.type, payload: payload.to_json)
|
28
|
+
Datadog.logger.debug { "Telemetry sent for event `#{event.type}` (code: #{res.code.inspect})" }
|
29
|
+
res
|
30
|
+
rescue => e
|
31
|
+
Datadog.logger.debug("Unable to send telemetry request for event `#{event.type rescue 'unknown'}`: #{e}")
|
32
|
+
Telemetry::Http::InternalErrorResponse.new(e)
|
35
33
|
end
|
36
34
|
|
37
35
|
# Initializes a Sequence object to track seq_id if not already initialized; else returns stored
|
@@ -18,7 +18,9 @@ module Datadog
|
|
18
18
|
# The type of the event.
|
19
19
|
# It must be one of the stings defined in the Telemetry V2
|
20
20
|
# specification for event names.
|
21
|
-
def type
|
21
|
+
def type
|
22
|
+
raise NotImplementedError, 'Must be implemented by subclass'
|
23
|
+
end
|
22
24
|
|
23
25
|
# The JSON payload for the event.
|
24
26
|
def payload
|
@@ -332,6 +334,35 @@ module Datadog
|
|
332
334
|
end
|
333
335
|
end
|
334
336
|
|
337
|
+
# Telemetry class for the 'logs' event
|
338
|
+
class Log < Base
|
339
|
+
LEVELS = {
|
340
|
+
error: 'ERROR',
|
341
|
+
debug: 'DEBUG',
|
342
|
+
warn: 'WARN',
|
343
|
+
}.freeze
|
344
|
+
|
345
|
+
def type
|
346
|
+
'logs'
|
347
|
+
end
|
348
|
+
|
349
|
+
def initialize(message:, level:)
|
350
|
+
super()
|
351
|
+
@message = message
|
352
|
+
@level = LEVELS.fetch(level) { |k| raise ArgumentError, "Invalid log level :#{k}" }
|
353
|
+
end
|
354
|
+
|
355
|
+
def payload
|
356
|
+
{
|
357
|
+
logs: [{
|
358
|
+
message: @message,
|
359
|
+
level: @level,
|
360
|
+
# More optional fields to be added here...
|
361
|
+
}]
|
362
|
+
}
|
363
|
+
end
|
364
|
+
end
|
365
|
+
|
335
366
|
# Telemetry class for the 'distributions' event
|
336
367
|
class Distributions < GenerateMetrics
|
337
368
|
def type
|
@@ -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,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'event'
|
4
|
+
|
5
|
+
module Datadog
|
6
|
+
module Core
|
7
|
+
module Telemetry
|
8
|
+
# Logging interface for sending telemetry logs.
|
9
|
+
#
|
10
|
+
# Reporting internal error so that we can fix them.
|
11
|
+
# IMPORTANT: Make sure to not log any sensitive information.
|
12
|
+
module Logging
|
13
|
+
module_function
|
14
|
+
|
15
|
+
def report(exception, level:)
|
16
|
+
# Annoymous exceptions to be logged as <Class:0x00007f8b1c0b3b40>
|
17
|
+
message = exception.class.name || exception.class.inspect
|
18
|
+
|
19
|
+
event = Event::Log.new(
|
20
|
+
message: message,
|
21
|
+
level: level
|
22
|
+
)
|
23
|
+
|
24
|
+
if (telemetry = Datadog.send(:components).telemetry)
|
25
|
+
telemetry.log!(event)
|
26
|
+
else
|
27
|
+
Datadog.logger.debug do
|
28
|
+
"Attempting to send telemetry log when telemetry component is not ready: #{message}"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -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
|
@@ -53,13 +53,11 @@ module Datadog
|
|
53
53
|
# @param user_exists [bool] Whether the user id that did a login attempt exists.
|
54
54
|
# @param others [Hash<String || Symbol, String>] Additional free-form
|
55
55
|
# event information to attach to the trace.
|
56
|
-
def track_login_failure(trace = nil, span = nil,
|
56
|
+
def track_login_failure(trace = nil, span = nil, user_exists:, user_id: nil, **others)
|
57
57
|
set_trace_and_span_context('track_login_failure', trace, span) do |active_trace, active_span|
|
58
|
-
raise ArgumentError, 'user_id cannot be nil' if user_id.nil?
|
59
|
-
|
60
58
|
track(LOGIN_FAILURE_EVENT, active_trace, active_span, **others)
|
61
59
|
|
62
|
-
active_span.set_tag('appsec.events.users.login.failure.usr.id', user_id)
|
60
|
+
active_span.set_tag('appsec.events.users.login.failure.usr.id', user_id) if user_id
|
63
61
|
active_span.set_tag('appsec.events.users.login.failure.usr.exists', user_exists)
|
64
62
|
end
|
65
63
|
end
|