datadog 2.12.1 → 2.17.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 (302) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +154 -2
  3. data/ext/datadog_profiling_native_extension/collectors_thread_context.c +16 -14
  4. data/ext/datadog_profiling_native_extension/datadog_ruby_common.c +1 -4
  5. data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +10 -0
  6. data/ext/datadog_profiling_native_extension/encoded_profile.c +79 -0
  7. data/ext/datadog_profiling_native_extension/encoded_profile.h +8 -0
  8. data/ext/datadog_profiling_native_extension/extconf.rb +3 -0
  9. data/ext/datadog_profiling_native_extension/heap_recorder.c +8 -1
  10. data/ext/datadog_profiling_native_extension/http_transport.c +60 -94
  11. data/ext/datadog_profiling_native_extension/private_vm_api_access.c +8 -0
  12. data/ext/datadog_profiling_native_extension/profiling.c +2 -0
  13. data/ext/datadog_profiling_native_extension/stack_recorder.c +23 -23
  14. data/ext/libdatadog_api/crashtracker.c +11 -12
  15. data/ext/libdatadog_api/crashtracker.h +5 -0
  16. data/ext/libdatadog_api/datadog_ruby_common.c +1 -4
  17. data/ext/libdatadog_api/datadog_ruby_common.h +10 -0
  18. data/ext/libdatadog_api/init.c +15 -0
  19. data/ext/libdatadog_api/library_config.c +122 -0
  20. data/ext/libdatadog_api/library_config.h +19 -0
  21. data/ext/libdatadog_api/macos_development.md +3 -3
  22. data/ext/libdatadog_api/process_discovery.c +117 -0
  23. data/ext/libdatadog_api/process_discovery.h +5 -0
  24. data/ext/libdatadog_extconf_helpers.rb +1 -1
  25. data/lib/datadog/appsec/actions_handler/serializable_backtrace.rb +89 -0
  26. data/lib/datadog/appsec/actions_handler.rb +24 -2
  27. data/lib/datadog/appsec/anonymizer.rb +16 -0
  28. data/lib/datadog/appsec/api_security/lru_cache.rb +49 -0
  29. data/lib/datadog/appsec/api_security.rb +9 -0
  30. data/lib/datadog/appsec/assets/waf_rules/README.md +50 -5
  31. data/lib/datadog/appsec/assets/waf_rules/processors.json +239 -10
  32. data/lib/datadog/appsec/assets/waf_rules/scanners.json +926 -17
  33. data/lib/datadog/appsec/autoload.rb +1 -1
  34. data/lib/datadog/appsec/component.rb +29 -20
  35. data/lib/datadog/appsec/compressed_json.rb +40 -0
  36. data/lib/datadog/appsec/configuration/settings.rb +93 -28
  37. data/lib/datadog/appsec/context.rb +1 -1
  38. data/lib/datadog/appsec/contrib/active_record/instrumentation.rb +10 -12
  39. data/lib/datadog/appsec/contrib/active_record/integration.rb +2 -2
  40. data/lib/datadog/appsec/contrib/active_record/patcher.rb +22 -22
  41. data/lib/datadog/appsec/contrib/auto_instrument.rb +1 -1
  42. data/lib/datadog/appsec/contrib/devise/configuration.rb +7 -31
  43. data/lib/datadog/appsec/contrib/devise/data_extractor.rb +78 -0
  44. data/lib/datadog/appsec/contrib/devise/ext.rb +22 -0
  45. data/lib/datadog/appsec/contrib/devise/integration.rb +1 -2
  46. data/lib/datadog/appsec/contrib/devise/patcher.rb +34 -23
  47. data/lib/datadog/appsec/contrib/devise/patches/signin_tracking_patch.rb +102 -0
  48. data/lib/datadog/appsec/contrib/devise/patches/signup_tracking_patch.rb +69 -0
  49. data/lib/datadog/appsec/contrib/devise/{patcher/rememberable_patch.rb → patches/skip_signin_tracking_patch.rb} +2 -2
  50. data/lib/datadog/appsec/contrib/devise/tracking_middleware.rb +106 -0
  51. data/lib/datadog/appsec/contrib/excon/integration.rb +1 -1
  52. data/lib/datadog/appsec/contrib/excon/ssrf_detection_middleware.rb +9 -10
  53. data/lib/datadog/appsec/contrib/faraday/integration.rb +1 -1
  54. data/lib/datadog/appsec/contrib/faraday/ssrf_detection_middleware.rb +8 -9
  55. data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +8 -9
  56. data/lib/datadog/appsec/contrib/graphql/integration.rb +1 -1
  57. data/lib/datadog/appsec/contrib/rack/ext.rb +34 -0
  58. data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +49 -32
  59. data/lib/datadog/appsec/contrib/rack/integration.rb +1 -1
  60. data/lib/datadog/appsec/contrib/rack/request_middleware.rb +19 -18
  61. data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +11 -13
  62. data/lib/datadog/appsec/contrib/rails/integration.rb +1 -1
  63. data/lib/datadog/appsec/contrib/rails/patcher.rb +21 -21
  64. data/lib/datadog/appsec/contrib/rest_client/integration.rb +1 -1
  65. data/lib/datadog/appsec/contrib/rest_client/request_ssrf_detection_patch.rb +10 -11
  66. data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +17 -23
  67. data/lib/datadog/appsec/contrib/sinatra/integration.rb +1 -1
  68. data/lib/datadog/appsec/event.rb +96 -135
  69. data/lib/datadog/appsec/ext.rb +4 -2
  70. data/lib/datadog/appsec/instrumentation/gateway/argument.rb +7 -2
  71. data/lib/datadog/appsec/instrumentation/gateway/middleware.rb +24 -0
  72. data/lib/datadog/appsec/instrumentation/gateway.rb +17 -22
  73. data/lib/datadog/appsec/metrics/telemetry.rb +1 -1
  74. data/lib/datadog/appsec/monitor/gateway/watcher.rb +49 -14
  75. data/lib/datadog/appsec/processor/rule_loader.rb +26 -28
  76. data/lib/datadog/appsec/processor/rule_merger.rb +7 -6
  77. data/lib/datadog/appsec/processor.rb +1 -1
  78. data/lib/datadog/appsec/remote.rb +23 -11
  79. data/lib/datadog/appsec/response.rb +6 -6
  80. data/lib/datadog/appsec/security_engine/runner.rb +3 -3
  81. data/lib/datadog/appsec/security_event.rb +39 -0
  82. data/lib/datadog/appsec/utils.rb +0 -2
  83. data/lib/datadog/appsec.rb +1 -1
  84. data/lib/datadog/core/buffer/random.rb +18 -2
  85. data/lib/datadog/core/configuration/agent_settings_resolver.rb +5 -5
  86. data/lib/datadog/core/configuration/agentless_settings_resolver.rb +176 -0
  87. data/lib/datadog/core/configuration/components.rb +50 -31
  88. data/lib/datadog/core/configuration/components_state.rb +23 -0
  89. data/lib/datadog/core/configuration/ext.rb +4 -0
  90. data/lib/datadog/core/configuration/option.rb +79 -43
  91. data/lib/datadog/core/configuration/option_definition.rb +4 -4
  92. data/lib/datadog/core/configuration/options.rb +3 -3
  93. data/lib/datadog/core/configuration/settings.rb +68 -35
  94. data/lib/datadog/core/configuration/stable_config.rb +23 -0
  95. data/lib/datadog/core/configuration.rb +40 -16
  96. data/lib/datadog/core/crashtracking/component.rb +3 -10
  97. data/lib/datadog/core/diagnostics/environment_logger.rb +1 -1
  98. data/lib/datadog/core/encoding.rb +1 -1
  99. data/lib/datadog/core/environment/agent_info.rb +4 -3
  100. data/lib/datadog/core/environment/cgroup.rb +10 -12
  101. data/lib/datadog/core/environment/container.rb +38 -40
  102. data/lib/datadog/core/environment/ext.rb +6 -6
  103. data/lib/datadog/core/environment/git.rb +1 -0
  104. data/lib/datadog/core/environment/identity.rb +3 -3
  105. data/lib/datadog/core/environment/platform.rb +3 -3
  106. data/lib/datadog/core/environment/variable_helpers.rb +1 -1
  107. data/lib/datadog/core/error.rb +11 -9
  108. data/lib/datadog/core/logger.rb +2 -2
  109. data/lib/datadog/core/metrics/client.rb +20 -21
  110. data/lib/datadog/core/metrics/logging.rb +5 -5
  111. data/lib/datadog/core/process_discovery.rb +32 -0
  112. data/lib/datadog/core/rate_limiter.rb +4 -2
  113. data/lib/datadog/core/remote/client.rb +40 -32
  114. data/lib/datadog/core/remote/component.rb +6 -9
  115. data/lib/datadog/core/remote/configuration/digest.rb +7 -7
  116. data/lib/datadog/core/remote/configuration/path.rb +1 -1
  117. data/lib/datadog/core/remote/configuration/repository.rb +2 -1
  118. data/lib/datadog/core/remote/negotiation.rb +9 -9
  119. data/lib/datadog/core/remote/transport/config.rb +4 -3
  120. data/lib/datadog/core/remote/transport/http/client.rb +5 -4
  121. data/lib/datadog/core/remote/transport/http/config.rb +27 -37
  122. data/lib/datadog/core/remote/transport/http/negotiation.rb +7 -33
  123. data/lib/datadog/core/remote/transport/http.rb +22 -57
  124. data/lib/datadog/core/remote/transport/negotiation.rb +4 -3
  125. data/lib/datadog/core/runtime/metrics.rb +12 -5
  126. data/lib/datadog/core/telemetry/component.rb +78 -53
  127. data/lib/datadog/core/telemetry/emitter.rb +23 -11
  128. data/lib/datadog/core/telemetry/event/app_client_configuration_change.rb +65 -0
  129. data/lib/datadog/core/telemetry/event/app_closing.rb +18 -0
  130. data/lib/datadog/core/telemetry/event/app_dependencies_loaded.rb +33 -0
  131. data/lib/datadog/core/telemetry/event/app_heartbeat.rb +18 -0
  132. data/lib/datadog/core/telemetry/event/app_integrations_change.rb +58 -0
  133. data/lib/datadog/core/telemetry/event/app_started.rb +179 -0
  134. data/lib/datadog/core/telemetry/event/base.rb +40 -0
  135. data/lib/datadog/core/telemetry/event/distributions.rb +18 -0
  136. data/lib/datadog/core/telemetry/event/generate_metrics.rb +43 -0
  137. data/lib/datadog/core/telemetry/event/log.rb +76 -0
  138. data/lib/datadog/core/telemetry/event/message_batch.rb +42 -0
  139. data/lib/datadog/core/telemetry/event/synth_app_client_configuration_change.rb +43 -0
  140. data/lib/datadog/core/telemetry/event.rb +17 -472
  141. data/lib/datadog/core/telemetry/http/adapters/net.rb +12 -97
  142. data/lib/datadog/core/telemetry/logger.rb +1 -1
  143. data/lib/datadog/core/telemetry/metric.rb +8 -8
  144. data/lib/datadog/core/telemetry/request.rb +4 -4
  145. data/lib/datadog/core/telemetry/transport/http/api.rb +43 -0
  146. data/lib/datadog/core/telemetry/transport/http/client.rb +49 -0
  147. data/lib/datadog/core/telemetry/transport/http/telemetry.rb +92 -0
  148. data/lib/datadog/core/telemetry/transport/http.rb +63 -0
  149. data/lib/datadog/core/telemetry/transport/telemetry.rb +51 -0
  150. data/lib/datadog/core/telemetry/worker.rb +90 -24
  151. data/lib/datadog/core/transport/http/adapters/test.rb +2 -1
  152. data/lib/datadog/core/transport/http/api/instance.rb +17 -0
  153. data/lib/datadog/core/transport/http/api/spec.rb +17 -0
  154. data/lib/datadog/core/transport/http/builder.rb +18 -16
  155. data/lib/datadog/core/transport/http.rb +39 -2
  156. data/lib/datadog/core/utils/at_fork_monkey_patch.rb +6 -6
  157. data/lib/datadog/core/utils/duration.rb +32 -32
  158. data/lib/datadog/core/utils/forking.rb +2 -2
  159. data/lib/datadog/core/utils/network.rb +6 -6
  160. data/lib/datadog/core/utils/only_once_successful.rb +16 -5
  161. data/lib/datadog/core/utils/time.rb +20 -0
  162. data/lib/datadog/core/utils/truncation.rb +21 -0
  163. data/lib/datadog/core/vendor/multipart-post/multipart/post/composite_read_io.rb +1 -1
  164. data/lib/datadog/core/vendor/multipart-post/multipart/post/multipartable.rb +8 -8
  165. data/lib/datadog/core/vendor/multipart-post/multipart/post/parts.rb +7 -7
  166. data/lib/datadog/core/worker.rb +1 -1
  167. data/lib/datadog/core/workers/async.rb +29 -12
  168. data/lib/datadog/core/workers/interval_loop.rb +12 -1
  169. data/lib/datadog/core/workers/runtime_metrics.rb +2 -2
  170. data/lib/datadog/core.rb +8 -0
  171. data/lib/datadog/di/boot.rb +34 -0
  172. data/lib/datadog/di/component.rb +0 -2
  173. data/lib/datadog/di/probe_notification_builder.rb +1 -1
  174. data/lib/datadog/di/probe_notifier_worker.rb +16 -16
  175. data/lib/datadog/di/remote.rb +2 -0
  176. data/lib/datadog/di/transport/diagnostics.rb +4 -3
  177. data/lib/datadog/di/transport/http/api.rb +2 -12
  178. data/lib/datadog/di/transport/http/client.rb +4 -3
  179. data/lib/datadog/di/transport/http/diagnostics.rb +7 -34
  180. data/lib/datadog/di/transport/http/input.rb +7 -34
  181. data/lib/datadog/di/transport/http.rb +14 -62
  182. data/lib/datadog/di/transport/input.rb +4 -3
  183. data/lib/datadog/di/utils.rb +5 -0
  184. data/lib/datadog/di.rb +5 -32
  185. data/lib/datadog/error_tracking/collector.rb +87 -0
  186. data/lib/datadog/error_tracking/component.rb +167 -0
  187. data/lib/datadog/error_tracking/configuration/settings.rb +63 -0
  188. data/lib/datadog/error_tracking/configuration.rb +11 -0
  189. data/lib/datadog/error_tracking/ext.rb +18 -0
  190. data/lib/datadog/error_tracking/extensions.rb +16 -0
  191. data/lib/datadog/error_tracking/filters.rb +77 -0
  192. data/lib/datadog/error_tracking.rb +18 -0
  193. data/lib/datadog/kit/appsec/events.rb +12 -0
  194. data/lib/datadog/kit/identity.rb +5 -1
  195. data/lib/datadog/opentelemetry/api/baggage.rb +90 -0
  196. data/lib/datadog/opentelemetry/api/baggage.rbs +26 -0
  197. data/lib/datadog/opentelemetry/api/context.rb +16 -2
  198. data/lib/datadog/opentelemetry/sdk/trace/span.rb +1 -1
  199. data/lib/datadog/opentelemetry.rb +2 -1
  200. data/lib/datadog/profiling/collectors/code_provenance.rb +1 -1
  201. data/lib/datadog/profiling/collectors/info.rb +3 -0
  202. data/lib/datadog/profiling/collectors/thread_context.rb +1 -1
  203. data/lib/datadog/profiling/encoded_profile.rb +11 -0
  204. data/lib/datadog/profiling/exporter.rb +3 -4
  205. data/lib/datadog/profiling/ext.rb +0 -2
  206. data/lib/datadog/profiling/flush.rb +5 -8
  207. data/lib/datadog/profiling/http_transport.rb +5 -59
  208. data/lib/datadog/profiling/scheduler.rb +8 -1
  209. data/lib/datadog/profiling/stack_recorder.rb +4 -4
  210. data/lib/datadog/profiling/tag_builder.rb +1 -5
  211. data/lib/datadog/profiling.rb +6 -2
  212. data/lib/datadog/tracing/analytics.rb +1 -1
  213. data/lib/datadog/tracing/component.rb +15 -12
  214. data/lib/datadog/tracing/configuration/ext.rb +7 -1
  215. data/lib/datadog/tracing/configuration/settings.rb +18 -2
  216. data/lib/datadog/tracing/context_provider.rb +1 -1
  217. data/lib/datadog/tracing/contrib/active_record/integration.rb +1 -1
  218. data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +4 -1
  219. data/lib/datadog/tracing/contrib/active_support/cache/instrumentation.rb +33 -0
  220. data/lib/datadog/tracing/contrib/active_support/cache/patcher.rb +4 -0
  221. data/lib/datadog/tracing/contrib/active_support/cache/redis.rb +2 -4
  222. data/lib/datadog/tracing/contrib/aws/instrumentation.rb +10 -0
  223. data/lib/datadog/tracing/contrib/aws/parsed_context.rb +5 -1
  224. data/lib/datadog/tracing/contrib/configuration/settings.rb +1 -1
  225. data/lib/datadog/tracing/contrib/ethon/easy_patch.rb +4 -5
  226. data/lib/datadog/tracing/contrib/excon/middleware.rb +5 -3
  227. data/lib/datadog/tracing/contrib/ext.rb +1 -0
  228. data/lib/datadog/tracing/contrib/faraday/middleware.rb +5 -3
  229. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/client.rb +7 -1
  230. data/lib/datadog/tracing/contrib/grpc/distributed/propagation.rb +3 -0
  231. data/lib/datadog/tracing/contrib/http/circuit_breaker.rb +0 -15
  232. data/lib/datadog/tracing/contrib/http/distributed/propagation.rb +4 -1
  233. data/lib/datadog/tracing/contrib/http/instrumentation.rb +6 -10
  234. data/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +6 -16
  235. data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +7 -15
  236. data/lib/datadog/tracing/contrib/karafka/configuration/settings.rb +27 -0
  237. data/lib/datadog/tracing/contrib/karafka/distributed/propagation.rb +48 -0
  238. data/lib/datadog/tracing/contrib/karafka/ext.rb +27 -0
  239. data/lib/datadog/tracing/contrib/karafka/integration.rb +45 -0
  240. data/lib/datadog/tracing/contrib/karafka/monitor.rb +66 -0
  241. data/lib/datadog/tracing/contrib/karafka/patcher.rb +71 -0
  242. data/lib/datadog/tracing/contrib/karafka.rb +37 -0
  243. data/lib/datadog/tracing/contrib/mongodb/configuration/settings.rb +8 -0
  244. data/lib/datadog/tracing/contrib/mongodb/ext.rb +1 -0
  245. data/lib/datadog/tracing/contrib/mongodb/subscribers.rb +18 -1
  246. data/lib/datadog/tracing/contrib/opensearch/configuration/settings.rb +17 -0
  247. data/lib/datadog/tracing/contrib/opensearch/ext.rb +9 -0
  248. data/lib/datadog/tracing/contrib/opensearch/patcher.rb +5 -1
  249. data/lib/datadog/tracing/contrib/patcher.rb +5 -2
  250. data/lib/datadog/tracing/contrib/rack/request_queue.rb +1 -1
  251. data/lib/datadog/tracing/contrib/rest_client/request_patch.rb +5 -3
  252. data/lib/datadog/tracing/contrib/sidekiq/client_tracer.rb +6 -1
  253. data/lib/datadog/tracing/contrib/sidekiq/distributed/propagation.rb +3 -0
  254. data/lib/datadog/tracing/contrib/sidekiq/server_tracer.rb +1 -1
  255. data/lib/datadog/tracing/contrib/support.rb +28 -0
  256. data/lib/datadog/tracing/contrib.rb +1 -0
  257. data/lib/datadog/tracing/correlation.rb +9 -2
  258. data/lib/datadog/tracing/distributed/b3_multi.rb +1 -1
  259. data/lib/datadog/tracing/distributed/b3_single.rb +1 -1
  260. data/lib/datadog/tracing/distributed/baggage.rb +131 -0
  261. data/lib/datadog/tracing/distributed/datadog.rb +4 -2
  262. data/lib/datadog/tracing/distributed/propagation.rb +25 -4
  263. data/lib/datadog/tracing/distributed/propagation_policy.rb +42 -0
  264. data/lib/datadog/tracing/metadata/errors.rb +4 -4
  265. data/lib/datadog/tracing/metadata/ext.rb +5 -0
  266. data/lib/datadog/tracing/metadata/metastruct.rb +36 -0
  267. data/lib/datadog/tracing/metadata/metastruct_tagging.rb +42 -0
  268. data/lib/datadog/tracing/metadata.rb +2 -0
  269. data/lib/datadog/tracing/sampling/rate_sampler.rb +2 -1
  270. data/lib/datadog/tracing/sampling/span/rule.rb +0 -1
  271. data/lib/datadog/tracing/span.rb +10 -1
  272. data/lib/datadog/tracing/span_event.rb +1 -1
  273. data/lib/datadog/tracing/span_operation.rb +46 -16
  274. data/lib/datadog/tracing/sync_writer.rb +1 -2
  275. data/lib/datadog/tracing/trace_digest.rb +9 -2
  276. data/lib/datadog/tracing/trace_operation.rb +44 -24
  277. data/lib/datadog/tracing/trace_segment.rb +6 -4
  278. data/lib/datadog/tracing/tracer.rb +45 -5
  279. data/lib/datadog/tracing/transport/http/api.rb +2 -10
  280. data/lib/datadog/tracing/transport/http/client.rb +5 -4
  281. data/lib/datadog/tracing/transport/http/traces.rb +13 -41
  282. data/lib/datadog/tracing/transport/http.rb +11 -44
  283. data/lib/datadog/tracing/transport/serializable_trace.rb +3 -1
  284. data/lib/datadog/tracing/transport/trace_formatter.rb +7 -0
  285. data/lib/datadog/tracing/transport/traces.rb +26 -9
  286. data/lib/datadog/tracing/utils.rb +1 -1
  287. data/lib/datadog/tracing/workers/trace_writer.rb +2 -6
  288. data/lib/datadog/tracing/writer.rb +2 -6
  289. data/lib/datadog/tracing.rb +16 -3
  290. data/lib/datadog/version.rb +2 -2
  291. data/lib/datadog.rb +2 -3
  292. metadata +80 -19
  293. data/lib/datadog/appsec/contrib/devise/event.rb +0 -54
  294. data/lib/datadog/appsec/contrib/devise/patcher/authenticatable_patch.rb +0 -72
  295. data/lib/datadog/appsec/contrib/devise/patcher/registration_controller_patch.rb +0 -47
  296. data/lib/datadog/appsec/contrib/devise/resource.rb +0 -35
  297. data/lib/datadog/appsec/contrib/devise/tracking.rb +0 -57
  298. data/lib/datadog/appsec/utils/trace_operation.rb +0 -15
  299. data/lib/datadog/core/telemetry/http/env.rb +0 -20
  300. data/lib/datadog/core/telemetry/http/ext.rb +0 -28
  301. data/lib/datadog/core/telemetry/http/response.rb +0 -70
  302. data/lib/datadog/core/telemetry/http/transport.rb +0 -90
