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.
Files changed (196) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +87 -2
  3. data/ext/datadog_profiling_loader/datadog_profiling_loader.c +9 -1
  4. data/ext/datadog_profiling_loader/extconf.rb +14 -26
  5. data/ext/datadog_profiling_native_extension/clock_id.h +1 -0
  6. data/ext/datadog_profiling_native_extension/clock_id_from_pthread.c +1 -2
  7. data/ext/datadog_profiling_native_extension/clock_id_noop.c +1 -2
  8. data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +257 -69
  9. data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.c +53 -28
  10. data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.h +34 -4
  11. data/ext/datadog_profiling_native_extension/collectors_idle_sampling_helper.c +4 -0
  12. data/ext/datadog_profiling_native_extension/collectors_stack.c +136 -81
  13. data/ext/datadog_profiling_native_extension/collectors_stack.h +2 -2
  14. data/ext/datadog_profiling_native_extension/collectors_thread_context.c +661 -48
  15. data/ext/datadog_profiling_native_extension/collectors_thread_context.h +10 -1
  16. data/ext/datadog_profiling_native_extension/datadog_ruby_common.c +83 -0
  17. data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +53 -0
  18. data/ext/datadog_profiling_native_extension/extconf.rb +91 -69
  19. data/ext/datadog_profiling_native_extension/gvl_profiling_helper.c +50 -0
  20. data/ext/datadog_profiling_native_extension/gvl_profiling_helper.h +75 -0
  21. data/ext/datadog_profiling_native_extension/heap_recorder.c +54 -12
  22. data/ext/datadog_profiling_native_extension/heap_recorder.h +3 -1
  23. data/ext/datadog_profiling_native_extension/helpers.h +6 -17
  24. data/ext/datadog_profiling_native_extension/http_transport.c +41 -9
  25. data/ext/datadog_profiling_native_extension/libdatadog_helpers.c +0 -86
  26. data/ext/datadog_profiling_native_extension/libdatadog_helpers.h +2 -23
  27. data/ext/datadog_profiling_native_extension/native_extension_helpers.rb +61 -172
  28. data/ext/datadog_profiling_native_extension/private_vm_api_access.c +116 -139
  29. data/ext/datadog_profiling_native_extension/private_vm_api_access.h +20 -11
  30. data/ext/datadog_profiling_native_extension/profiling.c +1 -3
  31. data/ext/datadog_profiling_native_extension/ruby_helpers.c +0 -33
  32. data/ext/datadog_profiling_native_extension/ruby_helpers.h +1 -26
  33. data/ext/datadog_profiling_native_extension/setup_signal_handler.h +1 -0
  34. data/ext/datadog_profiling_native_extension/stack_recorder.c +14 -2
  35. data/ext/datadog_profiling_native_extension/stack_recorder.h +2 -0
  36. data/ext/datadog_profiling_native_extension/time_helpers.c +0 -15
  37. data/ext/datadog_profiling_native_extension/time_helpers.h +36 -6
  38. data/ext/{datadog_profiling_native_extension → libdatadog_api}/crashtracker.c +37 -22
  39. data/ext/libdatadog_api/datadog_ruby_common.c +83 -0
  40. data/ext/libdatadog_api/datadog_ruby_common.h +53 -0
  41. data/ext/libdatadog_api/extconf.rb +108 -0
  42. data/ext/libdatadog_api/macos_development.md +26 -0
  43. data/ext/libdatadog_extconf_helpers.rb +130 -0
  44. data/lib/datadog/appsec/assets/waf_rules/recommended.json +2184 -108
  45. data/lib/datadog/appsec/assets/waf_rules/strict.json +1430 -2
  46. data/lib/datadog/appsec/component.rb +29 -8
  47. data/lib/datadog/appsec/configuration/settings.rb +2 -2
  48. data/lib/datadog/appsec/contrib/devise/patcher/authenticatable_patch.rb +1 -0
  49. data/lib/datadog/appsec/contrib/devise/patcher/rememberable_patch.rb +21 -0
  50. data/lib/datadog/appsec/contrib/devise/patcher.rb +12 -2
  51. data/lib/datadog/appsec/contrib/graphql/appsec_trace.rb +35 -0
  52. data/lib/datadog/appsec/contrib/graphql/gateway/multiplex.rb +109 -0
  53. data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +71 -0
  54. data/lib/datadog/appsec/contrib/graphql/integration.rb +54 -0
  55. data/lib/datadog/appsec/contrib/graphql/patcher.rb +37 -0
  56. data/lib/datadog/appsec/contrib/graphql/reactive/multiplex.rb +59 -0
  57. data/lib/datadog/appsec/contrib/rack/gateway/request.rb +3 -6
  58. data/lib/datadog/appsec/event.rb +1 -1
  59. data/lib/datadog/appsec/processor/actions.rb +1 -1
  60. data/lib/datadog/appsec/processor/rule_loader.rb +3 -1
  61. data/lib/datadog/appsec/processor/rule_merger.rb +33 -15
  62. data/lib/datadog/appsec/processor.rb +36 -37
  63. data/lib/datadog/appsec/rate_limiter.rb +25 -40
  64. data/lib/datadog/appsec/remote.rb +7 -3
  65. data/lib/datadog/appsec/response.rb +15 -1
  66. data/lib/datadog/appsec.rb +3 -2
  67. data/lib/datadog/core/configuration/components.rb +18 -15
  68. data/lib/datadog/core/configuration/settings.rb +135 -9
  69. data/lib/datadog/core/crashtracking/agent_base_url.rb +21 -0
  70. data/lib/datadog/core/crashtracking/component.rb +111 -0
  71. data/lib/datadog/core/crashtracking/tag_builder.rb +39 -0
  72. data/lib/datadog/core/diagnostics/environment_logger.rb +8 -11
  73. data/lib/datadog/core/environment/execution.rb +5 -5
  74. data/lib/datadog/core/metrics/client.rb +7 -0
  75. data/lib/datadog/core/rate_limiter.rb +183 -0
  76. data/lib/datadog/core/remote/client/capabilities.rb +4 -3
  77. data/lib/datadog/core/remote/component.rb +4 -2
  78. data/lib/datadog/core/remote/negotiation.rb +4 -4
  79. data/lib/datadog/core/remote/tie.rb +2 -0
  80. data/lib/datadog/core/runtime/metrics.rb +1 -1
  81. data/lib/datadog/core/telemetry/component.rb +51 -2
  82. data/lib/datadog/core/telemetry/emitter.rb +9 -11
  83. data/lib/datadog/core/telemetry/event.rb +37 -1
  84. data/lib/datadog/core/telemetry/ext.rb +1 -0
  85. data/lib/datadog/core/telemetry/http/adapters/net.rb +10 -12
  86. data/lib/datadog/core/telemetry/http/ext.rb +3 -0
  87. data/lib/datadog/core/telemetry/http/transport.rb +38 -9
  88. data/lib/datadog/core/telemetry/logger.rb +51 -0
  89. data/lib/datadog/core/telemetry/logging.rb +71 -0
  90. data/lib/datadog/core/telemetry/request.rb +13 -1
  91. data/lib/datadog/core/utils/at_fork_monkey_patch.rb +102 -0
  92. data/lib/datadog/core/utils/time.rb +12 -0
  93. data/lib/datadog/di/code_tracker.rb +168 -0
  94. data/lib/datadog/di/configuration/settings.rb +163 -0
  95. data/lib/datadog/di/configuration.rb +11 -0
  96. data/lib/datadog/di/error.rb +31 -0
  97. data/lib/datadog/di/extensions.rb +16 -0
  98. data/lib/datadog/di/probe.rb +133 -0
  99. data/lib/datadog/di/probe_builder.rb +41 -0
  100. data/lib/datadog/di/redactor.rb +188 -0
  101. data/lib/datadog/di/serializer.rb +193 -0
  102. data/lib/datadog/di.rb +14 -0
  103. data/lib/datadog/kit/appsec/events.rb +2 -4
  104. data/lib/datadog/opentelemetry/sdk/propagator.rb +2 -0
  105. data/lib/datadog/opentelemetry/sdk/span_processor.rb +10 -0
  106. data/lib/datadog/opentelemetry/sdk/trace/span.rb +23 -0
  107. data/lib/datadog/profiling/collectors/code_provenance.rb +7 -7
  108. data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +28 -26
  109. data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +11 -13
  110. data/lib/datadog/profiling/collectors/info.rb +15 -6
  111. data/lib/datadog/profiling/collectors/thread_context.rb +30 -2
  112. data/lib/datadog/profiling/component.rb +89 -95
  113. data/lib/datadog/profiling/exporter.rb +3 -3
  114. data/lib/datadog/profiling/ext/dir_monkey_patches.rb +3 -3
  115. data/lib/datadog/profiling/ext.rb +21 -21
  116. data/lib/datadog/profiling/flush.rb +1 -1
  117. data/lib/datadog/profiling/http_transport.rb +14 -7
  118. data/lib/datadog/profiling/load_native_extension.rb +5 -5
  119. data/lib/datadog/profiling/preload.rb +1 -1
  120. data/lib/datadog/profiling/profiler.rb +5 -8
  121. data/lib/datadog/profiling/scheduler.rb +33 -25
  122. data/lib/datadog/profiling/stack_recorder.rb +3 -0
  123. data/lib/datadog/profiling/tag_builder.rb +2 -2
  124. data/lib/datadog/profiling/tasks/exec.rb +5 -5
  125. data/lib/datadog/profiling/tasks/setup.rb +16 -35
  126. data/lib/datadog/profiling.rb +4 -5
  127. data/lib/datadog/single_step_instrument.rb +12 -0
  128. data/lib/datadog/tracing/contrib/action_cable/instrumentation.rb +8 -12
  129. data/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb +5 -0
  130. data/lib/datadog/tracing/contrib/action_pack/action_dispatch/instrumentation.rb +78 -0
  131. data/lib/datadog/tracing/contrib/action_pack/action_dispatch/patcher.rb +33 -0
  132. data/lib/datadog/tracing/contrib/action_pack/patcher.rb +2 -0
  133. data/lib/datadog/tracing/contrib/active_record/configuration/resolver.rb +4 -0
  134. data/lib/datadog/tracing/contrib/active_record/events/instantiation.rb +3 -1
  135. data/lib/datadog/tracing/contrib/active_record/events/sql.rb +4 -1
  136. data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +5 -1
  137. data/lib/datadog/tracing/contrib/aws/instrumentation.rb +5 -0
  138. data/lib/datadog/tracing/contrib/elasticsearch/patcher.rb +6 -1
  139. data/lib/datadog/tracing/contrib/ext.rb +14 -0
  140. data/lib/datadog/tracing/contrib/faraday/middleware.rb +9 -0
  141. data/lib/datadog/tracing/contrib/grape/endpoint.rb +19 -0
  142. data/lib/datadog/tracing/contrib/graphql/patcher.rb +9 -12
  143. data/lib/datadog/tracing/contrib/graphql/trace_patcher.rb +3 -3
  144. data/lib/datadog/tracing/contrib/graphql/tracing_patcher.rb +3 -3
  145. data/lib/datadog/tracing/contrib/graphql/unified_trace.rb +14 -10
  146. data/lib/datadog/tracing/contrib/graphql/unified_trace_patcher.rb +10 -4
  147. data/lib/datadog/tracing/contrib/http/instrumentation.rb +18 -15
  148. data/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +6 -5
  149. data/lib/datadog/tracing/contrib/httpclient/patcher.rb +1 -14
  150. data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +5 -0
  151. data/lib/datadog/tracing/contrib/httprb/patcher.rb +1 -14
  152. data/lib/datadog/tracing/contrib/lograge/patcher.rb +15 -0
  153. data/lib/datadog/tracing/contrib/mongodb/subscribers.rb +2 -0
  154. data/lib/datadog/tracing/contrib/mysql2/configuration/settings.rb +5 -0
  155. data/lib/datadog/tracing/contrib/mysql2/instrumentation.rb +17 -13
  156. data/lib/datadog/tracing/contrib/opensearch/patcher.rb +13 -6
  157. data/lib/datadog/tracing/contrib/patcher.rb +2 -1
  158. data/lib/datadog/tracing/contrib/pg/configuration/settings.rb +5 -0
  159. data/lib/datadog/tracing/contrib/pg/instrumentation.rb +4 -1
  160. data/lib/datadog/tracing/contrib/presto/patcher.rb +1 -13
  161. data/lib/datadog/tracing/contrib/propagation/sql_comment/ext.rb +28 -0
  162. data/lib/datadog/tracing/contrib/propagation/sql_comment/mode.rb +5 -1
  163. data/lib/datadog/tracing/contrib/propagation/sql_comment.rb +22 -10
  164. data/lib/datadog/tracing/contrib/rack/middlewares.rb +27 -0
  165. data/lib/datadog/tracing/contrib/redis/tags.rb +4 -0
  166. data/lib/datadog/tracing/contrib/sinatra/tracer.rb +4 -0
  167. data/lib/datadog/tracing/contrib/stripe/request.rb +3 -2
  168. data/lib/datadog/tracing/contrib/trilogy/configuration/settings.rb +5 -0
  169. data/lib/datadog/tracing/contrib/trilogy/instrumentation.rb +4 -1
  170. data/lib/datadog/tracing/diagnostics/environment_logger.rb +14 -16
  171. data/lib/datadog/tracing/distributed/propagation.rb +7 -0
  172. data/lib/datadog/tracing/metadata/errors.rb +9 -1
  173. data/lib/datadog/tracing/metadata/ext.rb +6 -0
  174. data/lib/datadog/tracing/pipeline/span_filter.rb +2 -2
  175. data/lib/datadog/tracing/remote.rb +5 -2
  176. data/lib/datadog/tracing/sampling/matcher.rb +6 -1
  177. data/lib/datadog/tracing/sampling/rate_sampler.rb +1 -1
  178. data/lib/datadog/tracing/sampling/rule.rb +2 -0
  179. data/lib/datadog/tracing/sampling/rule_sampler.rb +9 -5
  180. data/lib/datadog/tracing/sampling/span/ext.rb +1 -1
  181. data/lib/datadog/tracing/sampling/span/rule.rb +2 -2
  182. data/lib/datadog/tracing/span.rb +9 -2
  183. data/lib/datadog/tracing/span_event.rb +41 -0
  184. data/lib/datadog/tracing/span_operation.rb +6 -2
  185. data/lib/datadog/tracing/trace_operation.rb +26 -2
  186. data/lib/datadog/tracing/tracer.rb +14 -12
  187. data/lib/datadog/tracing/transport/http/client.rb +1 -0
  188. data/lib/datadog/tracing/transport/io/client.rb +1 -0
  189. data/lib/datadog/tracing/transport/serializable_trace.rb +3 -0
  190. data/lib/datadog/tracing/workers/trace_writer.rb +1 -1
  191. data/lib/datadog/tracing/workers.rb +1 -1
  192. data/lib/datadog/version.rb +1 -1
  193. metadata +46 -11
  194. data/lib/datadog/profiling/crashtracker.rb +0 -91
  195. data/lib/datadog/profiling/ext/forking.rb +0 -98
  196. data/lib/datadog/tracing/sampling/rate_limiter.rb +0 -185
