datadog 2.12.1 → 2.19.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 (346) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +243 -2
  3. data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +63 -56
  4. data/ext/datadog_profiling_native_extension/collectors_stack.c +263 -76
  5. data/ext/datadog_profiling_native_extension/collectors_stack.h +20 -3
  6. data/ext/datadog_profiling_native_extension/collectors_thread_context.c +78 -26
  7. data/ext/datadog_profiling_native_extension/collectors_thread_context.h +1 -0
  8. data/ext/datadog_profiling_native_extension/datadog_ruby_common.c +1 -4
  9. data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +10 -0
  10. data/ext/datadog_profiling_native_extension/encoded_profile.c +79 -0
  11. data/ext/datadog_profiling_native_extension/encoded_profile.h +8 -0
  12. data/ext/datadog_profiling_native_extension/extconf.rb +10 -0
  13. data/ext/datadog_profiling_native_extension/heap_recorder.c +247 -364
  14. data/ext/datadog_profiling_native_extension/heap_recorder.h +4 -6
  15. data/ext/datadog_profiling_native_extension/http_transport.c +60 -94
  16. data/ext/datadog_profiling_native_extension/libdatadog_helpers.c +22 -0
  17. data/ext/datadog_profiling_native_extension/libdatadog_helpers.h +8 -5
  18. data/ext/datadog_profiling_native_extension/private_vm_api_access.c +41 -21
  19. data/ext/datadog_profiling_native_extension/private_vm_api_access.h +6 -4
  20. data/ext/datadog_profiling_native_extension/profiling.c +2 -0
  21. data/ext/datadog_profiling_native_extension/ruby_helpers.c +1 -13
  22. data/ext/datadog_profiling_native_extension/ruby_helpers.h +3 -11
  23. data/ext/datadog_profiling_native_extension/stack_recorder.c +173 -76
  24. data/ext/libdatadog_api/crashtracker.c +11 -12
  25. data/ext/libdatadog_api/crashtracker.h +5 -0
  26. data/ext/libdatadog_api/datadog_ruby_common.c +1 -4
  27. data/ext/libdatadog_api/datadog_ruby_common.h +10 -0
  28. data/ext/libdatadog_api/extconf.rb +2 -2
  29. data/ext/libdatadog_api/init.c +15 -0
  30. data/ext/libdatadog_api/library_config.c +164 -0
  31. data/ext/libdatadog_api/library_config.h +25 -0
  32. data/ext/libdatadog_api/macos_development.md +3 -3
  33. data/ext/libdatadog_api/process_discovery.c +112 -0
  34. data/ext/libdatadog_api/process_discovery.h +5 -0
  35. data/ext/libdatadog_extconf_helpers.rb +2 -2
  36. data/lib/datadog/appsec/actions_handler/serializable_backtrace.rb +89 -0
  37. data/lib/datadog/appsec/actions_handler.rb +24 -2
  38. data/lib/datadog/appsec/anonymizer.rb +16 -0
  39. data/lib/datadog/appsec/api_security/lru_cache.rb +56 -0
  40. data/lib/datadog/appsec/api_security/route_extractor.rb +71 -0
  41. data/lib/datadog/appsec/api_security/sampler.rb +59 -0
  42. data/lib/datadog/appsec/api_security.rb +23 -0
  43. data/lib/datadog/appsec/assets/waf_rules/README.md +50 -5
  44. data/lib/datadog/appsec/assets/waf_rules/recommended.json +257 -85
  45. data/lib/datadog/appsec/assets/waf_rules/strict.json +10 -78
  46. data/lib/datadog/appsec/autoload.rb +1 -1
  47. data/lib/datadog/appsec/component.rb +46 -61
  48. data/lib/datadog/appsec/compressed_json.rb +40 -0
  49. data/lib/datadog/appsec/configuration/settings.rb +153 -30
  50. data/lib/datadog/appsec/context.rb +7 -7
  51. data/lib/datadog/appsec/contrib/active_record/instrumentation.rb +10 -12
  52. data/lib/datadog/appsec/contrib/active_record/integration.rb +2 -2
  53. data/lib/datadog/appsec/contrib/active_record/patcher.rb +22 -22
  54. data/lib/datadog/appsec/contrib/auto_instrument.rb +1 -1
  55. data/lib/datadog/appsec/contrib/devise/configuration.rb +7 -31
  56. data/lib/datadog/appsec/contrib/devise/data_extractor.rb +78 -0
  57. data/lib/datadog/appsec/contrib/devise/ext.rb +22 -0
  58. data/lib/datadog/appsec/contrib/devise/integration.rb +1 -2
  59. data/lib/datadog/appsec/contrib/devise/patcher.rb +34 -23
  60. data/lib/datadog/appsec/contrib/devise/patches/signin_tracking_patch.rb +102 -0
  61. data/lib/datadog/appsec/contrib/devise/patches/signup_tracking_patch.rb +69 -0
  62. data/lib/datadog/appsec/contrib/devise/{patcher/rememberable_patch.rb → patches/skip_signin_tracking_patch.rb} +2 -2
  63. data/lib/datadog/appsec/contrib/devise/tracking_middleware.rb +106 -0
  64. data/lib/datadog/appsec/contrib/excon/integration.rb +1 -1
  65. data/lib/datadog/appsec/contrib/excon/ssrf_detection_middleware.rb +9 -10
  66. data/lib/datadog/appsec/contrib/faraday/integration.rb +1 -1
  67. data/lib/datadog/appsec/contrib/faraday/ssrf_detection_middleware.rb +8 -9
  68. data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +8 -9
  69. data/lib/datadog/appsec/contrib/graphql/integration.rb +1 -1
  70. data/lib/datadog/appsec/contrib/rack/ext.rb +34 -0
  71. data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +49 -32
  72. data/lib/datadog/appsec/contrib/rack/integration.rb +1 -1
  73. data/lib/datadog/appsec/contrib/rack/request_middleware.rb +42 -30
  74. data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +11 -13
  75. data/lib/datadog/appsec/contrib/rails/integration.rb +1 -1
  76. data/lib/datadog/appsec/contrib/rails/patcher.rb +21 -21
  77. data/lib/datadog/appsec/contrib/rest_client/integration.rb +1 -1
  78. data/lib/datadog/appsec/contrib/rest_client/request_ssrf_detection_patch.rb +10 -11
  79. data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +17 -23
  80. data/lib/datadog/appsec/contrib/sinatra/integration.rb +1 -1
  81. data/lib/datadog/appsec/event.rb +96 -135
  82. data/lib/datadog/appsec/ext.rb +4 -2
  83. data/lib/datadog/appsec/instrumentation/gateway/argument.rb +7 -2
  84. data/lib/datadog/appsec/instrumentation/gateway/middleware.rb +24 -0
  85. data/lib/datadog/appsec/instrumentation/gateway.rb +17 -22
  86. data/lib/datadog/appsec/metrics/telemetry.rb +1 -1
  87. data/lib/datadog/appsec/monitor/gateway/watcher.rb +49 -14
  88. data/lib/datadog/appsec/processor/rule_loader.rb +30 -33
  89. data/lib/datadog/appsec/remote.rb +31 -59
  90. data/lib/datadog/appsec/response.rb +6 -6
  91. data/lib/datadog/appsec/security_engine/engine.rb +194 -0
  92. data/lib/datadog/appsec/security_engine/runner.rb +13 -14
  93. data/lib/datadog/appsec/security_event.rb +39 -0
  94. data/lib/datadog/appsec/utils.rb +0 -2
  95. data/lib/datadog/appsec.rb +5 -8
  96. data/lib/datadog/core/buffer/random.rb +18 -2
  97. data/lib/datadog/core/configuration/agent_settings.rb +52 -0
  98. data/lib/datadog/core/configuration/agent_settings_resolver.rb +4 -46
  99. data/lib/datadog/core/configuration/agentless_settings_resolver.rb +176 -0
  100. data/lib/datadog/core/configuration/components.rb +48 -31
  101. data/lib/datadog/core/configuration/components_state.rb +23 -0
  102. data/lib/datadog/core/configuration/ext.rb +4 -0
  103. data/lib/datadog/core/configuration/option.rb +81 -45
  104. data/lib/datadog/core/configuration/option_definition.rb +4 -4
  105. data/lib/datadog/core/configuration/options.rb +3 -3
  106. data/lib/datadog/core/configuration/settings.rb +109 -44
  107. data/lib/datadog/core/configuration/stable_config.rb +22 -0
  108. data/lib/datadog/core/configuration.rb +40 -16
  109. data/lib/datadog/core/crashtracking/component.rb +3 -10
  110. data/lib/datadog/core/crashtracking/tag_builder.rb +4 -22
  111. data/lib/datadog/core/diagnostics/environment_logger.rb +1 -1
  112. data/lib/datadog/core/encoding.rb +1 -1
  113. data/lib/datadog/core/environment/agent_info.rb +4 -3
  114. data/lib/datadog/core/environment/cgroup.rb +10 -12
  115. data/lib/datadog/core/environment/container.rb +38 -40
  116. data/lib/datadog/core/environment/ext.rb +6 -6
  117. data/lib/datadog/core/environment/git.rb +1 -0
  118. data/lib/datadog/core/environment/identity.rb +3 -3
  119. data/lib/datadog/core/environment/platform.rb +3 -3
  120. data/lib/datadog/core/environment/variable_helpers.rb +1 -1
  121. data/lib/datadog/core/error.rb +11 -9
  122. data/lib/datadog/core/logger.rb +2 -2
  123. data/lib/datadog/core/metrics/client.rb +20 -21
  124. data/lib/datadog/core/metrics/logging.rb +5 -5
  125. data/lib/datadog/core/process_discovery/tracer_memfd.rb +15 -0
  126. data/lib/datadog/core/process_discovery.rb +36 -0
  127. data/lib/datadog/core/rate_limiter.rb +4 -2
  128. data/lib/datadog/core/remote/client.rb +40 -32
  129. data/lib/datadog/core/remote/component.rb +6 -9
  130. data/lib/datadog/core/remote/configuration/digest.rb +7 -7
  131. data/lib/datadog/core/remote/configuration/path.rb +1 -1
  132. data/lib/datadog/core/remote/configuration/repository.rb +14 -1
  133. data/lib/datadog/core/remote/negotiation.rb +9 -9
  134. data/lib/datadog/core/remote/transport/config.rb +4 -3
  135. data/lib/datadog/core/remote/transport/http/client.rb +5 -4
  136. data/lib/datadog/core/remote/transport/http/config.rb +27 -37
  137. data/lib/datadog/core/remote/transport/http/negotiation.rb +7 -33
  138. data/lib/datadog/core/remote/transport/http.rb +22 -57
  139. data/lib/datadog/core/remote/transport/negotiation.rb +4 -3
  140. data/lib/datadog/core/runtime/metrics.rb +12 -5
  141. data/lib/datadog/core/tag_builder.rb +56 -0
  142. data/lib/datadog/core/telemetry/component.rb +81 -52
  143. data/lib/datadog/core/telemetry/emitter.rb +23 -11
  144. data/lib/datadog/core/telemetry/event/app_client_configuration_change.rb +66 -0
  145. data/lib/datadog/core/telemetry/event/app_closing.rb +18 -0
  146. data/lib/datadog/core/telemetry/event/app_dependencies_loaded.rb +33 -0
  147. data/lib/datadog/core/telemetry/event/app_heartbeat.rb +18 -0
  148. data/lib/datadog/core/telemetry/event/app_integrations_change.rb +58 -0
  149. data/lib/datadog/core/telemetry/event/app_started.rb +287 -0
  150. data/lib/datadog/core/telemetry/event/base.rb +40 -0
  151. data/lib/datadog/core/telemetry/event/distributions.rb +18 -0
  152. data/lib/datadog/core/telemetry/event/generate_metrics.rb +43 -0
  153. data/lib/datadog/core/telemetry/event/log.rb +76 -0
  154. data/lib/datadog/core/telemetry/event/message_batch.rb +42 -0
  155. data/lib/datadog/core/telemetry/event/synth_app_client_configuration_change.rb +43 -0
  156. data/lib/datadog/core/telemetry/event.rb +17 -472
  157. data/lib/datadog/core/telemetry/http/adapters/net.rb +12 -97
  158. data/lib/datadog/core/telemetry/logger.rb +5 -4
  159. data/lib/datadog/core/telemetry/logging.rb +11 -5
  160. data/lib/datadog/core/telemetry/metric.rb +8 -8
  161. data/lib/datadog/core/telemetry/request.rb +4 -4
  162. data/lib/datadog/core/telemetry/transport/http/api.rb +43 -0
  163. data/lib/datadog/core/telemetry/transport/http/client.rb +49 -0
  164. data/lib/datadog/core/telemetry/transport/http/telemetry.rb +92 -0
  165. data/lib/datadog/core/telemetry/transport/http.rb +63 -0
  166. data/lib/datadog/core/telemetry/transport/telemetry.rb +51 -0
  167. data/lib/datadog/core/telemetry/worker.rb +90 -24
  168. data/lib/datadog/core/transport/http/adapters/net.rb +17 -2
  169. data/lib/datadog/core/transport/http/adapters/test.rb +2 -1
  170. data/lib/datadog/core/transport/http/api/instance.rb +17 -0
  171. data/lib/datadog/core/transport/http/api/spec.rb +17 -0
  172. data/lib/datadog/core/transport/http/builder.rb +19 -17
  173. data/lib/datadog/core/transport/http/env.rb +8 -0
  174. data/lib/datadog/core/transport/http.rb +39 -2
  175. data/lib/datadog/core/utils/at_fork_monkey_patch.rb +6 -6
  176. data/lib/datadog/core/utils/duration.rb +32 -32
  177. data/lib/datadog/core/utils/forking.rb +2 -2
  178. data/lib/datadog/core/utils/network.rb +6 -6
  179. data/lib/datadog/core/utils/only_once_successful.rb +16 -5
  180. data/lib/datadog/core/utils/time.rb +20 -0
  181. data/lib/datadog/core/utils/truncation.rb +21 -0
  182. data/lib/datadog/core/utils.rb +7 -0
  183. data/lib/datadog/core/vendor/multipart-post/multipart/post/composite_read_io.rb +1 -1
  184. data/lib/datadog/core/vendor/multipart-post/multipart/post/multipartable.rb +8 -8
  185. data/lib/datadog/core/vendor/multipart-post/multipart/post/parts.rb +7 -7
  186. data/lib/datadog/core/worker.rb +1 -1
  187. data/lib/datadog/core/workers/async.rb +29 -12
  188. data/lib/datadog/core/workers/interval_loop.rb +12 -1
  189. data/lib/datadog/core/workers/runtime_metrics.rb +2 -2
  190. data/lib/datadog/core.rb +8 -0
  191. data/lib/datadog/di/boot.rb +34 -0
  192. data/lib/datadog/di/component.rb +0 -2
  193. data/lib/datadog/di/instrumenter.rb +48 -5
  194. data/lib/datadog/di/probe_notification_builder.rb +38 -43
  195. data/lib/datadog/di/probe_notifier_worker.rb +25 -17
  196. data/lib/datadog/di/remote.rb +2 -0
  197. data/lib/datadog/di/serializer.rb +10 -2
  198. data/lib/datadog/di/transport/diagnostics.rb +4 -3
  199. data/lib/datadog/di/transport/http/api.rb +2 -12
  200. data/lib/datadog/di/transport/http/client.rb +4 -3
  201. data/lib/datadog/di/transport/http/diagnostics.rb +7 -34
  202. data/lib/datadog/di/transport/http/input.rb +18 -35
  203. data/lib/datadog/di/transport/http.rb +14 -62
  204. data/lib/datadog/di/transport/input.rb +14 -5
  205. data/lib/datadog/di/utils.rb +5 -0
  206. data/lib/datadog/di.rb +0 -33
  207. data/lib/datadog/error_tracking/collector.rb +87 -0
  208. data/lib/datadog/error_tracking/component.rb +167 -0
  209. data/lib/datadog/error_tracking/configuration/settings.rb +63 -0
  210. data/lib/datadog/error_tracking/configuration.rb +11 -0
  211. data/lib/datadog/error_tracking/ext.rb +18 -0
  212. data/lib/datadog/error_tracking/extensions.rb +16 -0
  213. data/lib/datadog/error_tracking/filters.rb +77 -0
  214. data/lib/datadog/error_tracking.rb +18 -0
  215. data/lib/datadog/kit/appsec/events/v2.rb +195 -0
  216. data/lib/datadog/kit/appsec/events.rb +12 -0
  217. data/lib/datadog/kit/identity.rb +5 -1
  218. data/lib/datadog/opentelemetry/api/baggage.rb +90 -0
  219. data/lib/datadog/opentelemetry/api/baggage.rbs +26 -0
  220. data/lib/datadog/opentelemetry/api/context.rb +16 -2
  221. data/lib/datadog/opentelemetry/sdk/trace/span.rb +1 -1
  222. data/lib/datadog/opentelemetry.rb +2 -1
  223. data/lib/datadog/profiling/collectors/code_provenance.rb +18 -9
  224. data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +6 -0
  225. data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +1 -0
  226. data/lib/datadog/profiling/collectors/info.rb +44 -0
  227. data/lib/datadog/profiling/collectors/thread_context.rb +17 -2
  228. data/lib/datadog/profiling/component.rb +8 -9
  229. data/lib/datadog/profiling/encoded_profile.rb +11 -0
  230. data/lib/datadog/profiling/exporter.rb +12 -7
  231. data/lib/datadog/profiling/ext.rb +0 -14
  232. data/lib/datadog/profiling/flush.rb +5 -8
  233. data/lib/datadog/profiling/http_transport.rb +7 -61
  234. data/lib/datadog/profiling/profiler.rb +2 -0
  235. data/lib/datadog/profiling/scheduler.rb +10 -2
  236. data/lib/datadog/profiling/sequence_tracker.rb +44 -0
  237. data/lib/datadog/profiling/stack_recorder.rb +9 -9
  238. data/lib/datadog/profiling/tag_builder.rb +7 -41
  239. data/lib/datadog/profiling/tasks/setup.rb +2 -0
  240. data/lib/datadog/profiling.rb +7 -2
  241. data/lib/datadog/single_step_instrument.rb +9 -0
  242. data/lib/datadog/tracing/analytics.rb +1 -1
  243. data/lib/datadog/tracing/component.rb +15 -12
  244. data/lib/datadog/tracing/configuration/ext.rb +7 -1
  245. data/lib/datadog/tracing/configuration/settings.rb +18 -2
  246. data/lib/datadog/tracing/context_provider.rb +1 -1
  247. data/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb +15 -0
  248. data/lib/datadog/tracing/contrib/action_pack/action_dispatch/instrumentation.rb +19 -12
  249. data/lib/datadog/tracing/contrib/action_pack/ext.rb +2 -0
  250. data/lib/datadog/tracing/contrib/active_record/integration.rb +1 -1
  251. data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +11 -2
  252. data/lib/datadog/tracing/contrib/active_support/cache/instrumentation.rb +33 -0
  253. data/lib/datadog/tracing/contrib/active_support/cache/patcher.rb +4 -0
  254. data/lib/datadog/tracing/contrib/active_support/cache/redis.rb +2 -4
  255. data/lib/datadog/tracing/contrib/active_support/configuration/settings.rb +13 -0
  256. data/lib/datadog/tracing/contrib/aws/instrumentation.rb +10 -0
  257. data/lib/datadog/tracing/contrib/aws/parsed_context.rb +5 -1
  258. data/lib/datadog/tracing/contrib/configuration/settings.rb +1 -1
  259. data/lib/datadog/tracing/contrib/ethon/easy_patch.rb +4 -5
  260. data/lib/datadog/tracing/contrib/excon/middleware.rb +5 -3
  261. data/lib/datadog/tracing/contrib/ext.rb +1 -0
  262. data/lib/datadog/tracing/contrib/faraday/middleware.rb +5 -3
  263. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/client.rb +7 -1
  264. data/lib/datadog/tracing/contrib/grpc/distributed/propagation.rb +3 -0
  265. data/lib/datadog/tracing/contrib/http/circuit_breaker.rb +0 -15
  266. data/lib/datadog/tracing/contrib/http/distributed/propagation.rb +4 -1
  267. data/lib/datadog/tracing/contrib/http/instrumentation.rb +6 -10
  268. data/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +6 -16
  269. data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +7 -15
  270. data/lib/datadog/tracing/contrib/karafka/configuration/settings.rb +27 -0
  271. data/lib/datadog/tracing/contrib/karafka/distributed/propagation.rb +48 -0
  272. data/lib/datadog/tracing/contrib/karafka/ext.rb +27 -0
  273. data/lib/datadog/tracing/contrib/karafka/integration.rb +45 -0
  274. data/lib/datadog/tracing/contrib/karafka/monitor.rb +66 -0
  275. data/lib/datadog/tracing/contrib/karafka/patcher.rb +71 -0
  276. data/lib/datadog/tracing/contrib/karafka.rb +37 -0
  277. data/lib/datadog/tracing/contrib/lograge/patcher.rb +4 -2
  278. data/lib/datadog/tracing/contrib/mongodb/configuration/settings.rb +8 -0
  279. data/lib/datadog/tracing/contrib/mongodb/ext.rb +1 -0
  280. data/lib/datadog/tracing/contrib/mongodb/subscribers.rb +18 -1
  281. data/lib/datadog/tracing/contrib/mysql2/instrumentation.rb +16 -6
  282. data/lib/datadog/tracing/contrib/opensearch/configuration/settings.rb +17 -0
  283. data/lib/datadog/tracing/contrib/opensearch/ext.rb +9 -0
  284. data/lib/datadog/tracing/contrib/opensearch/patcher.rb +5 -1
  285. data/lib/datadog/tracing/contrib/patcher.rb +5 -2
  286. data/lib/datadog/tracing/contrib/rack/request_queue.rb +1 -1
  287. data/lib/datadog/tracing/contrib/rails/patcher.rb +4 -1
  288. data/lib/datadog/tracing/contrib/rails/runner.rb +61 -40
  289. data/lib/datadog/tracing/contrib/rest_client/request_patch.rb +5 -3
  290. data/lib/datadog/tracing/contrib/sidekiq/client_tracer.rb +6 -1
  291. data/lib/datadog/tracing/contrib/sidekiq/distributed/propagation.rb +3 -0
  292. data/lib/datadog/tracing/contrib/sidekiq/ext.rb +1 -0
  293. data/lib/datadog/tracing/contrib/sidekiq/server_tracer.rb +5 -2
  294. data/lib/datadog/tracing/contrib/support.rb +28 -0
  295. data/lib/datadog/tracing/contrib.rb +1 -0
  296. data/lib/datadog/tracing/correlation.rb +9 -2
  297. data/lib/datadog/tracing/diagnostics/environment_logger.rb +3 -1
  298. data/lib/datadog/tracing/distributed/b3_multi.rb +1 -1
  299. data/lib/datadog/tracing/distributed/b3_single.rb +1 -1
  300. data/lib/datadog/tracing/distributed/baggage.rb +131 -0
  301. data/lib/datadog/tracing/distributed/datadog.rb +4 -2
  302. data/lib/datadog/tracing/distributed/propagation.rb +25 -4
  303. data/lib/datadog/tracing/distributed/propagation_policy.rb +42 -0
  304. data/lib/datadog/tracing/metadata/errors.rb +4 -4
  305. data/lib/datadog/tracing/metadata/ext.rb +5 -0
  306. data/lib/datadog/tracing/metadata/metastruct.rb +36 -0
  307. data/lib/datadog/tracing/metadata/metastruct_tagging.rb +42 -0
  308. data/lib/datadog/tracing/metadata.rb +2 -0
  309. data/lib/datadog/tracing/sampling/rate_sampler.rb +2 -1
  310. data/lib/datadog/tracing/sampling/span/rule.rb +0 -1
  311. data/lib/datadog/tracing/span.rb +10 -1
  312. data/lib/datadog/tracing/span_event.rb +2 -2
  313. data/lib/datadog/tracing/span_operation.rb +68 -16
  314. data/lib/datadog/tracing/sync_writer.rb +2 -3
  315. data/lib/datadog/tracing/trace_digest.rb +9 -2
  316. data/lib/datadog/tracing/trace_operation.rb +55 -27
  317. data/lib/datadog/tracing/trace_segment.rb +6 -4
  318. data/lib/datadog/tracing/tracer.rb +51 -7
  319. data/lib/datadog/tracing/transport/http/api.rb +2 -10
  320. data/lib/datadog/tracing/transport/http/client.rb +5 -4
  321. data/lib/datadog/tracing/transport/http/traces.rb +13 -41
  322. data/lib/datadog/tracing/transport/http.rb +11 -44
  323. data/lib/datadog/tracing/transport/serializable_trace.rb +3 -1
  324. data/lib/datadog/tracing/transport/trace_formatter.rb +7 -0
  325. data/lib/datadog/tracing/transport/traces.rb +26 -9
  326. data/lib/datadog/tracing/utils.rb +1 -1
  327. data/lib/datadog/tracing/workers/trace_writer.rb +2 -6
  328. data/lib/datadog/tracing/writer.rb +2 -6
  329. data/lib/datadog/tracing.rb +16 -3
  330. data/lib/datadog/version.rb +2 -2
  331. data/lib/datadog.rb +8 -2
  332. metadata +88 -23
  333. data/lib/datadog/appsec/assets/waf_rules/processors.json +0 -92
  334. data/lib/datadog/appsec/assets/waf_rules/scanners.json +0 -114
  335. data/lib/datadog/appsec/contrib/devise/event.rb +0 -54
  336. data/lib/datadog/appsec/contrib/devise/patcher/authenticatable_patch.rb +0 -72
  337. data/lib/datadog/appsec/contrib/devise/patcher/registration_controller_patch.rb +0 -47
  338. data/lib/datadog/appsec/contrib/devise/resource.rb +0 -35
  339. data/lib/datadog/appsec/contrib/devise/tracking.rb +0 -57
  340. data/lib/datadog/appsec/processor/rule_merger.rb +0 -170
  341. data/lib/datadog/appsec/processor.rb +0 -107
  342. data/lib/datadog/appsec/utils/trace_operation.rb +0 -15
  343. data/lib/datadog/core/telemetry/http/env.rb +0 -20
  344. data/lib/datadog/core/telemetry/http/ext.rb +0 -28
  345. data/lib/datadog/core/telemetry/http/response.rb +0 -70
  346. data/lib/datadog/core/telemetry/http/transport.rb +0 -90