@@ -1,181 +1,142 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'json'
4
- require 'zlib'
5
-
6
4
  require_relative 'rate_limiter'
7
- require_relative '../core/utils/base64'
5
+ require_relative 'compressed_json'
8
6
 
9
7
  module Datadog
10
8
  module AppSec
11
9
  # AppSec event
12
10
  module Event
11
+ DERIVATIVE_SCHEMA_KEY_PREFIX = '_dd.appsec.s.'
12
+ DERIVATIVE_SCHEMA_MAX_COMPRESSED_SIZE = 25000
13
13
  ALLOWED_REQUEST_HEADERS = %w[
14
- X-Forwarded-For
15
- X-Client-IP
16
- X-Real-IP
17
- X-Forwarded
18
- X-Cluster-Client-IP
19
- Forwarded-For
20
- Forwarded
21
- Via
22
- True-Client-IP
23
- Content-Length
24
- Content-Type
25
- Content-Encoding
26
- Content-Language
27
- Host
28
- User-Agent
29
- Accept
30
- Accept-Encoding
31
- Accept-Language
32
- ].map!(&:downcase).freeze
14
+ x-forwarded-for
15
+ x-client-ip
16
+ x-real-ip
17
+ x-forwarded
18
+ x-cluster-client-ip
19
+ forwarded-for
20
+ forwarded
21
+ via
22
+ true-client-ip
23
+ content-length
24
+ content-type
25
+ content-encoding
26
+ content-language
27
+ host
28
+ user-agent
29
+ accept
30
+ accept-encoding
31
+ accept-language
32
+ ].freeze
33
33
 
