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
@@ -1,11 +1,16 @@
|
|
1
1
|
# rubocop:disable Style/StderrPuts
|
2
2
|
# rubocop:disable Style/GlobalVars
|
3
3
|
|
4
|
-
require_relative
|
4
|
+
require_relative "native_extension_helpers"
|
5
|
+
require_relative "../libdatadog_extconf_helpers"
|
5
6
|
|
6
7
|
SKIPPED_REASON_FILE = "#{__dir__}/skipped_reason.txt".freeze
|
7
8
|
# Not a problem if the file doesn't exist or we can't delete it
|
8
|
-
|
9
|
+
begin
|
10
|
+
File.delete(SKIPPED_REASON_FILE)
|
11
|
+
rescue
|
12
|
+
nil
|
13
|
+
end
|
9
14
|
|
10
15
|
def skip_building_extension!(reason)
|
11
16
|
fail_install_if_missing_extension =
|
@@ -24,13 +29,13 @@ def skip_building_extension!(reason)
|
|
24
29
|
)
|
25
30
|
|
26
31
|
if fail_install_if_missing_extension
|
27
|
-
require
|
32
|
+
require "mkmf"
|
28
33
|
Logging.message(
|
29
|
-
|
34
|
+
"[datadog] Failure cause: " \
|
30
35
|
"#{Datadog::Profiling::NativeExtensionHelpers::Supported.render_skipped_reason_file(**reason)}\n"
|
31
36
|
)
|
32
37
|
else
|
33
|
-
File.write(
|
38
|
+
File.write("Makefile", "all install clean: # dummy makefile that does nothing")
|
34
39
|
end
|
35
40
|
|
36
41
|
exit
|
@@ -63,17 +68,17 @@ $stderr.puts(
|
|
63
68
|
|
64
69
|
# NOTE: we MUST NOT require 'mkmf' before we check the #skip_building_extension? because the require triggers checks
|
65
70
|
# that may fail on an environment not properly setup for building Ruby extensions.
|
66
|
-
require
|
71
|
+
require "mkmf"
|
67
72
|
|
68
73
|
Logging.message("[datadog] Using compiler:\n")
|
69
|
-
xsystem("#{CONFIG[
|
74
|
+
xsystem("#{CONFIG["CC"]} -v")
|
70
75
|
Logging.message("[datadog] End of compiler information\n")
|
71
76
|
|
72
77
|
# mkmf on modern Rubies actually has an append_cflags that does something similar
|
73
78
|
# (see https://github.com/ruby/ruby/pull/5760), but as usual we need a bit more boilerplate to deal with legacy Rubies
|
74
79
|
def add_compiler_flag(flag)
|
75
80
|
if try_cflags(flag)
|
76
|
-
$CFLAGS <<
|
81
|
+
$CFLAGS << " " << flag
|
77
82
|
else
|
78
83
|
$stderr.puts("WARNING: '#{flag}' not accepted by compiler, skipping it")
|
79
84
|
end
|
@@ -81,23 +86,23 @@ end
|
|
81
86
|
|
82
87
|
# Because we can't control what compiler versions our customers use, shipping with -Werror by default is a no-go.
|
83
88
|
# But we can enable it in CI, so that we quickly spot any new warnings that just got introduced.
|
84
|
-
add_compiler_flag
|
89
|
+
add_compiler_flag "-Werror" if ENV["DATADOG_GEM_CI"] == "true"
|
85
90
|
|
86
91
|
# Older gcc releases may not default to C99 and we need to ask for this. This is also used:
|
87
92
|
# * by upstream Ruby -- search for gnu99 in the codebase
|
88
93
|
# * by msgpack, another datadog gem dependency
|
89
94
|
# (https://github.com/msgpack/msgpack-ruby/blob/18ce08f6d612fe973843c366ac9a0b74c4e50599/ext/msgpack/extconf.rb#L8)
|
90
|
-
add_compiler_flag
|
95
|
+
add_compiler_flag "-std=gnu99"
|
91
96
|
|
92
97
|
# Gets really noisy when we include the MJIT header, let's omit it (TODO: Use #pragma GCC diagnostic instead?)
|
93
|
-
add_compiler_flag
|
98
|
+
add_compiler_flag "-Wno-unused-function"
|
94
99
|
|
95
100
|
# Allow defining variables at any point in a function
|
96
|
-
add_compiler_flag
|
101
|
+
add_compiler_flag "-Wno-declaration-after-statement"
|
97
102
|
|
98
103
|
# If we forget to include a Ruby header, the function call may still appear to work, but then
|
99
104
|
# cause a segfault later. Let's ensure that never happens.
|
100
|
-
add_compiler_flag
|
105
|
+
add_compiler_flag "-Werror-implicit-function-declaration"
|
101
106
|
|
102
107
|
# The native extension is not intended to expose any symbols/functions for other native libraries to use;
|
103
108
|
# the sole exception being `Init_datadog_profiling_native_extension` which needs to be visible for Ruby to call it when
|
@@ -105,22 +110,22 @@ add_compiler_flag '-Werror-implicit-function-declaration'
|
|
105
110
|
#
|
106
111
|
# By setting this compiler flag, we tell it to assume that everything is private unless explicitly stated.
|
107
112
|
# For more details see https://gcc.gnu.org/wiki/Visibility
|
108
|
-
add_compiler_flag
|
113
|
+
add_compiler_flag "-fvisibility=hidden"
|
109
114
|
|
110
115
|
# Avoid legacy C definitions
|
111
|
-
add_compiler_flag
|
116
|
+
add_compiler_flag "-Wold-style-definition"
|
112
117
|
|
113
118
|
# Enable all other compiler warnings
|
114
|
-
add_compiler_flag
|
115
|
-
add_compiler_flag
|
119
|
+
add_compiler_flag "-Wall"
|
120
|
+
add_compiler_flag "-Wextra"
|
116
121
|
|
117
|
-
if ENV[
|
118
|
-
$defs <<
|
119
|
-
CONFIG[
|
120
|
-
CONFIG[
|
122
|
+
if ENV["DDTRACE_DEBUG"] == "true"
|
123
|
+
$defs << "-DDD_DEBUG"
|
124
|
+
CONFIG["optflags"] = "-O0"
|
125
|
+
CONFIG["debugflags"] = "-ggdb3"
|
121
126
|
end
|
122
127
|
|
123
|
-
if RUBY_PLATFORM.include?(
|
128
|
+
if RUBY_PLATFORM.include?("linux")
|
124
129
|
# Supposedly, the correct way to do this is
|
125
130
|
# ```
|
126
131
|
# have_library 'pthread'
|
@@ -128,77 +133,77 @@ if RUBY_PLATFORM.include?('linux')
|
|
128
133
|
# ```
|
129
134
|
# but it's slower to build
|
130
135
|
# so instead we just assume that we have the function we need on Linux, and nowhere else
|
131
|
-
$defs <<
|
136
|
+
$defs << "-DHAVE_PTHREAD_GETCPUCLOCKID"
|
137
|
+
|
138
|
+
# Not available on macOS
|
139
|
+
$defs << "-DHAVE_CLOCK_MONOTONIC_COARSE"
|
132
140
|
end
|
133
141
|
|
134
|
-
have_func
|
142
|
+
have_func "malloc_stats"
|
135
143
|
|
136
144
|
# On older Rubies, rb_postponed_job_preregister/rb_postponed_job_trigger did not exist
|
137
|
-
$defs <<
|
145
|
+
$defs << "-DNO_POSTPONED_TRIGGER" if RUBY_VERSION < "3.3"
|
138
146
|
|
139
147
|
# On older Rubies, M:N threads were not available
|
140
|
-
$defs <<
|
148
|
+
$defs << "-DNO_MN_THREADS_AVAILABLE" if RUBY_VERSION < "3.3"
|
141
149
|
|
142
150
|
# On older Rubies, we did not need to include the ractor header (this was built into the MJIT header)
|
143
|
-
$defs <<
|
151
|
+
$defs << "-DNO_RACTOR_HEADER_INCLUDE" if RUBY_VERSION < "3.3"
|
144
152
|
|
145
153
|
# On older Rubies, some of the Ractor internal APIs were directly accessible
|
146
|
-
$defs <<
|
154
|
+
$defs << "-DUSE_RACTOR_INTERNAL_APIS_DIRECTLY" if RUBY_VERSION < "3.3"
|
147
155
|
|
148
156
|
# On older Rubies, there was no struct rb_native_thread. See private_vm_api_acccess.c for details.
|
149
|
-
$defs <<
|
157
|
+
$defs << "-DNO_RB_NATIVE_THREAD" if RUBY_VERSION < "3.2"
|
150
158
|
|
151
159
|
# On older Rubies, there was no struct rb_thread_sched (it was struct rb_global_vm_lock_struct)
|
152
|
-
$defs <<
|
160
|
+
$defs << "-DNO_RB_THREAD_SCHED" if RUBY_VERSION < "3.2"
|
153
161
|
|
154
162
|
# On older Rubies, the first_lineno inside a location was a VALUE and not a int (https://github.com/ruby/ruby/pull/6430)
|
155
|
-
$defs <<
|
163
|
+
$defs << "-DNO_INT_FIRST_LINENO" if RUBY_VERSION < "3.2"
|
156
164
|
|
157
165
|
# On older Rubies, "pop" was not a primitive operation
|
158
|
-
$defs <<
|
166
|
+
$defs << "-DNO_PRIMITIVE_POP" if RUBY_VERSION < "3.2"
|
159
167
|
|
160
168
|
# On older Rubies, there was no tid member in the internal thread structure
|
161
|
-
$defs <<
|
169
|
+
$defs << "-DNO_THREAD_TID" if RUBY_VERSION < "3.1"
|
162
170
|
|
163
171
|
# On older Rubies, there was no jit_return member on the rb_control_frame_t struct
|
164
|
-
$defs <<
|
172
|
+
$defs << "-DNO_JIT_RETURN" if RUBY_VERSION < "3.1"
|
165
173
|
|
166
174
|
# On older Rubies, rb_gc_force_recycle allowed to free objects in a way that
|
167
175
|
# would be invisible to free tracepoints, finalizers and without cleaning
|
168
176
|
# obj_to_id_tbl mappings.
|
169
|
-
$defs <<
|
170
|
-
|
171
|
-
# On older Rubies, we need to use a backported version of this function. See private_vm_api_access.h for details.
|
172
|
-
$defs << '-DUSE_BACKPORTED_RB_PROFILE_FRAME_METHOD_NAME' if RUBY_VERSION < '3'
|
177
|
+
$defs << "-DHAVE_WORKING_RB_GC_FORCE_RECYCLE" if RUBY_VERSION < "3.1"
|
173
178
|
|
174
179
|
# On older Rubies, there are no Ractors
|
175
|
-
$defs <<
|
180
|
+
$defs << "-DNO_RACTORS" if RUBY_VERSION < "3"
|
176
181
|
|
177
182
|
# On older Rubies, rb_imemo_name did not exist
|
178
|
-
$defs <<
|
183
|
+
$defs << "-DNO_IMEMO_NAME" if RUBY_VERSION < "3"
|
179
184
|
|
180
185
|
# On older Rubies, objects would not move
|
181
|
-
$defs <<
|
186
|
+
$defs << "-DNO_T_MOVED" if RUBY_VERSION < "2.7"
|
182
187
|
|
183
188
|
# On older Rubies, there was no RUBY_SEEN_OBJ_ID flag
|
184
|
-
$defs <<
|
189
|
+
$defs << "-DNO_SEEN_OBJ_ID_FLAG" if RUBY_VERSION < "2.7"
|
185
190
|
|
186
191
|
# On older Rubies, rb_global_vm_lock_struct did not include the owner field
|
187
|
-
$defs <<
|
192
|
+
$defs << "-DNO_GVL_OWNER" if RUBY_VERSION < "2.6"
|
188
193
|
|
189
194
|
# On older Rubies, there was no thread->invoke_arg
|
190
|
-
$defs <<
|
195
|
+
$defs << "-DNO_THREAD_INVOKE_ARG" if RUBY_VERSION < "2.6"
|
191
196
|
|
192
197
|
# If we got here, libdatadog is available and loaded
|
193
|
-
ENV[
|
194
|
-
Logging.message("[datadog] PKG_CONFIG_PATH set to #{ENV[
|
198
|
+
ENV["PKG_CONFIG_PATH"] = "#{ENV["PKG_CONFIG_PATH"]}:#{Libdatadog.pkgconfig_folder}"
|
199
|
+
Logging.message("[datadog] PKG_CONFIG_PATH set to #{ENV["PKG_CONFIG_PATH"].inspect}\n")
|
195
200
|
$stderr.puts("Using libdatadog #{Libdatadog::VERSION} from #{Libdatadog.pkgconfig_folder}")
|
196
201
|
|
197
|
-
unless pkg_config(
|
202
|
+
unless pkg_config("datadog_profiling_with_rpath")
|
198
203
|
Logging.message("[datadog] Ruby detected the pkg-config command is #{$PKGCONFIG.inspect}\n")
|
199
204
|
|
200
205
|
skip_building_extension!(
|
201
|
-
if Datadog::
|
206
|
+
if Datadog::LibdatadogExtconfHelpers.pkg_config_missing?
|
202
207
|
Datadog::Profiling::NativeExtensionHelpers::Supported::PKG_CONFIG_IS_MISSING
|
203
208
|
else
|
204
209
|
# Less specific error message
|
@@ -207,7 +212,7 @@ unless pkg_config('datadog_profiling_with_rpath')
|
|
207
212
|
)
|
208
213
|
end
|
209
214
|
|
210
|
-
unless have_type(
|
215
|
+
unless have_type("atomic_int", ["stdatomic.h"])
|
211
216
|
skip_building_extension!(Datadog::Profiling::NativeExtensionHelpers::Supported::COMPILER_ATOMIC_MISSING)
|
212
217
|
end
|
213
218
|
|
@@ -215,8 +220,8 @@ end
|
|
215
220
|
# The extremely excessive escaping around ORIGIN below seems to be correct and was determined after a lot of
|
216
221
|
# experimentation. We need to get these special characters across a lot of tools untouched...
|
217
222
|
extra_relative_rpaths = [
|
218
|
-
Datadog::
|
219
|
-
*Datadog::
|
223
|
+
Datadog::LibdatadogExtconfHelpers.libdatadog_folder_relative_to_native_lib_folder(current_folder: __dir__),
|
224
|
+
*Datadog::LibdatadogExtconfHelpers.libdatadog_folder_relative_to_ruby_extensions_folders,
|
220
225
|
]
|
221
226
|
extra_relative_rpaths.each { |folder| $LDFLAGS += " -Wl,-rpath,$$$\\\\{ORIGIN\\}/#{folder.to_str}" }
|
222
227
|
Logging.message("[datadog] After pkg-config $LDFLAGS were set to: #{$LDFLAGS.inspect}\n")
|
@@ -237,8 +242,8 @@ if Datadog::Profiling::NativeExtensionHelpers::CAN_USE_MJIT_HEADER
|
|
237
242
|
# use the MJIT header.
|
238
243
|
# Finally, the `COMMON_HEADERS` conflict with the MJIT header so we need to temporarily disable them for this check.
|
239
244
|
original_common_headers = MakeMakefile::COMMON_HEADERS
|
240
|
-
MakeMakefile::COMMON_HEADERS =
|
241
|
-
unless have_macro(
|
245
|
+
MakeMakefile::COMMON_HEADERS = "".freeze
|
246
|
+
unless have_macro("RUBY_MJIT_H", mjit_header_file_name)
|
242
247
|
skip_building_extension!(Datadog::Profiling::NativeExtensionHelpers::Supported::COMPILATION_BROKEN)
|
243
248
|
end
|
244
249
|
MakeMakefile::COMMON_HEADERS = original_common_headers
|
@@ -250,7 +255,7 @@ if Datadog::Profiling::NativeExtensionHelpers::CAN_USE_MJIT_HEADER
|
|
250
255
|
|
251
256
|
# Warn on unused parameters to functions. Use `DDTRACE_UNUSED` to mark things as known-to-not-be-used.
|
252
257
|
# See the comment on the same flag below for why this is done last.
|
253
|
-
add_compiler_flag
|
258
|
+
add_compiler_flag "-Wunused-parameter"
|
254
259
|
|
255
260
|
create_makefile EXTENSION_NAME
|
256
261
|
else
|
@@ -261,23 +266,23 @@ else
|
|
261
266
|
|
262
267
|
create_header
|
263
268
|
|
264
|
-
require
|
265
|
-
dir_config(
|
269
|
+
require "debase/ruby_core_source"
|
270
|
+
dir_config("ruby") # allow user to pass in non-standard core include directory
|
266
271
|
|
267
272
|
Debase::RubyCoreSource
|
268
273
|
.create_makefile_with_core(
|
269
274
|
proc do
|
270
275
|
headers_available =
|
271
|
-
have_header(
|
272
|
-
have_header(
|
273
|
-
(RUBY_VERSION <
|
276
|
+
have_header("vm_core.h") &&
|
277
|
+
have_header("iseq.h") &&
|
278
|
+
(RUBY_VERSION < "3.3" || have_header("ractor_core.h"))
|
274
279
|
|
275
280
|
if headers_available
|
276
281
|
# Warn on unused parameters to functions. Use `DDTRACE_UNUSED` to mark things as known-to-not-be-used.
|
277
282
|
# This is added as late as possible because in some Rubies we support (e.g. 3.3), adding this flag before
|
278
283
|
# checking if internal VM headers are available causes those checks to fail because of this warning (and not
|
279
284
|
# because the headers are not available.)
|
280
|
-
add_compiler_flag
|
285
|
+
add_compiler_flag "-Wunused-parameter"
|
281
286
|
end
|
282
287
|
|
283
288
|
headers_available
|
@@ -166,6 +166,12 @@ struct heap_recorder {
|
|
166
166
|
size_t objects_frozen;
|
167
167
|
} stats_last_update;
|
168
168
|
};
|
169
|
+
|
170
|
+
struct end_heap_allocation_args {
|
171
|
+
struct heap_recorder *heap_recorder;
|
172
|
+
ddog_prof_Slice_Location locations;
|
173
|
+
};
|
174
|
+
|
169
175
|
static heap_record* get_or_create_heap_record(heap_recorder*, ddog_prof_Slice_Location);
|
170
176
|
static void cleanup_heap_record_if_unused(heap_recorder*, heap_record*);
|
171
177
|
static void on_committed_object_record_cleanup(heap_recorder *heap_recorder, object_record *record);
|
@@ -176,6 +182,7 @@ static int st_object_records_iterate(st_data_t, st_data_t, st_data_t);
|
|
176
182
|
static int st_object_records_debug(st_data_t key, st_data_t value, st_data_t extra);
|
177
183
|
static int update_object_record_entry(st_data_t*, st_data_t*, st_data_t, int);
|
178
184
|
static void commit_recording(heap_recorder*, heap_record*, recording);
|
185
|
+
static VALUE end_heap_allocation_recording(VALUE end_heap_allocation_args);
|
179
186
|
|
180
187
|
// ==========================
|
181
188
|
// Heap Recorder External API
|
@@ -219,7 +226,7 @@ void heap_recorder_free(heap_recorder *heap_recorder) {
|
|
219
226
|
st_foreach(heap_recorder->heap_records, st_heap_record_entry_free, 0);
|
220
227
|
st_free_table(heap_recorder->heap_records);
|
221
228
|
|
222
|
-
if (heap_recorder->active_recording.object_record != NULL) {
|
229
|
+
if (heap_recorder->active_recording.object_record != NULL && heap_recorder->active_recording.object_record != &SKIPPED_RECORD) {
|
223
230
|
// If there's a partial object record, clean it up as well
|
224
231
|
object_record_free(heap_recorder->active_recording.object_record);
|
225
232
|
}
|
@@ -340,9 +347,28 @@ void start_heap_allocation_recording(heap_recorder *heap_recorder, VALUE new_obj
|
|
340
347
|
};
|
341
348
|
}
|
342
349
|
|
343
|
-
|
350
|
+
// end_heap_allocation_recording_with_rb_protect gets called while the stack_recorder is holding one of the profile
|
351
|
+
// locks. To enable us to correctly unlock the profile on exception, we wrap the call to end_heap_allocation_recording
|
352
|
+
// with an rb_protect.
|
353
|
+
__attribute__((warn_unused_result))
|
354
|
+
int end_heap_allocation_recording_with_rb_protect(struct heap_recorder *heap_recorder, ddog_prof_Slice_Location locations) {
|
355
|
+
int exception_state;
|
356
|
+
struct end_heap_allocation_args end_heap_allocation_args = {
|
357
|
+
.heap_recorder = heap_recorder,
|
358
|
+
.locations = locations,
|
359
|
+
};
|
360
|
+
rb_protect(end_heap_allocation_recording, (VALUE) &end_heap_allocation_args, &exception_state);
|
361
|
+
return exception_state;
|
362
|
+
}
|
363
|
+
|
364
|
+
static VALUE end_heap_allocation_recording(VALUE end_heap_allocation_args) {
|
365
|
+
struct end_heap_allocation_args *args = (struct end_heap_allocation_args *) end_heap_allocation_args;
|
366
|
+
|
367
|
+
struct heap_recorder *heap_recorder = args->heap_recorder;
|
368
|
+
ddog_prof_Slice_Location locations = args->locations;
|
369
|
+
|
344
370
|
if (heap_recorder == NULL) {
|
345
|
-
return;
|
371
|
+
return Qnil;
|
346
372
|
}
|
347
373
|
|
348
374
|
recording active_recording = heap_recorder->active_recording;
|
@@ -356,15 +382,16 @@ void end_heap_allocation_recording(struct heap_recorder *heap_recorder, ddog_pro
|
|
356
382
|
// data required for committing though.
|
357
383
|
heap_recorder->active_recording = (recording) {0};
|
358
384
|
|
359
|
-
if (active_recording.object_record == &SKIPPED_RECORD) {
|
360
|
-
|
361
|
-
return;
|
385
|
+
if (active_recording.object_record == &SKIPPED_RECORD) { // special marker when we decided to skip due to sampling
|
386
|
+
return Qnil;
|
362
387
|
}
|
363
388
|
|
364
389
|
heap_record *heap_record = get_or_create_heap_record(heap_recorder, locations);
|
365
390
|
|
366
391
|
// And then commit the new allocation.
|
367
392
|
commit_recording(heap_recorder, heap_record, active_recording);
|
393
|
+
|
394
|
+
return Qnil;
|
368
395
|
}
|
369
396
|
|
370
397
|
void heap_recorder_prepare_iteration(heap_recorder *heap_recorder) {
|
@@ -815,6 +842,7 @@ VALUE object_record_inspect(object_record *record) {
|
|
815
842
|
if (!ruby_ref_from_id(LONG2NUM(record->obj_id), &ref)) {
|
816
843
|
rb_str_catf(inspect, "object=<invalid>");
|
817
844
|
} else {
|
845
|
+
rb_str_catf(inspect, "value=%p ", (void *) ref);
|
818
846
|
VALUE ruby_inspect = ruby_safe_inspect(ref);
|
819
847
|
if (ruby_inspect != Qnil) {
|
820
848
|
rb_str_catf(inspect, "object=%"PRIsVALUE, ruby_inspect);
|
@@ -114,7 +114,9 @@ void start_heap_allocation_recording(heap_recorder *heap_recorder, VALUE new_obj
|
|
114
114
|
// @param locations The stacktrace representing the location of the allocation.
|
115
115
|
//
|
116
116
|
// WARN: It is illegal to call this without previously having called ::start_heap_allocation_recording.
|
117
|
-
|
117
|
+
// WARN: This method rescues exceptions with `rb_protect`, returning the exception state integer for the caller to handle.
|
118
|
+
__attribute__((warn_unused_result))
|
119
|
+
int end_heap_allocation_recording_with_rb_protect(heap_recorder *heap_recorder, ddog_prof_Slice_Location locations);
|
118
120
|
|
119
121
|
// Update the heap recorder to reflect the latest state of the VM and prepare internal structures
|
120
122
|
// for efficient iteration.
|
@@ -2,22 +2,11 @@
|
|
2
2
|
|
3
3
|
#include <stdint.h>
|
4
4
|
|
5
|
-
// Used to mark symbols to be exported to the outside of the extension.
|
6
|
-
// Consider very carefully before tagging a function with this.
|
7
|
-
#define DDTRACE_EXPORT __attribute__ ((visibility ("default")))
|
8
|
-
|
9
|
-
// Used to mark function arguments that are deliberately left unused
|
10
|
-
#ifdef __GNUC__
|
11
|
-
#define DDTRACE_UNUSED __attribute__((unused))
|
12
|
-
#else
|
13
|
-
#define DDTRACE_UNUSED
|
14
|
-
#endif
|
15
|
-
|
16
5
|
// @ivoanjo: After trying to read through https://stackoverflow.com/questions/3437404/min-and-max-in-c I decided I
|
17
6
|
// don't like C and I just implemented this as a function.
|
18
|
-
inline
|
19
|
-
inline
|
20
|
-
inline
|
21
|
-
inline
|
22
|
-
inline
|
23
|
-
inline
|
7
|
+
static inline uint64_t uint64_max_of(uint64_t a, uint64_t b) { return a > b ? a : b; }
|
8
|
+
static inline uint64_t uint64_min_of(uint64_t a, uint64_t b) { return a > b ? b : a; }
|
9
|
+
static inline long long_max_of(long a, long b) { return a > b ? a : b; }
|
10
|
+
static inline long long_min_of(long a, long b) { return a > b ? b : a; }
|
11
|
+
static inline double double_max_of(double a, double b) { return a > b ? a : b; }
|
12
|
+
static inline double double_min_of(double a, double b) { return a > b ? b : a; }
|
@@ -21,7 +21,7 @@ struct call_exporter_without_gvl_arguments {
|
|
21
21
|
bool send_ran;
|
22
22
|
};
|
23
23
|
|
24
|
-
inline
|
24
|
+
static inline ddog_ByteSlice byte_slice_from_ruby_string(VALUE string);
|
25
25
|
static VALUE _native_validate_exporter(VALUE self, VALUE exporter_configuration);
|
26
26
|
static ddog_prof_Exporter_NewResult create_exporter(VALUE exporter_configuration, VALUE tags_as_array);
|
27
27
|
static VALUE handle_exporter_failure(ddog_prof_Exporter_NewResult exporter_result);
|
@@ -53,11 +53,11 @@ void http_transport_init(VALUE profiling_module) {
|
|
53
53
|
ok_symbol = ID2SYM(rb_intern_const("ok"));
|
54
54
|
error_symbol = ID2SYM(rb_intern_const("error"));
|
55
55
|
|
56
|
-
library_version_string =
|
56
|
+
library_version_string = datadog_gem_version();
|
57
57
|
rb_global_variable(&library_version_string);
|
58
58
|
}
|
59
59
|
|
60
|
-
inline
|
60
|
+
static inline ddog_ByteSlice byte_slice_from_ruby_string(VALUE string) {
|
61
61
|
ENFORCE_TYPE(string, T_STRING);
|
62
62
|
ddog_ByteSlice byte_slice = {.ptr = (uint8_t *) StringValuePtr(string), .len = RSTRING_LEN(string)};
|
63
63
|
return byte_slice;
|
@@ -2,8 +2,6 @@
|
|
2
2
|
|
3
3
|
#include <ruby.h>
|
4
4
|
|
5
|
-
static VALUE log_failure_to_process_tag(VALUE err_details);
|
6
|
-
|
7
5
|
const char *ruby_value_type_to_string(enum ruby_value_type type) {
|
8
6
|
return ruby_value_type_to_char_slice(type).ptr;
|
9
7
|
}
|
@@ -62,87 +60,3 @@ size_t read_ddogerr_string_and_drop(ddog_Error *error, char *string, size_t capa
|
|
62
60
|
ddog_Error_drop(error);
|
63
61
|
return error_msg_size;
|
64
62
|
}
|
65
|
-
|
66
|
-
__attribute__((warn_unused_result))
|
67
|
-
ddog_prof_Endpoint endpoint_from(VALUE exporter_configuration) {
|
68
|
-
ENFORCE_TYPE(exporter_configuration, T_ARRAY);
|
69
|
-
|
70
|
-
VALUE exporter_working_mode = rb_ary_entry(exporter_configuration, 0);
|
71
|
-
ENFORCE_TYPE(exporter_working_mode, T_SYMBOL);
|
72
|
-
ID working_mode = SYM2ID(exporter_working_mode);
|
73
|
-
|
74
|
-
ID agentless_id = rb_intern("agentless");
|
75
|
-
ID agent_id = rb_intern("agent");
|
76
|
-
|
77
|
-
if (working_mode != agentless_id && working_mode != agent_id) {
|
78
|
-
rb_raise(rb_eArgError, "Failed to initialize transport: Unexpected working mode, expected :agentless or :agent");
|
79
|
-
}
|
80
|
-
|
81
|
-
if (working_mode == agentless_id) {
|
82
|
-
VALUE site = rb_ary_entry(exporter_configuration, 1);
|
83
|
-
VALUE api_key = rb_ary_entry(exporter_configuration, 2);
|
84
|
-
ENFORCE_TYPE(site, T_STRING);
|
85
|
-
ENFORCE_TYPE(api_key, T_STRING);
|
86
|
-
|
87
|
-
return ddog_prof_Endpoint_agentless(char_slice_from_ruby_string(site), char_slice_from_ruby_string(api_key));
|
88
|
-
} else { // agent_id
|
89
|
-
VALUE base_url = rb_ary_entry(exporter_configuration, 1);
|
90
|
-
ENFORCE_TYPE(base_url, T_STRING);
|
91
|
-
|
92
|
-
return ddog_prof_Endpoint_agent(char_slice_from_ruby_string(base_url));
|
93
|
-
}
|
94
|
-
}
|
95
|
-
|
96
|
-
__attribute__((warn_unused_result))
|
97
|
-
ddog_Vec_Tag convert_tags(VALUE tags_as_array) {
|
98
|
-
ENFORCE_TYPE(tags_as_array, T_ARRAY);
|
99
|
-
|
100
|
-
long tags_count = RARRAY_LEN(tags_as_array);
|
101
|
-
ddog_Vec_Tag tags = ddog_Vec_Tag_new();
|
102
|
-
|
103
|
-
for (long i = 0; i < tags_count; i++) {
|
104
|
-
VALUE name_value_pair = rb_ary_entry(tags_as_array, i);
|
105
|
-
|
106
|
-
if (!RB_TYPE_P(name_value_pair, T_ARRAY)) {
|
107
|
-
ddog_Vec_Tag_drop(tags);
|
108
|
-
ENFORCE_TYPE(name_value_pair, T_ARRAY);
|
109
|
-
}
|
110
|
-
|
111
|
-
// Note: We can index the array without checking its size first because rb_ary_entry returns Qnil if out of bounds
|
112
|
-
VALUE tag_name = rb_ary_entry(name_value_pair, 0);
|
113
|
-
VALUE tag_value = rb_ary_entry(name_value_pair, 1);
|
114
|
-
|
115
|
-
if (!(RB_TYPE_P(tag_name, T_STRING) && RB_TYPE_P(tag_value, T_STRING))) {
|
116
|
-
ddog_Vec_Tag_drop(tags);
|
117
|
-
ENFORCE_TYPE(tag_name, T_STRING);
|
118
|
-
ENFORCE_TYPE(tag_value, T_STRING);
|
119
|
-
}
|
120
|
-
|
121
|
-
ddog_Vec_Tag_PushResult push_result =
|
122
|
-
ddog_Vec_Tag_push(&tags, char_slice_from_ruby_string(tag_name), char_slice_from_ruby_string(tag_value));
|
123
|
-
|
124
|
-
if (push_result.tag == DDOG_VEC_TAG_PUSH_RESULT_ERR) {
|
125
|
-
// libdatadog validates tags and may catch invalid tags that ddtrace didn't actually catch.
|
126
|
-
// We warn users about such tags, and then just ignore them.
|
127
|
-
|
128
|
-
int exception_state;
|
129
|
-
rb_protect(log_failure_to_process_tag, get_error_details_and_drop(&push_result.err), &exception_state);
|
130
|
-
|
131
|
-
// Since we are calling into Ruby code, it may raise an exception. Ensure that dynamically-allocated tags
|
132
|
-
// get cleaned before propagating the exception.
|
133
|
-
if (exception_state) {
|
134
|
-
ddog_Vec_Tag_drop(tags);
|
135
|
-
rb_jump_tag(exception_state); // "Re-raise" exception
|
136
|
-
}
|
137
|
-
}
|
138
|
-
}
|
139
|
-
|
140
|
-
return tags;
|
141
|
-
}
|
142
|
-
|
143
|
-
static VALUE log_failure_to_process_tag(VALUE err_details) {
|
144
|
-
VALUE datadog_module = rb_const_get(rb_cObject, rb_intern("Datadog"));
|
145
|
-
VALUE logger = rb_funcall(datadog_module, rb_intern("logger"), 0);
|
146
|
-
|
147
|
-
return rb_funcall(logger, rb_intern("warn"), 1, rb_sprintf("Failed to add tag to profiling request: %"PRIsVALUE, err_details));
|
148
|
-
}
|
@@ -3,27 +3,10 @@
|
|
3
3
|
#include <datadog/profiling.h>
|
4
4
|
#include "ruby_helpers.h"
|
5
5
|
|
6
|
-
|
7
|
-
ENFORCE_TYPE(string, T_STRING);
|
8
|
-
ddog_CharSlice char_slice = {.ptr = StringValuePtr(string), .len = RSTRING_LEN(string)};
|
9
|
-
return char_slice;
|
10
|
-
}
|
11
|
-
|
12
|
-
inline static VALUE ruby_string_from_vec_u8(ddog_Vec_U8 string) {
|
6
|
+
static inline VALUE ruby_string_from_vec_u8(ddog_Vec_U8 string) {
|
13
7
|
return rb_str_new((char *) string.ptr, string.len);
|
14
8
|
}
|
15
9
|
|
16
|
-
inline static VALUE ruby_string_from_error(const ddog_Error *error) {
|
17
|
-
ddog_CharSlice char_slice = ddog_Error_message(error);
|
18
|
-
return rb_str_new(char_slice.ptr, char_slice.len);
|
19
|
-
}
|
20
|
-
|
21
|
-
inline static VALUE get_error_details_and_drop(ddog_Error *error) {
|
22
|
-
VALUE result = ruby_string_from_error(error);
|
23
|
-
ddog_Error_drop(error);
|
24
|
-
return result;
|
25
|
-
}
|
26
|
-
|
27
10
|
// Utility function to be able to extract an error cstring from a ddog_Error.
|
28
11
|
// Returns the amount of characters written to string (which are necessarily
|
29
12
|
// bounded by capacity - 1 since the string will be null-terminated).
|
@@ -37,10 +20,6 @@ ddog_CharSlice ruby_value_type_to_char_slice(enum ruby_value_type type);
|
|
37
20
|
|
38
21
|
// Returns a dynamically allocated string from the provided char slice.
|
39
22
|
// WARN: The returned string must be explicitly freed with ruby_xfree.
|
40
|
-
inline
|
23
|
+
static inline char* string_from_char_slice(ddog_CharSlice slice) {
|
41
24
|
return ruby_strndup(slice.ptr, slice.len);
|
42
25
|
}
|
43
|
-
|
44
|
-
ddog_prof_Endpoint endpoint_from(VALUE exporter_configuration);
|
45
|
-
|
46
|
-
ddog_Vec_Tag convert_tags(VALUE tags_as_array);
|