@@ -20,7 +20,7 @@ module Datadog
20
20
  end
21
21
 
22
22
  def id
23
- @id ||= "#{type}::#{name}::#{tags.join(',')}"
23
+ @id ||= "#{type}::#{name}::#{tags.join(",")}"
24
24
  end
25
25
 
26
26
  def track(value)
@@ -47,7 +47,7 @@ module Datadog
47
47
  values == other.values && tags == other.tags && common == other.common && type == other.type
48
48
  end
49
49
 
50
- alias eql? ==
50
+ alias_method :eql?, :==
51
51
 
52
52
  def hash
53
53
  [self.class, name, values, tags, common, type].hash
@@ -88,7 +88,7 @@ module Datadog
88
88
  super && interval == other.interval
89
89
  end
90
90
 
91
- alias eql? ==
91
+ alias_method :eql?, :==
92
92
 
93
93
  def hash
94
94
  [super, interval].hash
@@ -108,9 +108,9 @@ module Datadog
108
108
  value = value.to_i
109
109
 
110
110
  if values.empty?
111
- values << [Time.now.to_i, value]
111
+ values << [Core::Utils::Time.now.to_i, value]
112
112
  else
113
- values[0][0] = Time.now.to_i
113
+ values[0][0] = Core::Utils::Time.now.to_i
114
114
  values[0][1] += value