34
34
  ALLOWED_RESPONSE_HEADERS = %w[
35
- Content-Length
36
- Content-Type
37
- Content-Encoding
38
- Content-Language
39
- ].map!(&:downcase).freeze
40
-
41
- MAX_ENCODED_SCHEMA_SIZE = 25000
42
- # For more information about this number
43
- # please check https://github.com/DataDog/dd-trace-rb/pull/3177#issuecomment-1747221082
44
- MIN_SCHEMA_SIZE_FOR_COMPRESSION = 260
45
-
46
- # Record events for a trace
47
- #
48
- # This is expected to be called only once per trace for the rate limiter
49
- # to properly apply
50
- class << self
51
- def record(span, *events)
52
- # ensure rate limiter is called only when there are events to record
53
- return if events.empty? || span.nil?
35
+ content-length
36
+ content-type
37
+ content-encoding
38
+ content-language
39
+ ].freeze
54
40
 
55
- Datadog::AppSec::RateLimiter.thread_local.limit do
56
- record_via_span(span, *events)
57
- end
58
- end
41
+ class << self
42
+ def tag_and_keep!(context, waf_result)
43
+ # We want to keep the trace in case of security event
44
+ context.trace&.keep!
59
45
 
60
- def record_via_span(span, *events)
61
- events.group_by { |e| e[:trace] }.each do |trace, event_group|
62
- unless trace
63
- Datadog.logger.debug { "{ error: 'no trace: cannot record', event_group: #{event_group.inspect}}" }
64
- next
46
+ if context.span
47
+ if waf_result.actions.key?('block_request') || waf_result.actions.key?('redirect_request')
48
+ context.span.set_tag('appsec.blocked', 'true')
65
49
  end