@@ -0,0 +1,193 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "redactor"
4
+
5
+ module Datadog
6
+ module DI
7
+ # Serializes captured snapshot to primitive types, which are subsequently
8
+ # serialized to JSON and sent to the backend.
9
+ #
10
+ # This class performs actual removal of sensitive values from the
11
+ # snapshots. It uses Redactor to determine which values are sensitive
12
+ # and need to be removed.
13
+ #
14
+ # Serializer normally ought not to invoke user (application) code,
15
+ # to guarantee predictable performance. However, objects like ActiveRecord
16
+ # models cannot be usefully serialized into primitive types without
17
+ # custom logic (for example, the attributes are more than 3 levels
18
+ # down from the top-level object which is the default capture depth,
19
+ # thus they won't be captured at all). To accommodate complex objects,
20
+ # there is an extension mechanism implemented permitting registration
21
+ # of serializer callbacks for arbitrary types. Applications and libraries
22
+ # definining such serializer callbacks should be very careful to
23
+ # have predictable performance and avoid exceptions and infinite loops
24
+ # and other such issues.
25
+ #
26
+ # All serialization methods take the names of the variables being
27
+ # serialized in order to be able to redact values.
28
+ #
29
+ # @api private
30
+ class Serializer
31
+ def initialize(settings, redactor)
32
+ @settings = settings
33
+ @redactor = redactor
34
+ end
35
+
36
+ attr_reader :settings
37
+ attr_reader :redactor
38
+
39
+ # Serializes positional and keyword arguments to a method,
40
+ # as obtained by a method probe.
41
+ #
42
+ # UI supports a single argument list only and does not distinguish
43
+ # between positional and keyword arguments. We convert positional
44
+ # arguments to keyword arguments ("arg1", "arg2", ...) and ensure
45
+ # the positional arguments are listed first.
46
+ def serialize_args(args, kwargs)
47
+ counter = 0
48
+ combined = args.each_with_object({}) do |value, c|
49
+ counter += 1
50
+ # Conversion to symbol is needed here to put args ahead of
51
+ # kwargs when they are merged below.
52
+ c[:"arg#{counter}"] = value
53
+ end.update(kwargs)
54
+ serialize_vars(combined)
55
+ end
56
+
57
+ # Serializes variables captured by a line probe.
58
+ #
59
+ # These are normally local variables that exist on a particular line
60
+ # of executed code.
61
+ def serialize_vars(vars)
62
+ vars.each_with_object({}) do |(k, v), agg|
63
+ agg[k] = serialize_value(v, name: k)
64
+ end
65
+ end
66
+
67
+ # Serializes a single named value.
68
+ #
69
+ # The name is needed to perform sensitive data redaction.
70
+ #
71
+ # In some cases, the value being serialized does not have a name
72
+ # (for example, it is the return value of a method).
73
+ # In this case +name+ can be nil.
74
+ #
75
+ # Returns a data structure comprised of only values of basic types
76
+ # (integers, strings, arrays, hashes).
77
+ #
78
+ # Respects string length, collection size and traversal depth limits.
79
+ def serialize_value(value, name: nil, depth: settings.dynamic_instrumentation.max_capture_depth)
80
+ if redactor.redact_type?(value)
81
+ return {type: class_name(value.class), notCapturedReason: "redactedType"}
82
+ end
83
+
84
+ if name && redactor.redact_identifier?(name)
85
+ return {type: class_name(value.class), notCapturedReason: "redactedIdent"}
86
+ end
87
+
88
+ serialized = {type: class_name(value.class)}
89
+ case value
90
+ when NilClass
91
+ serialized.update(isNull: true)
92
+ when Integer, Float, TrueClass, FalseClass
93
+ serialized.update(value: value.to_s)
94
+ when String, Symbol
95
+ value = value.to_s
96
+ max = settings.dynamic_instrumentation.max_capture_string_length
97
+ if value.length > max
98
+ serialized.update(truncated: true, size: value.length)
99
+ value = value[0...max]
100
+ end
101
+ serialized.update(value: value)
102
+ when Array
103
+ if depth < 0
104
+ serialized.update(notCapturedReason: "depth")
105
+ else
106
+ max = settings.dynamic_instrumentation.max_capture_collection_size
107
+ if max != 0 && value.length > max
108
+ serialized.update(notCapturedReason: "collectionSize", size: value.length)
109
+ # same steep failure with array slices.
110
+ # https://github.com/soutaro/steep/issues/1219
111
+ value = value[0...max] || []
112
+ end
113
+ entries = value.map do |elt|
114
+ serialize_value(elt, depth: depth - 1)
115
+ end
116
+ serialized.update(elements: entries)
117
+ end
118
+ when Hash
119
+ if depth < 0
120
+ serialized.update(notCapturedReason: "depth")
121
+ else
122
+ max = settings.dynamic_instrumentation.max_capture_collection_size
123
+ cur = 0
124
+ entries = []
125
+ value.each do |k, v|
126
+ if max != 0 && cur >= max
127
+ serialized.update(notCapturedReason: "collectionSize", size: value.length)
128
+ break
129
+ end
130
+ cur += 1
131
+ entries << [serialize_value(k, depth: depth - 1), serialize_value(v, name: k, depth: depth - 1)]
132
+ end
133
+ serialized.update(entries: entries)
134
+ end
135
+ else
136
+ if depth < 0
137
+ serialized.update(notCapturedReason: "depth")
138
+ else
139
+ fields = {}
140
+ max = settings.dynamic_instrumentation.max_capture_attribute_count
141
+ cur = 0
142
+
143
+ # MRI and JRuby 9.4.5+ preserve instance variable definition
144
+ # order when calling #instance_variables. Previous JRuby versions
145
+ # did not preserve order and returned the variables in arbitrary
146
+ # order.
147
+ #
148
+ # The arbitrary order is problematic because 1) when there are
149
+ # fewer instance variables than capture limit, the order in which
150
+ # the variables are shown in UI will change from one capture to
151
+ # the next and generally will be arbitrary to the user, and
152
+ # 2) when there are more instance variables than capture limit,
153
+ # *which* variables are captured will also change meaning user
154
+ # looking at the UI may have "new" instance variables appear and
155
+ # existing ones disappear as they are looking at multiple captures.
156
+ #
157
+ # For consistency, we should have some kind of stable order of
158
+ # instance variables on all supported Ruby runtimes, so that the UI
159
+ # stays consistent. Given that initial implementation of Ruby DI
160
+ # does not support JRuby, we don't handle JRuby's lack of ordering
161
+ # of #instance_variables here, but if JRuby is supported in the
162
+ # future this may need to be addressed.
163
+ ivars = value.instance_variables
164
+
165
+ ivars.each do |ivar|
166
+ if cur >= max
167
+ serialized.update(notCapturedReason: "fieldCount", fields: fields)
168
+ break
169
+ end
170
+ cur += 1
171
+ fields[ivar] = serialize_value(value.instance_variable_get(ivar), name: ivar, depth: depth - 1)
172
+ end
173
+ serialized.update(fields: fields)
174
+ end
175
+ end
176
+ serialized
177
+ end
178
+
179
+ private
180
+
181
+ # Returns the name for the specified class object.
182
+ #
183
+ # Ruby can have nameless classes, e.g. Class.new is a class object
184
+ # with no name. We return a placeholder for such nameless classes.
185
+ def class_name(cls)
186
+ # We could call `cls.to_s` to get the "standard" Ruby inspection of
187
+ # the class, but it is likely that user code can override #to_s
188
+ # and we don't want to invoke user code.
189
+ cls.name || "[Unnamed class]"
190
+ end
191
+ end
192
+ end
193
+ end
data/lib/datadog/di.rb ADDED
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'di/configuration'
4
+ require_relative 'di/extensions'
5
+
6
+ module Datadog
7
+ # Namespace for Datadog dynamic instrumentation.
8
+ #
9
+ # @api private
10
+ module DI
11
+ # Expose DI to global shared objects
12
+ Extensions.activate!
13
+ end
14
+ 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, user_id:, user_exists:, **others)
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
@@ -15,6 +15,7 @@ module Datadog
15
15
  setter: ::OpenTelemetry::Context::Propagation.text_map_setter