115
115
  end
116
116
  nil
@@ -129,9 +129,9 @@ module Datadog
129
129
 
130
130
  def track(value)
131
131
  if values.empty?
132
- values << [Time.now.to_i, value]
132
+ values << [Core::Utils::Time.now.to_i, value]
133
133
  else
134
- values[0][0] = Time.now.to_i
134
+ values[0][0] = Core::Utils::Time.now.to_i
135
135
  values[0][1] = value
136
136
  end
137
137
  nil
@@ -155,7 +155,7 @@ module Datadog
155
155
 
156
156
  def track(value = 1.0)
157
157
  @value += value
158
- @values = [[Time.now.to_i, @value / interval]]
158
+ @values = [[Core::Utils::Time.now.to_i, @value / interval]]
159
159
  nil
160
160
  end
161
161
  end
@@ -11,17 +11,17 @@ module Datadog
11
11
  class << self
12
12
  using Core::Utils::Hash::Refinement
13
13
 
14
- def build_payload(event, seq_id)
14
+ def build_payload(event, seq_id, api_version: 'v2', debug: false)
15
15
  hash = {
16
- api_version: Http::Ext::API_VERSION,
16
+ api_version: api_version,
17
17
  application: application,
18
- debug: false,
18
+ debug: debug,
19
19
  host: host,
20
20
  payload: event.payload,
21
21
  request_type: event.type,
22
22
  runtime_id: Core::Environment::Identity.id,
23
23
  seq_id: seq_id,
24
- tracer_time: Time.now.to_i,
24
+ tracer_time: Core::Utils::Time.now.to_i,
25
25
  }