66
50
 
67
- trace.keep!
68
- trace.set_tag(
69
- Datadog::Tracing::Metadata::Ext::Distributed::TAG_DECISION_MAKER,
70
- Datadog::Tracing::Sampling::Ext::Decision::ASM
71
- )
72
-
73
- # prepare and gather tags to apply
74
- service_entry_tags = build_service_entry_tags(event_group)
75
-
76
- # apply tags to service entry span
77
- service_entry_tags.each do |key, value|
78
- span.set_tag(key, value)
79
- end
51
+ context.span.set_tag('appsec.event', 'true')
80
52
  end
53
+
54
+ add_distributed_tags(context.trace)
81
55
  end
82
56
 
83
- # rubocop:disable Metrics/MethodLength
84
- def build_service_entry_tags(event_group)
85
- waf_events = []
86
- entry_tags = event_group.each_with_object({ '_dd.origin' => 'appsec' }) do |event, tags|
87
- # TODO: assume HTTP request context for now
88
- if (request = event[:request])
89
- request.headers.each do |header, value|
90
- tags["http.request.headers.#{header}"] = value if ALLOWED_REQUEST_HEADERS.include?(header.downcase)
57
+ def record(context, request: nil, response: nil)
58
+ return if context.events.empty? || context.span.nil?
59
+
60
+ Datadog::AppSec::RateLimiter.thread_local.limit do
61
+ context.events.group_by(&:trace).each do |trace, event_group|
62
+ unless trace
63
+ next Datadog.logger.debug do
64
+ "AppSec: Cannot record event group with #{event_group.count} events because it has no trace"
65
+ end
91
66
  end