16
16
  )
17
17
  unless setter == ::OpenTelemetry::Context::Propagation.text_map_setter
18
+ # PENDING: Not to report telemetry logs for now
18
19
  Datadog.logger.error(
19
20
  'Custom setter is not supported. Please inform the `datadog` team at ' \
20
21
  ' https://github.com/DataDog/dd-trace-rb of your use case so we can best support you. Using the default ' \
@@ -31,6 +32,7 @@ module Datadog
31
32
  )
32
33
  if getter != ::OpenTelemetry::Context::Propagation.text_map_getter &&
33
34
  getter != ::OpenTelemetry::Common::Propagation.rack_env_getter
35
+ # PENDING: Not to report telemetry logs for now
34
36
  Datadog.logger.error(
35
37
  "Custom getter #{getter} is not supported. Please inform the `datadog` team at " \
36
38
  ' https://github.com/DataDog/dd-trace-rb of your use case so we can best support you. Using the default ' \
@@ -2,6 +2,7 @@
2
2
 
3
3
  require_relative 'trace/span'
4
4
  require_relative '../../tracing/span_link'
5
+ require_relative '../../tracing/span_event'
5
6
  require_relative '../../tracing/trace_digest'
6
7
 
7
8
  module Datadog
@@ -31,6 +32,15 @@ module Datadog
31
32
  #
32
33
  # @param [Span] span the {Span} that just ended.
33
34
  def on_finish(span)
35
+ unless span.events.nil?
36
+ span.datadog_span.span_events = span.events.map do |event|
37
+ Datadog::Tracing::SpanEvent.new(
38
+ event.name,
39
+ attributes: event.attributes,
40
+ time_unix_nano: event.timestamp
41
+ )
42
+ end
43
+ end
34
44
  span.datadog_span.finish(ns_to_time(span.end_timestamp))
35
45
  end
36
46
 
@@ -15,6 +15,29 @@ module Datadog
15
15
  res
16
16
  end
17
17
 
18
+ # Record an exception during the execution of this span. Multiple exceptions
19
+ # can be recorded on a span.
20
+ #
21
+ # @param [Exception] exception The exception to recorded
22
+ # @param [optional Hash{String => String, Numeric, Boolean, Array<String, Numeric, Boolean>}]
23
+ # attributes One or more key:value pairs, where the keys must be
24
+ # strings and the values may be (array of) string, boolean or numeric
25
+ # type.
26
+ #
27
+ # @return [void]
28
+ def record_exception(exception, attributes: nil)
29
+ res = super
30
+ if (span = datadog_span)
31
+ # Sets the exception attributes as span error tags. The values in the attribute hash MUST
32
+ # take precedence over the type, message and stacktrace inferred from the exception object
33
+ type = attributes&.[]('exception.type') || exception.class.to_s
34
+ message = attributes&.[]('exception.message') || exception.message
35
+ stacktrace = attributes&.[]('exception.stacktrace') || exception.full_message(highlight: false, order: :top)
36
+ span.set_error_tags([type, message, stacktrace])
37
+ end
38
+ res
39
+ end
40
+
18
41
  # `alias` performed to match {OpenTelemetry::SDK::Trace::Span} aliasing upstream
19
42
  alias []= set_attribute
20
43
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'set'
4
- require 'json'
3
+ require "set"
4
+ require "json"
5
5
 
6
6
  module Datadog
7
7
  module Profiling
@@ -14,7 +14,7 @@ module Datadog
14
14
  #
15
15
  # This class acts both as a collector (collecting data) as well as a recorder (records/serializes it)
16
16
  class CodeProvenance
17
- def initialize(standard_library_path: RbConfig::CONFIG.fetch('rubylibdir'))
17
+ def initialize(standard_library_path: RbConfig::CONFIG.fetch("rubylibdir"))
18
18
  @libraries_by_name = {}
19
19
  @libraries_by_path = {}
20
20
  @seen_files = Set.new
@@ -22,8 +22,8 @@ module Datadog
22
22
 
23
23
  record_library(
24
24
  Library.new(
25
- kind: 'standard library',
26
- name: 'stdlib',
25
+ kind: "standard library",
26
+ name: "stdlib",
27
27
  version: RUBY_VERSION,
28
28
  path: standard_library_path,
29
29
  )
@@ -79,7 +79,7 @@ module Datadog
79
79
  loaded_specs.each do |spec|
80
80
  next if libraries_by_name.key?(spec.name)
81
81
 
82
- record_library(Library.new(kind: 'library', name: spec.name, version: spec.version, path: spec.gem_dir))
82
+ record_library(Library.new(kind: "library", name: spec.name, version: spec.version, path: spec.gem_dir))
83
83
  recorded_library = true
84
84
  end
85
85
 
@@ -119,7 +119,7 @@ module Datadog
119
119
  end
120
120
 
121
121
  def to_json(arg = nil)
122
- { kind: @kind, name: @name, version: @version, paths: @paths }.to_json(arg)
122
+ {kind: @kind, name: @name, version: @version, paths: @paths}.to_json(arg)
123
123
  end
124
124
 
125
125
  def path
@@ -21,6 +21,8 @@ module Datadog
21
21
  thread_context_collector:,
22
22
  dynamic_sampling_rate_overhead_target_percentage:,
23
23
  allocation_profiling_enabled:,
24
+ allocation_counting_enabled:,
25
+ gvl_profiling_enabled:,
24
26
  # **NOTE**: This should only be used for testing; disabling the dynamic sampling rate will increase the
25
27
  # profiler overhead!
26
28
  dynamic_sampling_rate_enabled: true,
@@ -29,20 +31,22 @@ module Datadog
29
31
  )
30
32
  unless dynamic_sampling_rate_enabled
31
33
  Datadog.logger.warn(
32
- 'Profiling dynamic sampling rate disabled. This should only be used for testing, and will increase overhead!'
34
+ "Profiling dynamic sampling rate disabled. This should only be used for testing, and will increase overhead!"
33
35
  )
34
36
  end
35
37
 
36
38
  self.class._native_initialize(
37
- self,
38
- thread_context_collector,
39
- gc_profiling_enabled,
40
- idle_sampling_helper,
41
- no_signals_workaround_enabled,
42
- dynamic_sampling_rate_enabled,
43
- dynamic_sampling_rate_overhead_target_percentage,
44
- allocation_profiling_enabled,
45
- skip_idle_samples_for_testing,
39
+ self_instance: self,
40
+ thread_context_collector: thread_context_collector,
41
+ gc_profiling_enabled: gc_profiling_enabled,
42
+ idle_sampling_helper: idle_sampling_helper,
43
+ no_signals_workaround_enabled: no_signals_workaround_enabled,
44
+ dynamic_sampling_rate_enabled: dynamic_sampling_rate_enabled,
45
+ dynamic_sampling_rate_overhead_target_percentage: dynamic_sampling_rate_overhead_target_percentage,
46
+ allocation_profiling_enabled: allocation_profiling_enabled,
47
+ allocation_counting_enabled: allocation_counting_enabled,
48
+ gvl_profiling_enabled: gvl_profiling_enabled,
49
+ skip_idle_samples_for_testing: skip_idle_samples_for_testing,
46
50
  )
47
51
  @worker_thread = nil
48
52
  @failure_exception = nil
@@ -54,27 +58,25 @@ module Datadog
54
58
 
55
59
  def start(on_failure_proc: nil)
56
60
  @start_stop_mutex.synchronize do
57
- return if @worker_thread && @worker_thread.alive?
61
+ return if @worker_thread&.alive?
58
62
 
59
63
  Datadog.logger.debug { "Starting thread for: #{self}" }
60
64
 
61
65
  @idle_sampling_helper.start
62
66
 
63
67
  @worker_thread = Thread.new do
64
- begin
65
- Thread.current.name = self.class.name
66
-
67
- self.class._native_sampling_loop(self)
68
-
69
- Datadog.logger.debug('CpuAndWallTimeWorker thread stopping cleanly')
70
- rescue Exception => e # rubocop:disable Lint/RescueException
71
- @failure_exception = e
72
- Datadog.logger.warn(
73
- 'CpuAndWallTimeWorker thread error. ' \
74
- "Cause: #{e.class.name} #{e.message} Location: #{Array(e.backtrace).first}"
75
- )
76
- on_failure_proc&.call
77
- end
68
+ Thread.current.name = self.class.name
69
+
70
+ self.class._native_sampling_loop(self)
71
+
72
+ Datadog.logger.debug("CpuAndWallTimeWorker thread stopping cleanly")
73
+ rescue Exception => e # rubocop:disable Lint/RescueException
74
+ @failure_exception = e
75
+ Datadog.logger.warn(
76
+ "CpuAndWallTimeWorker thread error. " \
77
+ "Cause: #{e.class.name} #{e.message} Location: #{Array(e.backtrace).first}"
78
+ )
79
+ on_failure_proc&.call
78
80
  end
79
81
  @worker_thread.name = self.class.name # Repeated from above to make sure thread gets named asap
80
82
  @worker_thread.thread_variable_set(:fork_safe, true)
@@ -85,7 +87,7 @@ module Datadog
85
87
 
86
88
  def stop
87
89
  @start_stop_mutex.synchronize do
88
- Datadog.logger.debug('Requesting CpuAndWallTimeWorker thread shut down')
90
+ Datadog.logger.debug("Requesting CpuAndWallTimeWorker thread shut down")
89
91
 
90
92
  @idle_sampling_helper.stop
91
93
 
@@ -21,7 +21,7 @@ module Datadog
21
21
 
22
22
  def start
23
23
  @start_stop_mutex.synchronize do
24
- return if @worker_thread && @worker_thread.alive?
24
+ return if @worker_thread&.alive?
25
25
 
26
26
  Datadog.logger.debug { "Starting thread for: #{self}" }
27
27
 
@@ -30,19 +30,17 @@ module Datadog
30
30
  self.class._native_reset(self)
31
31
 
32
32
  @worker_thread = Thread.new do
33
- begin
34
- Thread.current.name = self.class.name
33
+ Thread.current.name = self.class.name
35
34
 
36
- self.class._native_idle_sampling_loop(self)
35
+ self.class._native_idle_sampling_loop(self)
37
36
 
38
- Datadog.logger.debug('IdleSamplingHelper thread stopping cleanly')
39
- rescue Exception => e # rubocop:disable Lint/RescueException
40
- @failure_exception = e
41
- Datadog.logger.warn(
42
- 'IdleSamplingHelper thread error. ' \
43
- "Cause: #{e.class.name} #{e.message} Location: #{Array(e.backtrace).first}"
44
- )
45
- end
37
+ Datadog.logger.debug("IdleSamplingHelper thread stopping cleanly")
38
+ rescue Exception => e # rubocop:disable Lint/RescueException
39
+ @failure_exception = e
40
+ Datadog.logger.warn(
41
+ "IdleSamplingHelper thread error. " \
42
+ "Cause: #{e.class.name} #{e.message} Location: #{Array(e.backtrace).first}"
43
+ )
46
44
  end
47
45
  @worker_thread.name = self.class.name # Repeated from above to make sure thread gets named asap
48
46
  @worker_thread.thread_variable_set(:fork_safe, true)
@@ -53,7 +51,7 @@ module Datadog
53
51
 
54
52
  def stop
55
53
  @start_stop_mutex.synchronize do
56
- Datadog.logger.debug('Requesting IdleSamplingHelper thread shut down')
54
+ Datadog.logger.debug("Requesting IdleSamplingHelper thread shut down")
57
55
 
58
56
  return unless @worker_thread
59
57
 
@@ -1,7 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'set'
4
- require 'time'
3
+ require "set"
4
+ require "time"
5
+ require "libdatadog"
5
6
 
6
7
  module Datadog
7
8
  module Profiling
@@ -61,12 +62,20 @@ module Datadog
61
62
 
62
63
  def collect_profiler_info(settings)
63
64
  unless @profiler_info
64
- lib_datadog_gem = ::Gem.loaded_specs['libdatadog']
65
+ lib_datadog_gem = ::Gem.loaded_specs["libdatadog"]
66
+
67
+ libdatadog_version =
68
+ if lib_datadog_gem
69
+ "#{lib_datadog_gem.version}-#{lib_datadog_gem.platform}"
70
+ else
71
+ # In some cases, Gem.loaded_specs may not be available, as in
72
+ # https://github.com/DataDog/dd-trace-rb/pull/1506; let's use the version directly
73
+ "#{Libdatadog::VERSION}-(unknown)"
74
+ end
75
+
65
76
  @profiler_info = {
66
- # TODO: If profiling is extracted and its version diverges from the datadog gem, this is inaccurate.
67
- # Update if this ever occurs.
68
77
  version: Datadog::Core::Environment::Identity.gem_datadog_version,
69
- libdatadog: "#{lib_datadog_gem.version}-#{lib_datadog_gem.platform}",
78
+ libdatadog: libdatadog_version,
70
79
  settings: collect_settings_recursively(settings.profiling),
71
80
  }.freeze
72
81
  end
@@ -20,6 +20,8 @@ module Datadog
20
20
  tracer:,
21
21
  endpoint_collection_enabled:,
22
22
  timeline_enabled:,
23
+ waiting_for_gvl_threshold_ns:,
24
+ otel_context_enabled:,
23
25
  allocation_type_enabled: true
24
26
  )