26
26
  hash.compact!
27
27
  hash
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../../encoding'
4
+ require_relative '../../../transport/http/api/map'
5
+ require_relative '../../../transport/http/api/instance'
6
+ require_relative '../../../transport/http/api/spec'
7
+ require_relative 'telemetry'
8
+
9
+ module Datadog
10
+ module Core
11
+ module Telemetry
12
+ module Transport
13
+ module HTTP
14
+ # Namespace for API components
15
+ module API
16
+ # Default API versions
17
+ AGENT_TELEMETRY = 'agent_telemetry'
18
+ AGENTLESS_TELEMETRY = 'agentless_telemetry'
19
+
20
+ module_function
21
+
22
+ def defaults
23
+ Datadog::Core::Transport::HTTP::API::Map[
24
+ AGENT_TELEMETRY => Telemetry::API::Spec.new do |s|
25
+ s.telemetry = Telemetry::API::Endpoint.new(
26
+ '/telemetry/proxy/api/v2/apmtelemetry',
27
+ Core::Encoding::JSONEncoder,
28
+ )
29
+ end,
30
+ AGENTLESS_TELEMETRY => Telemetry::API::Spec.new do |s|
31
+ s.telemetry = Telemetry::API::Endpoint.new(
32
+ '/api/v2/apmtelemetry',
33
+ Core::Encoding::JSONEncoder,
34
+ )
35
+ end,
36
+ ]
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../../transport/http/env'
4
+ require_relative '../../../transport/http/response'
5
+
6
+ # TODO: Decouple transport/http/client
7
+ #
8
+ # The standard one does `include Transport::HTTP::Statistics` and performs
9
+ # stats updates, which may or may not be desirable in general.
10
+
11
+ module Datadog
12
+ module Core
13
+ module Telemetry
14
+ module Transport
15
+ module HTTP
16
+ # Routes, encodes, and sends DI data to the trace agent via HTTP.
17
+ class Client
18
+ attr_reader :api, :logger
19
+
20
+ def initialize(api, logger:)
21
+ @api = api
22
+ @logger = logger
23
+ end
24
+
25
+ def send_request(request, &block)
26
+ # Build request into env
27
+ env = build_env(request)
28
+
29
+ # Get responses from API
30
+ yield(api, env)
31
+ rescue => e
32
+ message =
33
+ "Internal error during #{self.class.name} request. Cause: #{e.class.name} #{e.message} " \
34
+ "Location: #{Array(e.backtrace).first}"
35
+
36
+ logger.debug(message)
37
+
38
+ Datadog::Core::Transport::InternalErrorResponse.new(e)
39
+ end
40
+
41
+ def build_env(request)
42
+ Datadog::Core::Transport::HTTP::Env.new(request)
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../../transport/http/api/endpoint'
4
+ require_relative '../../../transport/http/api/instance'
5
+ require_relative '../../../transport/http/api/spec'
6
+ require_relative '../../../transport/request'
7
+ require_relative 'client'
8
+
9
+ module Datadog
10
+ module Core
11
+ module Telemetry
12
+ module Transport
13
+ module HTTP
14
+ module Telemetry
15
+ module Client
16
+ def send_telemetry_payload(request)
17
+ send_request(request) do |api, env| # steep:ignore
18
+ api.send_telemetry(env)
19
+ end
20
+ end
21
+ end
22
+
23
+ module API
24
+ class Instance < Core::Transport::HTTP::API::Instance
25
+ def send_telemetry(env)
26
+ raise Core::Transport::HTTP::API::Instance::EndpointNotSupportedError.new('telemetry', self) unless spec.is_a?(Telemetry::API::Spec)
27
+
28
+ spec.send_telemetry(env) do |request_env|
29
+ call(request_env)
30
+ end
31
+ end
32
+ end
33
+
34
+ class Spec < Core::Transport::HTTP::API::Spec
35
+ attr_accessor :telemetry
36
+
37
+ def send_telemetry(env, &block)
38
+ raise Core::Transport::HTTP::API::Spec::EndpointNotDefinedError.new('telemetry', self) if telemetry.nil?
39
+
40
+ telemetry.call(env, &block)
41
+ end
42
+ end
43
+
44
+ class Endpoint < Datadog::Core::Transport::HTTP::API::Endpoint
45
+ HEADER_CONTENT_TYPE = 'Content-Type'
46
+
47
+ attr_reader \
48
+ :encoder
49
+
50
+ def initialize(path, encoder)
51
+ super(:post, path)
52
+ @encoder = encoder
53
+ end
54
+
55
+ def call(env, &block)
56
+ # Encode body & type
57
+ env.headers[HEADER_CONTENT_TYPE] = encoder.content_type
58
+ env.headers.update(headers(
59
+ request_type: env.request.request_type,
60
+ api_key: env.request.api_key,
61
+ ))
62
+ env.body = env.request.parcel.data
63
+
64
+ super
65
+ end
66
+
67
+ def headers(request_type:, api_key:, api_version: 'v2')
68
+ {
69
+ Core::Transport::Ext::HTTP::HEADER_DD_INTERNAL_UNTRACED_REQUEST => '1',
70
+ # Provided by encoder
71
+ # 'Content-Type' => 'application/json',
72
+ 'DD-Telemetry-API-Version' => api_version,
73
+ 'DD-Telemetry-Request-Type' => request_type,
74
+ 'DD-Client-Library-Language' => Core::Environment::Ext::LANG,
75
+ 'DD-Client-Library-Version' => Core::Environment::Identity.gem_datadog_version_semver2,
76
+
77
+ # Enable debug mode for telemetry
78
+ # 'DD-Telemetry-Debug-Enabled' => 'true',
79
+ }.tap do |result|
80
+ result['DD-API-KEY'] = api_key unless api_key.nil?
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
86
+
87
+ HTTP::Client.include(Telemetry::Client)
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'telemetry'
4
+ require_relative 'http/api'
5
+ require_relative '../../transport/http'
6
+
7
+ module Datadog
8
+ module Core
9
+ module Telemetry
10
+ module Transport
11
+ # Namespace for HTTP transport components
12
+ module HTTP
13
+ module_function
14
+
15
+ # Builds a new Transport::HTTP::Client with default settings
16
+ # Pass a block to override any settings.
17
+ def agentless_telemetry(
18
+ agent_settings:,
19
+ logger:,
20
+ api_key: nil,
21
+ api_version: nil,
22
+ headers: nil
23
+ )
24
+ Core::Transport::HTTP.build(api_instance_class: Telemetry::API::Instance,
25
+ logger: logger,
26
+ agent_settings: agent_settings,
27
+ api_version: api_version,
28
+ headers: headers) do |transport|
29
+ apis = API.defaults
30
+
31
+ transport.api API::AGENTLESS_TELEMETRY, apis[API::AGENTLESS_TELEMETRY]
32
+
33
+ # Call block to apply any customization, if provided
34
+ yield(transport) if block_given?
35
+ end.to_transport(Core::Telemetry::Transport::Telemetry::Transport).tap do |transport|
36
+ transport.api_key = api_key
37
+ end
38
+ end
39
+
40
+ # Builds a new Transport::HTTP::Client with default settings
41
+ # Pass a block to override any settings.
42
+ def agent_telemetry(
43
+ agent_settings:,
44
+ logger:,
45
+ api_version: nil,
46
+ headers: nil
47
+ )
48
+ Core::Transport::HTTP.build(api_instance_class: Telemetry::API::Instance,
49
+ logger: logger,
50
+ agent_settings: agent_settings, api_version: api_version, headers: headers) do |transport|
51
+ apis = API.defaults
52
+
53
+ transport.api API::AGENT_TELEMETRY, apis[API::AGENT_TELEMETRY]
54
+
55
+ # Call block to apply any customization, if provided
56
+ yield(transport) if block_given?
57
+ end.to_transport(Core::Telemetry::Transport::Telemetry::Transport)
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../transport/parcel'
4
+ require_relative 'http/client'
5
+ require_relative 'http/telemetry'
6
+
7
+ module Datadog
8
+ module Core
9
+ module Telemetry
10
+ module Transport
11
+ module Telemetry
12
+ class EncodedParcel
13
+ include Datadog::Core::Transport::Parcel
14
+ end
15
+
16
+ class Request < Datadog::Core::Transport::Request
17
+ attr_reader :request_type
18
+ attr_reader :api_key
19
+
20
+ def initialize(request_type, parcel, api_key)
21
+ @request_type = request_type
22
+ super(parcel)
23
+ @api_key = api_key
24
+ end
25
+ end
26
+
27
+ class Transport
28
+ attr_reader :client, :apis, :default_api, :current_api_id, :logger
29
+ attr_accessor :api_key
30
+
31
+ def initialize(apis, default_api, logger:)
32
+ @apis = apis
33
+ @logger = logger
34
+
35
+ @client = HTTP::Client.new(@apis[default_api], logger: logger)
36
+ end
37
+
38
+ def send_telemetry(request_type:, payload:)
39
+ json = JSON.dump(payload)
40
+ parcel = EncodedParcel.new(json)
41
+ request = Request.new(request_type, parcel, api_key)
42
+
43
+ @client.send_telemetry_payload(request)
44
+ # Perform no error checking here
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -17,8 +17,6 @@ module Datadog
17
17
  DEFAULT_BUFFER_MAX_SIZE = 1000