92
67
 
93
- tags['http.host'] = request.host
94
- tags['http.useragent'] = request.user_agent
95
- tags['network.client.ip'] = request.remote_addr
96
- end
68
+ if event_group.any? { |event| event.attack? || event.schema? }
69
+ trace.keep!
70
+ trace[Tracing::Metadata::Ext::Distributed::TAG_DECISION_MAKER] = Tracing::Sampling::Ext::Decision::ASM
97
71
 
98
- if (response = event[:response])
99
- response.headers.each do |header, value|
100
- tags["http.response.headers.#{header}"] = value if ALLOWED_RESPONSE_HEADERS.include?(header.downcase)
72
+ context.span['_dd.origin'] = 'appsec'
73
+ context.span.set_tags(request_tags(request)) if request
74
+ context.span.set_tags(response_tags(response)) if response
101
75
  end
76
+
77
+ context.span.set_tags(waf_tags(event_group))
102
78
  end
79
+ end
80
+ end
103
81
 
104
- waf_result = event[:waf_result]
105
- # accumulate triggers
106
- waf_events += waf_result.events
82
+ private
107
83
 
108
- waf_result.derivatives.each do |key, value|
109
- parsed_value = json_parse(value)
110
- next unless parsed_value
84
+ def request_tags(request)
85
+ tags = {}
111
86
 
112
- parsed_value_size = parsed_value.size
87
+ tags['http.host'] = request.host if request.host
88
+ tags['http.useragent'] = request.user_agent if request.user_agent
89
+ tags['network.client.ip'] = request.remote_addr if request.remote_addr
113
90
 
114
- schema_value = if parsed_value_size >= MIN_SCHEMA_SIZE_FOR_COMPRESSION
115
- compressed_and_base64_encoded(parsed_value)
116
- else
117
- parsed_value
118
- end
119
- next unless schema_value
91
+ request.headers.each_with_object(tags) do |(name, value), memo|
92
+ next unless ALLOWED_REQUEST_HEADERS.include?(name)
120
93
 
121
- if schema_value.size >= MAX_ENCODED_SCHEMA_SIZE
122
- Datadog.logger.debug do
123
- "Schema key: #{key} exceeds the max size value. It will not be included as part of the span tags"
124
- end
125
- next
126
- end
94
+ memo["http.request.headers.#{name}"] = value
95
+ end
96
+ end
127
97
 
128
- tags[key] = schema_value
129
- end
98
+ def response_tags(response)
99
+ response.headers.each_with_object({}) do |(name, value), memo|
100
+ next unless ALLOWED_RESPONSE_HEADERS.include?(name)
130
101
 