25
27
  tracer_context_key = safely_extract_context_key_from(tracer)
@@ -30,10 +32,34 @@ module Datadog
30
32
  tracer_context_key,
31
33
  endpoint_collection_enabled,
32
34
  timeline_enabled,
35
+ waiting_for_gvl_threshold_ns,
36
+ otel_context_enabled,
33
37
  allocation_type_enabled,
34
38
  )
35
39
  end
36
40
 
41
+ def self.for_testing(
42
+ recorder:,
43
+ max_frames: 400,
44
+ tracer: nil,
45
+ endpoint_collection_enabled: false,
46
+ timeline_enabled: false,
47
+ waiting_for_gvl_threshold_ns: 10_000_000,
48
+ otel_context_enabled: false,
49
+ **options
50
+ )
51
+ new(
52
+ recorder: recorder,
53
+ max_frames: max_frames,
54
+ tracer: tracer,
55
+ endpoint_collection_enabled: endpoint_collection_enabled,
56
+ timeline_enabled: timeline_enabled,
57
+ waiting_for_gvl_threshold_ns: waiting_for_gvl_threshold_ns,
58
+ otel_context_enabled: otel_context_enabled,
59
+ **options,
60
+ )
61
+ end
62
+
37
63
  def inspect
38
64
  # Compose Ruby's default inspect with our custom inspect for the native parts
39
65
  result = super()
@@ -48,12 +74,14 @@ module Datadog
48
74
  private
49
75
 
50
76
  def safely_extract_context_key_from(tracer)
51
- provider = tracer && tracer.respond_to?(:provider) && tracer.provider
77
+ return unless tracer
78
+
79
+ provider = tracer.respond_to?(:provider) && tracer.provider
52
80
 
53
81
  return unless provider
54
82
 
55
83
  context = provider.instance_variable_get(:@context)
56
- context && context.instance_variable_get(:@key)
84
+ context&.instance_variable_get(:@key)
57
85
  end
58
86
  end
59
87
  end