18
18
  APP_STARTED_EVENT_RETRIES = 10
19
19
 
20
- TELEMETRY_STARTED_ONCE = Utils::OnlyOnceSuccessful.new(APP_STARTED_EVENT_RETRIES)
21
-
22
20
  def initialize(
23
21
  heartbeat_interval_seconds:,
24
22
  metrics_aggregation_interval_seconds:,
@@ -48,14 +46,25 @@ module Datadog
48
46
  @buffer_size = buffer_size
49
47
 
50
48
  self.buffer = buffer_klass.new(@buffer_size)
49
+
50
+ @initial_event_once = Utils::OnlyOnceSuccessful.new(APP_STARTED_EVENT_RETRIES)
51
51
  end
52
52
 
53
53
  attr_reader :logger
54
+ attr_reader :initial_event_once
55
+ attr_reader :initial_event
54
56
 
55
- def start
57
+ # Returns true if worker thread is successfully started,
58
+ # false if worker thread was not started but telemetry is enabled,
59
+ # nil if telemetry is disabled.
60
+ def start(initial_event)
56
61
  return if !enabled? || forked?
57
62
 
63
+ @initial_event = initial_event
64
+
58
65
  # starts async worker
66
+ # perform should return true if thread was actually started,
67
+ # false otherwise
59
68
  perform
60
69
  end
61
70
 
@@ -65,18 +74,60 @@ module Datadog
65
74
  super
66
75
  end
67
76
 
77
+ # Returns true if event was enqueued, nil if not.
78
+ # While returning false may seem more reasonable, the only reason
79
+ # for not enqueueing event (presently) is that telemetry is disabled
80
+ # altogether, and in this case other methods return nil.
68
81
  def enqueue(event)
69
82
  return if !enabled? || forked?
70
83
 
71
84
  buffer.push(event)
85
+ true
86
+ end
87
+
88
+ def sent_initial_event?
89
+ initial_event_once.success?
72
90
  end
73
91
 
74
- def sent_started_event?
75
- TELEMETRY_STARTED_ONCE.success?
92
+ def failed_initial_event?
93
+ initial_event_once.failed?
76
94
  end
77
95
 
78
- def failed_to_start?
79
- TELEMETRY_STARTED_ONCE.failed?
96
+ def need_initial_event?
97
+ !sent_initial_event? && !failed_initial_event?
98
+ end
99
+
100
+ # Wait for the worker to send out all events that have already
101
+ # been queued, up to 15 seconds. Returns whether all events have
102
+ # been flushed.
103
+ #
104
+ # @api private
105
+ def flush
106
+ return true unless enabled? || !run_loop?
107
+
108
+ started = Utils::Time.get_time
109
+ loop do
110
+ # The AppStarted event is triggered by the worker itself,
111
+ # from the worker thread. As such the main thread has no way
112
+ # to delay itself until that event is queued and we need some
113
+ # way to wait until that event is sent out to assert on it in
114
+ # the test suite. Check the run once flag which *should*
115
+ # indicate the event has been queued (at which point our queue
116
+ # depth check should waint until it's sent).
117
+ # This is still a hack because the flag can be overridden
118
+ # either way with or without the event being sent out.
119
+ # Note that if the AppStarted sending fails, this check
120
+ # will return false and flushing will be blocked until the
121
+ # 15 second timeout.
122
+ # Note that the first wait interval between telemetry event
123
+ # sending is 10 seconds, the timeout needs to be strictly
124
+ # greater than that.
125
+ return true if buffer.empty? && !in_iteration? && sent_initial_event?
126
+
127
+ sleep 0.5
128
+
129
+ return false if Utils::Time.get_time - started > 15
130
+ end
80
131
  end
81
132
 
82
133
  private
@@ -84,11 +135,26 @@ module Datadog
84
135
  def perform(*events)
85
136
  return if !enabled? || forked?
86
137
 
87
- started! unless sent_started_event?
138
+ if need_initial_event?
139
+ started!
140
+ unless sent_initial_event?
141
+ # We still haven't succeeded in sending the started event,
142
+ # which will make flush_events do nothing - but the events
143
+ # given to us as the parameter have already been removed
144
+ # from the queue.
145
+ # Put the events back to the front of the queue to not
146
+ # lose them.
147
+ buffer.unshift(*events)
148
+ return
149
+ end
150
+ end
88
151
 
89
152
  metric_events = @metrics_manager.flush!
90
153
  events = [] if events.nil?
91
- flush_events(events + metric_events)
154
+ events += metric_events
155
+ if events.any?
156
+ flush_events(events)
157
+ end
92
158
 
93
159
  @current_ticks += 1
94
160
  return if @current_ticks < @ticks_per_heartbeat
@@ -98,9 +164,6 @@ module Datadog
98
164
  end
99
165
 
100
166
  def flush_events(events)
101
- return if events.empty?
102
- return if !enabled? || !sent_started_event?
103
-
104
167
  events = deduplicate_logs(events)
105
168
 
106
169
  logger.debug { "Sending #{events&.count} telemetry events" }
@@ -108,7 +171,7 @@ module Datadog
108
171
  end
109
172
 
110
173
  def heartbeat!
111
- return if !enabled? || !sent_started_event?
174
+ return if !enabled? || !sent_initial_event?
112
175
 
113
176
  send_event(Event::AppHeartbeat.new)
114
177
  end
@@ -116,26 +179,29 @@ module Datadog
116
179
  def started!
117
180
  return unless enabled?
118
181
 
119
- if failed_to_start?
120
- logger.debug('Telemetry app-started event exhausted retries, disabling telemetry worker')
121
- disable!
122
- return
123
- end
124
-
125
- TELEMETRY_STARTED_ONCE.run do
126
- res = send_event(Event::AppStarted.new)
182
+ initial_event_once.run do
183
+ res = send_event(initial_event)
127
184
 
128
185
  if res.ok?
129
- logger.debug('Telemetry app-started event is successfully sent')
186
+ logger.debug { "Telemetry initial event (#{initial_event.type}) is successfully sent" }
130
187
 
131
- send_event(Event::AppDependenciesLoaded.new) if @dependency_collection
188
+ # TODO Dependencies loaded event should probably check for new
189
+ # dependencies and send the new ones.
190
+ # System tests demand only one instance of this event per
191
+ # dependency.
192
+ send_event(Event::AppDependenciesLoaded.new) if @dependency_collection && initial_event.class.eql?(Telemetry::Event::AppStarted) # standard:disable Style/ClassEqualityComparison:
132
193
 
133
194
  true
134
195
  else
135
- logger.debug('Error sending telemetry app-started event, retry after heartbeat interval...')
196
+ logger.debug("Error sending telemetry initial event (#{initial_event.type}), retry after heartbeat interval...")
136
197
  false
137
198
  end
138
199
  end
200
+
201
+ if failed_initial_event?
202
+ logger.debug { "Telemetry initial event (#{initial_event.type}) exhausted retries, disabling telemetry worker" }
203
+ disable!
204
+ end
139
205
  end
140
206
 
141
207
  def send_event(event)
@@ -48,7 +48,7 @@ module Datadog
48
48
  end
49
49
 
50
50
  def get(env)
51
- get = ::Net::HTTP::Get.new(env.path, env.headers)
51
+ get = ::Net::HTTP::Get.new(net_http_path_from_env(env), env.headers)
52
52
 
53
53
  # Connect and send the request
54
54
  http_response = open do |http|
@@ -63,7 +63,7 @@ module Datadog
63
63
  post = nil
64
64
 
65
65
  if env.form.nil? || env.form.empty?
66
- post = ::Net::HTTP::Post.new(env.path, env.headers)
66
+ post = ::Net::HTTP::Post.new(net_http_path_from_env(env), env.headers)
67
67
  post.body = env.body
68
68
  else
69
69
  post = ::Datadog::Core::Vendor::Net::HTTP::Post::Multipart.new(
@@ -86,6 +86,21 @@ module Datadog
86
86
  "http://#{hostname}:#{port}?timeout=#{timeout}"
87
87
  end
88
88
 
89
+ def net_http_path_from_env(env)
90
+ path = env.path
91
+ case query = env.query
92
+ when Hash
93
+ path = path + '?' + URI.encode_www_form(query)
94
+ when String
95
+ path = path + '?' + query
96
+ when nil
97
+ # Nothing
98
+ else
99
+ raise ArgumentError, "Invalid type for query: #{query}"
100
+ end
101
+ path
102
+ end
103
+
89
104
  # Raised when called with an unknown HTTP method
90
105
  class UnknownHTTPMethod < StandardError
91
106
  attr_reader :verb
@@ -38,7 +38,8 @@ module Datadog
38
38
  @status = status
39
39
  end
40
40
 
41
- def url; end
41
+ def url
42
+ end
42
43
 
43
44
  # Response for test adapter
44
45
  class Response
@@ -7,6 +7,23 @@ module Datadog
7
7
  module API
8
8
  # An API configured with adapter and routes
9
9
  class Instance
10
+ # Raised when an endpoint is invoked on an API that is not the
11
+ # of expected API class for that endpoint.
12
+ class EndpointNotSupportedError < StandardError
13
+ attr_reader :spec, :endpoint_name
14
+
15
+ def initialize(endpoint_name, spec)
16
+ @spec = spec
17
+ @endpoint_name = endpoint_name
18
+
19
+ super(message)
20
+ end
21
+
22
+ def message
23
+ "#{endpoint_name} not supported for this API!"
24
+ end
25
+ end
26
+
10
27
  attr_reader \
11
28
  :adapter,
12
29
  :headers,
@@ -8,6 +8,23 @@ module Datadog
8
8
  # Specification for an HTTP API
9
9
  # Defines behaviors without specific configuration details.
10
10
  class Spec
11
+ # Raised when an endpoint is invoked on an API that did not
12
+ # define that endpoint.
13
+ class EndpointNotDefinedError < StandardError
14
+ attr_reader :spec, :endpoint_name
15
+
16
+ def initialize(endpoint_name, spec)
17
+ @spec = spec
18
+ @endpoint_name = endpoint_name
19
+
20
+ super(message)
21
+ end
22
+
23
+ def message
24
+ "No #{endpoint_name} endpoint is defined for API specification!"
25
+ end
26
+ end
27
+
11
28
  def initialize
12
29
  yield(self) if block_given?
13
30
  end