131
- tags
102
+ memo["http.response.headers.#{name}"] = value
132
103
  end
133
-
134
- appsec_events = json_parse({ triggers: waf_events })
135
- entry_tags['_dd.appsec.json'] = appsec_events if appsec_events
136
- entry_tags
137
104
  end
138
- # rubocop:enable Metrics/MethodLength
139
105
 
140
- def tag_and_keep!(context, waf_result)
141
- # We want to keep the trace in case of security event
142
- context.trace.keep! if context.trace
106
+ def waf_tags(security_events)
107
+ triggers = []
143
108
 
144
- if context.span
145
- context.span.set_tag('appsec.blocked', 'true') if waf_result.actions.key?('block_request')
146
- context.span.set_tag('appsec.event', 'true')
147
- end
109
+ tags = security_events.each_with_object({}) do |security_event, memo|
110
+ triggers.concat(security_event.waf_result.events)
148
111
 
149
- add_distributed_tags(context.trace)
150
- end
112
+ security_event.waf_result.derivatives.each do |key, value|
113
+ next memo[key] = value unless key.start_with?(DERIVATIVE_SCHEMA_KEY_PREFIX)
151
114
 
152
- private
115
+ value = CompressedJson.dump(value)
116
+ next if value.nil?
117
+
118
+ if value.size >= DERIVATIVE_SCHEMA_MAX_COMPRESSED_SIZE
119
+ Datadog.logger.debug { "AppSec: Schema key '#{key}' will not be included into span tags due to it's size" }
120
+ next
121
+ end
153
122
 
154
- def compressed_and_base64_encoded(value)
155
- Datadog::Core::Utils::Base64.strict_encode64(gzip(value))
156
- rescue TypeError => e
157
- Datadog.logger.debug do
158
- "Failed to compress and encode value when populating AppSec::Event. Error: #{e.message}"
123
+ memo[key] = value
124
+ end
159
125
  end
160
- nil
126
+
127
+ tags['_dd.appsec.json'] = json_parse({triggers: triggers}) unless triggers.empty?
128
+ tags
161
129
  end
162
130
 
131
+ # NOTE: Handling of Encoding::UndefinedConversionError is added as a quick fix to
132
+ # the issue between Ruby encoded strings and libddwaf produced events and now
133
+ # is under investigation.
163
134
  def json_parse(value)
164
135
  JSON.dump(value)
165
- rescue ArgumentError => e
166
- Datadog.logger.debug do
167
- "Failed to parse value to JSON when populating AppSec::Event. Error: #{e.message}"
168
- end
169
- nil
170
- end
136
+ rescue ArgumentError, Encoding::UndefinedConversionError, JSON::JSONError => e
137
+ AppSec.telemetry.report(e, description: 'AppSec: Failed to convert value into JSON')
171
138
 
172
- def gzip(value)
173
- sio = StringIO.new
174
- # For an in depth comparison of Zlib options check https://github.com/DataDog/dd-trace-rb/pull/3177#issuecomment-1747215473
175
- gz = Zlib::GzipWriter.new(sio, Zlib::BEST_SPEED, Zlib::DEFAULT_STRATEGY)
176
- gz.write(value)
177
- gz.close
178
- sio.string
139
+ nil
179
140
  end
180
141
 
181
142
  # Propagate to downstream services the information that the current distributed trace is
@@ -187,7 +148,7 @@ module Datadog
187
148
  Datadog::Tracing::Metadata::Ext::Distributed::TAG_DECISION_MAKER,
188
149
  Datadog::Tracing::Sampling::Ext::Decision::ASM
189
150
  )
190
- trace.set_tag(Datadog::AppSec::Ext::TAG_DISTRIBUTED_APPSEC_EVENT, '1')
151
+ trace.set_distributed_source(Datadog::AppSec::Ext::PRODUCT_BIT)
191
152
  end
192
153
  end
193
154
  end
@@ -7,13 +7,15 @@ module Datadog
7
7
  RASP_LFI = 'lfi'
8
8
  RASP_SSRF = 'ssrf'
9
9
 
10
+ PRODUCT_BIT = 0b00000010
11
+
10
12
  INTERRUPT = :datadog_appsec_interrupt
11
13
  CONTEXT_KEY = 'datadog.appsec.context'
12
14
  ACTIVE_CONTEXT_KEY = :datadog_appsec_active_context
15
+ EXPLOIT_PREVENTION_EVENT_CATEGORY = 'exploit'
13
16
 
14
17
  TAG_APPSEC_ENABLED = '_dd.appsec.enabled'
15
- TAG_APM_ENABLED = '_dd.apm.enabled'
16
- TAG_DISTRIBUTED_APPSEC_EVENT = '_dd.p.appsec'
18
+ TAG_METASTRUCT_STACK_TRACE = '_dd.stack'
17
19
 
18
20
  TELEMETRY_METRICS_NAMESPACE = 'appsec'
19
21
  end
@@ -8,12 +8,17 @@ module Datadog
8
8
  class Argument; end # rubocop:disable Lint/EmptyClass
9
9
 
10
10
  # Gateway User argument
11
+ # NOTE: This class is a subject of elimination and will be removed when
12
+ # the event system is refactored.
11
13
  class User < Argument
12
- attr_reader :id
14
+ attr_reader :id, :login, :session_id
13
15
 
14
- def initialize(id)
16
+ def initialize(id, login = nil, session_id = nil)
15
17
  super()
18
+
16
19
  @id = id
20
+ @login = login
21
+ @session_id = session_id
17
22
  end
18
23
  end
19
24
  end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Datadog
4
+ module AppSec
5
+ module Instrumentation
6
+ class Gateway
7
+ # NOTE: This class extracted as-is and will be deprecated
8
+ # Instrumentation gateway middleware
9
+ class Middleware
10
+ attr_reader :key, :block
11
+
12
+ def initialize(key, &block)
13
+ @key = key
14
+ @block = block
15
+ end
16
+
17
+ def call(stack, env)
18
+ @block.call(stack, env)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -1,35 +1,29 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'gateway/middleware'
4
+
3
5
  module Datadog
4
6
  module AppSec
5
7
  # Instrumentation for AppSec
6
8
  module Instrumentation
7
9
  # Instrumentation gateway implementation
8
10
  class Gateway
9
- # Instrumentation gateway middleware
10
- class Middleware
11
- attr_reader :key, :block
12
-
13
- def initialize(key, &block)
14
- @key = key
15
- @block = block
16
- end
17
-
18
- def call(stack, env)
19
- @block.call(stack, env)
20
- end
21
- end
22
-
23
- private_constant :Middleware
24
-
25
11
  def initialize
26
12
  @middlewares = Hash.new { |h, k| h[k] = [] }
13
+ @pushed_events = {}
27
14
  end
28
15
 
16
+ # NOTE: Be careful with pushed names because every pushed event name
17
+ # is recorded in order to provide an ability to any subscriber
18
+ # to check wether an arbitrary event had happened.
19
+ #
20
+ # WARNING: If we start pushing generated names we should consider
21
+ # limiting the storage of pushed names.
29
22
  def push(name, env, &block)
30
- block ||= -> {}
23
+ @pushed_events[name] = true
31
24
 
32
- middlewares_for_name = middlewares[name]
25
+ block ||= -> {}
26
+ middlewares_for_name = @middlewares[name]
33
27
 
34
28
  return [block.call, nil] if middlewares_for_name.empty?
35
29
 
@@ -48,14 +42,15 @@ module Datadog
48
42
  end
49
43
 
50
44
  def watch(name, key, &block)
51
- @middlewares[name] << Middleware.new(key, &block) unless middlewares[name].any? { |m| m.key == key }
45
+ @middlewares[name] << Middleware.new(key, &block) unless @middlewares[name].any? { |m| m.key == key }
52
46
  end
53
47
 
54
- private
55
-
56
- attr_reader :middlewares
48
+ def pushed?(name)
49
+ @pushed_events.key?(name)
50
+ end
57
51
  end
58
52
 
53
+ # NOTE: This left as-is and will be depricated soon.
59
54
  def self.gateway
60
55
  @gateway ||= Gateway.new # TODO: not thread safe
61
56
  end
@@ -10,7 +10,7 @@ module Datadog
10
10
  def report_rasp(type, result)
11
11
  return if result.is_a?(SecurityEngine::Result::Error)
12
12
 
13
- tags = { rule_type: type, waf_version: Datadog::AppSec::WAF::VERSION::BASE_STRING }
13
+ tags = {rule_type: type, waf_version: Datadog::AppSec::WAF::VERSION::BASE_STRING}
14
14
  namespace = Ext::TELEMETRY_METRICS_NAMESPACE
15
15
 
16
16
  AppSec.telemetry.inc(namespace, 'rasp.rule.eval', 1, tags: tags)
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative '../../event'
4
+ require_relative '../../security_event'
3
5
  require_relative '../../instrumentation/gateway'
4
6
 
5
7
  module Datadog
@@ -8,38 +10,71 @@ module Datadog
8
10
  module Gateway
9
11
  # Watcher for Apssec internal events
10
12
  module Watcher
13
+ ARBITRARY_VALUE = 'invalid'
14
+ EVENT_LOGIN_SUCCESS = 'users.login.success'
15
+ EVENT_LOGIN_FAILURE = 'users.login.failure'
16
+ WATCHED_LOGIN_EVENTS = [EVENT_LOGIN_SUCCESS, EVENT_LOGIN_FAILURE].freeze
17
+
11
18
  class << self
12
19
  def watch
13
20
  gateway = Instrumentation.gateway
14
21
 
15
22
  watch_user_id(gateway)
23
+ watch_user_login(gateway)
16
24
  end
17
25
 
18
26
  def watch_user_id(gateway = Instrumentation.gateway)
19
27
  gateway.watch('identity.set_user', :appsec) do |stack, user|
20
- context = Datadog::AppSec.active_context
28
+ context = AppSec.active_context
29
+
30
+ if user.id.nil? && user.login.nil? && user.session_id.nil?
31
+ Datadog.logger.debug { 'AppSec: skipping WAF check because no user information was provided' }
32
+ next stack.call(user)
33
+ end
21
34
 
22
- persistent_data = {
23
- 'usr.id' => user.id
24
- }
35
+ persistent_data = {}
36
+ persistent_data['usr.id'] = user.id if user.id
37
+ persistent_data['usr.login'] = user.login if user.login
38
+ persistent_data['usr.session_id'] = user.session_id if user.session_id
25
39
 
26
40
  result = context.run_waf(persistent_data, {}, Datadog.configuration.appsec.waf_timeout)
27
41
 
42
+ if result.match? || result.derivatives.any?
43
+ context.events.push(
44
+ AppSec::SecurityEvent.new(result, trace: context.trace, span: context.span)
45
+ )
46
+ end
47
+
28
48
  if result.match?
29
- Datadog::AppSec::Event.tag_and_keep!(context, result)
49
+ AppSec::Event.tag_and_keep!(context, result)
50
+ AppSec::ActionsHandler.handle(result.actions)
51
+ end
30
52
 
31
- context.events << {
32
- waf_result: result,
33
- trace: context.trace,
34
- span: context.span,
35
- user: user,
36
- actions: result.actions
37
- }
53
+ stack.call(user)
54
+ end
55
+ end
38
56
 
39
- Datadog::AppSec::ActionsHandler.handle(result.actions)
57
+ def watch_user_login(gateway = Instrumentation.gateway)
58
+ gateway.watch('appsec.events.user_lifecycle', :appsec) do |stack, kind|
59
+ context = AppSec.active_context
60
+
61
+ next stack.call(kind) unless WATCHED_LOGIN_EVENTS.include?(kind)
62
+
63
+ persistent_data = {"server.business_logic.#{kind}" => ARBITRARY_VALUE}
64
+ result = context.run_waf(persistent_data, {}, Datadog.configuration.appsec.waf_timeout)
65
+
66
+ if result.match? || result.derivatives.any?
67
+ context.events.push(
68
+ AppSec::SecurityEvent.new(result, trace: context.trace, span: context.span)
69
+ )
40
70
  end
41
71
 
42
- stack.call(user)
72
+ if result.match?
73
+ AppSec::Event.tag_and_keep!(context, result)
74
+ AppSec::ActionsHandler.handle(result.actions)
75
+ end
76
+
77
+ stack.call(kind)
43
78
  end
44
79
  end
45
80
  end
@@ -10,35 +10,33 @@ module Datadog
10
10
  module RuleLoader
11
11
  class << self
12
12
  def load_rules(ruleset:, telemetry:)
13
- begin
14
- case ruleset
15
- when :recommended, :strict
16
- JSON.parse(Datadog::AppSec::Assets.waf_rules(ruleset))
17
- when :risky
18
- Datadog.logger.warn(
19
- 'The :risky Application Security Management ruleset has been deprecated and no longer available.'\
20
- 'The `:recommended` ruleset will be used instead.'\
21
- 'Please remove the `appsec.ruleset = :risky` setting from your Datadog.configure block.'
22
- )
23
- JSON.parse(Datadog::AppSec::Assets.waf_rules(:recommended))
24
- when String
25
- JSON.parse(File.read(File.expand_path(ruleset)))
26
- when File, StringIO
27
- JSON.parse(ruleset.read || '').tap { ruleset.rewind }
28
- when Hash
29
- ruleset
30
- else
31
- raise ArgumentError, "unsupported value for ruleset setting: #{ruleset.inspect}"
32
- end
33
- rescue StandardError => e
34
- Datadog.logger.error do
35
- "libddwaf ruleset failed to load, ruleset: #{ruleset.inspect} error: #{e.inspect}"
36
- end
13
+ case ruleset
14
+ when :recommended, :strict
15
+ JSON.parse(Datadog::AppSec::Assets.waf_rules(ruleset))
16
+ when :risky
17
+ Datadog.logger.warn(
18
+ 'The :risky Application Security Management ruleset has been deprecated and no longer available.' \
19
+ 'The `:recommended` ruleset will be used instead.' \
20
+ 'Please remove the `appsec.ruleset = :risky` setting from your Datadog.configure block.'
21
+ )
22
+ JSON.parse(Datadog::AppSec::Assets.waf_rules(:recommended))
23
+ when String
24
+ JSON.parse(File.read(File.expand_path(ruleset)))
25
+ when File, StringIO
26
+ JSON.parse(ruleset.read || '').tap { ruleset.rewind }
27
+ when Hash
28
+ ruleset
29
+ else
30
+ raise ArgumentError, "unsupported value for ruleset setting: #{ruleset.inspect}"
31
+ end
32
+ rescue => e
33
+ Datadog.logger.error do
34
+ "libddwaf ruleset failed to load, ruleset: #{ruleset.inspect} error: #{e.inspect}"
35
+ end
37
36
 
38
- telemetry.report(e, description: 'libddwaf ruleset failed to load')
37
+ telemetry.report(e, description: 'libddwaf ruleset failed to load')
39
38
 
40
- nil
41
- end
39
+ nil
42
40
  end
43
41
 
44
42
  def load_data(ip_denylist: [], user_id_denylist: [])
@@ -62,7 +60,7 @@ module Datadog
62
60
  {
63
61
  'id' => id,
64
62
  'type' => 'data_with_expiration',
65
- 'data' => denylist.map { |v| { 'value' => v.to_s, 'expiration' => 2**63 } }
63
+ 'data' => denylist.map { |v| {'value' => v.to_s, 'expiration' => 2**63} }
66
64
  }
67
65
  end
68
66
 
@@ -11,8 +11,8 @@ module Datadog
11
11
  # RuleVersionMismatchError
12
12
  class RuleVersionMismatchError < StandardError
13
13
  def initialize(version1, version2)
14
- msg = 'Merging rule files with different version could lead to unkown behaviour. '\
15
- "We have receieve two rule files with versions: #{version1}, #{version2}. "\
14
+ msg = 'Merging rule files with different version could lead to unkown behaviour. ' \
15
+ "We have receieve two rule files with versions: #{version1}, #{version2}. " \
16
16
  'Please validate the configuration is correct and try again.'
17
17
  super(msg)
18
18
  end
@@ -22,12 +22,12 @@ module Datadog
22
22
  # TODO: `processors` and `scanners` are not provided by the caller, consider removing them
23
23
  def merge(
24
24
  telemetry:,
25
- rules:, data: [], overrides: [], exclusions: [], custom_rules: [],
25
+ rules:, actions: [], data: [], overrides: [], exclusions: [], custom_rules: [],
26
26
  processors: nil, scanners: nil
27
27
  )
28
28
  processors ||= begin
29
29
  default_waf_processors
30
- rescue StandardError => e
30
+ rescue => e
31
31
  Datadog.logger.error("libddwaf rulemerger failed to parse default waf processors. Error: #{e.inspect}")
32
32
  telemetry.report(
33
33
  e,
@@ -38,7 +38,7 @@ module Datadog
38
38
 
39
39
  scanners ||= begin
40
40
  default_waf_scanners
41
- rescue StandardError => e
41
+ rescue => e
42
42
  Datadog.logger.error("libddwaf rulemerger failed to parse default waf scanners. Error: #{e.inspect}")
43
43
  telemetry.report(
44
44
  e,
@@ -54,6 +54,7 @@ module Datadog
54
54
  combined_exclusions = combine_exclusions(exclusions) if exclusions.any?
55
55
  combined_custom_rules = combine_custom_rules(custom_rules) if custom_rules.any?
56
56
 
57
+ combined_rules['actions'] = actions if actions.any?
57
58
  combined_rules['rules_data'] = combined_data if combined_data
58
59
  combined_rules['rules_override'] = combined_overrides if combined_overrides
59
60
  combined_rules['exclusions'] = combined_exclusions if combined_exclusions
@@ -145,7 +146,7 @@ module Datadog
145
146
  end
146
147
 
147
148
  result.each_with_object([]) do |entry, acc|
148
- value = { 'value' => entry[0] }
149
+ value = {'value' => entry[0]}
149
150
  value['expiration'] = entry[1] if entry[1]
150
151
 
151
152
  acc << value
@@ -82,7 +82,7 @@ module Datadog
82
82
  @diagnostics = e.diagnostics if e.diagnostics
83
83
 
84
84
  false
85
- rescue StandardError => e
85
+ rescue => e
86
86
  Datadog.logger.error do
87
87
  "libddwaf failed to initialize, error: #{e.inspect}"
88
88
  end