sqreen 1.21.0 → 1.23.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (180) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +27 -0
  3. data/lib/sqreen/actions.rb +1 -1
  4. data/lib/sqreen/actions/actions_index.rb +5 -1
  5. data/lib/sqreen/actions/base.rb +1 -1
  6. data/lib/sqreen/actions/block_ip.rb +1 -1
  7. data/lib/sqreen/actions/block_user.rb +1 -1
  8. data/lib/sqreen/actions/ip_range_indexed_action_class.rb +1 -1
  9. data/lib/sqreen/actions/ip_ranges_index.rb +1 -1
  10. data/lib/sqreen/actions/redirect_ip.rb +1 -1
  11. data/lib/sqreen/actions/redirect_user.rb +1 -1
  12. data/lib/sqreen/actions/repository.rb +1 -1
  13. data/lib/sqreen/actions/unknown_action_type.rb +1 -1
  14. data/lib/sqreen/actions/user_action_class.rb +1 -1
  15. data/lib/sqreen/actions/users_index.rb +5 -1
  16. data/lib/sqreen/agent_message.rb +5 -0
  17. data/lib/sqreen/aggregated_metric.rb +5 -0
  18. data/lib/sqreen/attack_blocked.rb +1 -1
  19. data/lib/sqreen/binding_accessor.rb +1 -1
  20. data/lib/sqreen/binding_accessor/path_elem.rb +1 -1
  21. data/lib/sqreen/binding_accessor/transforms.rb +1 -1
  22. data/lib/sqreen/call_countable.rb +1 -1
  23. data/lib/sqreen/capped_queue.rb +1 -1
  24. data/lib/sqreen/cb.rb +1 -1
  25. data/lib/sqreen/condition_evaluator.rb +1 -1
  26. data/lib/sqreen/conditionable.rb +1 -1
  27. data/lib/sqreen/context.rb +1 -1
  28. data/lib/sqreen/default_cb.rb +1 -1
  29. data/lib/sqreen/deferred_logger.rb +1 -1
  30. data/lib/sqreen/deliveries.rb +1 -1
  31. data/lib/sqreen/deliveries/batch.rb +1 -1
  32. data/lib/sqreen/deliveries/simple.rb +1 -1
  33. data/lib/sqreen/dependency.rb +1 -1
  34. data/lib/sqreen/dependency/detector.rb +11 -3
  35. data/lib/sqreen/dependency/new_relic.rb +10 -1
  36. data/lib/sqreen/deprecation.rb +1 -1
  37. data/lib/sqreen/ecosystem.rb +5 -0
  38. data/lib/sqreen/ecosystem/databases/database_connection_data.rb +5 -0
  39. data/lib/sqreen/ecosystem/databases/mongo.rb +5 -0
  40. data/lib/sqreen/ecosystem/databases/mysql.rb +5 -0
  41. data/lib/sqreen/ecosystem/databases/postgres.rb +5 -0
  42. data/lib/sqreen/ecosystem/databases/redis.rb +5 -0
  43. data/lib/sqreen/ecosystem/dispatch_table.rb +5 -0
  44. data/lib/sqreen/ecosystem/exception_reporting.rb +5 -0
  45. data/lib/sqreen/ecosystem/http/net_http.rb +5 -0
  46. data/lib/sqreen/ecosystem/http/rack_request.rb +5 -0
  47. data/lib/sqreen/ecosystem/loggable.rb +5 -0
  48. data/lib/sqreen/ecosystem/messaging/bunny.rb +5 -0
  49. data/lib/sqreen/ecosystem/messaging/kafka.rb +5 -0
  50. data/lib/sqreen/ecosystem/messaging/kinesis.rb +5 -0
  51. data/lib/sqreen/ecosystem/messaging/sqs.rb +5 -0
  52. data/lib/sqreen/ecosystem/module_api.rb +5 -0
  53. data/lib/sqreen/ecosystem/module_api/event_listener.rb +5 -0
  54. data/lib/sqreen/ecosystem/module_api/instrumentation.rb +5 -0
  55. data/lib/sqreen/ecosystem/module_api/message_producer.rb +5 -0
  56. data/lib/sqreen/ecosystem/module_api/signal_producer.rb +5 -0
  57. data/lib/sqreen/ecosystem/module_api/tracing.rb +5 -0
  58. data/lib/sqreen/ecosystem/module_api/tracing/client_data.rb +5 -0
  59. data/lib/sqreen/ecosystem/module_api/tracing/consumer_data.rb +5 -0
  60. data/lib/sqreen/ecosystem/module_api/tracing/messaging_data.rb +5 -0
  61. data/lib/sqreen/ecosystem/module_api/tracing/producer_data.rb +5 -0
  62. data/lib/sqreen/ecosystem/module_api/tracing/server_data.rb +5 -0
  63. data/lib/sqreen/ecosystem/module_api/tracing_id_generation.rb +5 -0
  64. data/lib/sqreen/ecosystem/module_api/transaction_storage.rb +5 -0
  65. data/lib/sqreen/ecosystem/module_registry.rb +5 -0
  66. data/lib/sqreen/ecosystem/tracing/modules/client.rb +5 -0
  67. data/lib/sqreen/ecosystem/tracing/modules/consumer.rb +5 -0
  68. data/lib/sqreen/ecosystem/tracing/modules/determine_ip.rb +5 -0
  69. data/lib/sqreen/ecosystem/tracing/modules/producer.rb +5 -0
  70. data/lib/sqreen/ecosystem/tracing/modules/server.rb +5 -0
  71. data/lib/sqreen/ecosystem/tracing/sampler.rb +5 -0
  72. data/lib/sqreen/ecosystem/tracing/sampling_configuration.rb +5 -0
  73. data/lib/sqreen/ecosystem/tracing/signals/tracing_client.rb +5 -0
  74. data/lib/sqreen/ecosystem/tracing/signals/tracing_consumer.rb +5 -0
  75. data/lib/sqreen/ecosystem/tracing/signals/tracing_producer.rb +5 -0
  76. data/lib/sqreen/ecosystem/tracing/signals/tracing_server.rb +5 -0
  77. data/lib/sqreen/ecosystem/tracing_broker.rb +5 -0
  78. data/lib/sqreen/ecosystem/tracing_id_setup.rb +5 -0
  79. data/lib/sqreen/ecosystem/transaction_storage.rb +5 -0
  80. data/lib/sqreen/ecosystem/util/call_writers_from_init.rb +5 -0
  81. data/lib/sqreen/ecosystem_integration.rb +5 -0
  82. data/lib/sqreen/ecosystem_integration/around_callbacks.rb +5 -0
  83. data/lib/sqreen/ecosystem_integration/instrumentation_service.rb +5 -0
  84. data/lib/sqreen/ecosystem_integration/request_lifecycle_tracking.rb +5 -0
  85. data/lib/sqreen/ecosystem_integration/signal_consumption.rb +6 -8
  86. data/lib/sqreen/endpoint_testing.rb +5 -0
  87. data/lib/sqreen/error_handling_middleware.rb +1 -1
  88. data/lib/sqreen/event.rb +1 -1
  89. data/lib/sqreen/events/attack.rb +1 -1
  90. data/lib/sqreen/events/remote_exception.rb +1 -1
  91. data/lib/sqreen/events/request_record.rb +1 -1
  92. data/lib/sqreen/exception.rb +1 -1
  93. data/lib/sqreen/formatter_with_tid.rb +1 -1
  94. data/lib/sqreen/framework_cb.rb +1 -1
  95. data/lib/sqreen/frameworks/generic.rb +18 -0
  96. data/lib/sqreen/frameworks/sqreen_test.rb +1 -1
  97. data/lib/sqreen/graft.rb +1 -1
  98. data/lib/sqreen/graft/call.rb +1 -1
  99. data/lib/sqreen/graft/callback.rb +1 -1
  100. data/lib/sqreen/graft/hook.rb +8 -294
  101. data/lib/sqreen/graft/hook.ruby_2.rb +305 -0
  102. data/lib/sqreen/graft/hook.ruby_3.rb +305 -0
  103. data/lib/sqreen/graft/hook_point.rb +7 -7
  104. data/lib/sqreen/graft/hook_point.ruby_2.rb +18 -0
  105. data/lib/sqreen/graft/hook_point.ruby_3.rb +19 -0
  106. data/lib/sqreen/graft/hook_point_error.rb +1 -1
  107. data/lib/sqreen/invalid_signature_exception.rb +1 -1
  108. data/lib/sqreen/js.rb +1 -1
  109. data/lib/sqreen/js/call_context.rb +1 -1
  110. data/lib/sqreen/js/context_pool.rb +8 -6
  111. data/lib/sqreen/js/exec_js_runnable.rb +1 -1
  112. data/lib/sqreen/js/execjs_adapter.rb +1 -1
  113. data/lib/sqreen/js/executable_js.rb +1 -1
  114. data/lib/sqreen/js/js_service_adapter.rb +1 -1
  115. data/lib/sqreen/js/mini_racer_adapter.rb +2 -1
  116. data/lib/sqreen/js/mini_racer_executable_js.rb +2 -0
  117. data/lib/sqreen/js/thread_local_exec_js_runnable.rb +1 -1
  118. data/lib/sqreen/legacy.rb +1 -1
  119. data/lib/sqreen/log/loggable.rb +1 -1
  120. data/lib/sqreen/logger.rb +1 -1
  121. data/lib/sqreen/metrics.rb +1 -1
  122. data/lib/sqreen/metrics/average.rb +1 -1
  123. data/lib/sqreen/metrics/base.rb +1 -1
  124. data/lib/sqreen/metrics/binning.rb +1 -1
  125. data/lib/sqreen/metrics/collect.rb +1 -1
  126. data/lib/sqreen/metrics/sum.rb +1 -1
  127. data/lib/sqreen/metrics_store.rb +1 -1
  128. data/lib/sqreen/metrics_store/already_registered_metric.rb +1 -1
  129. data/lib/sqreen/metrics_store/unknown_metric.rb +1 -1
  130. data/lib/sqreen/metrics_store/unregistered_metric.rb +1 -1
  131. data/lib/sqreen/middleware.rb +1 -1
  132. data/lib/sqreen/node.rb +1 -1
  133. data/lib/sqreen/not_implemented_yet.rb +1 -1
  134. data/lib/sqreen/null_logger.rb +1 -1
  135. data/lib/sqreen/payload_creator/header_section.rb +1 -1
  136. data/lib/sqreen/performance_notifications.rb +1 -1
  137. data/lib/sqreen/performance_notifications/binned_metrics.rb +1 -1
  138. data/lib/sqreen/performance_notifications/log.rb +1 -1
  139. data/lib/sqreen/performance_notifications/log_performance.rb +1 -1
  140. data/lib/sqreen/performance_notifications/metrics.rb +1 -1
  141. data/lib/sqreen/prefix.rb +1 -1
  142. data/lib/sqreen/rails_middleware.rb +1 -1
  143. data/lib/sqreen/remote_command.rb +1 -1
  144. data/lib/sqreen/remote_command/failure_output.rb +1 -1
  145. data/lib/sqreen/rules/attrs.rb +1 -1
  146. data/lib/sqreen/rules/execjs_cb.rb +1 -0
  147. data/lib/sqreen/rules/run_user_actions.rb +1 -1
  148. data/lib/sqreen/run_when_called_cb.rb +1 -1
  149. data/lib/sqreen/safe_json.rb +1 -1
  150. data/lib/sqreen/sensitive_data_redactor.rb +2 -2
  151. data/lib/sqreen/serializer.rb +1 -1
  152. data/lib/sqreen/shared_storage.rb +1 -1
  153. data/lib/sqreen/shrink_wrap.rb +1 -1
  154. data/lib/sqreen/signals/conversions.rb +5 -0
  155. data/lib/sqreen/signals/http_trace_redaction.rb +5 -0
  156. data/lib/sqreen/signals/signals_submission_strategy.rb +5 -0
  157. data/lib/sqreen/signature_verifier.rb +1 -1
  158. data/lib/sqreen/sinatra_middleware.rb +1 -1
  159. data/lib/sqreen/sqreen_signed_verifier.rb +1 -1
  160. data/lib/sqreen/token_invalid_exception.rb +1 -1
  161. data/lib/sqreen/token_not_found_exception.rb +1 -1
  162. data/lib/sqreen/trie.rb +1 -1
  163. data/lib/sqreen/unauthorized.rb +1 -1
  164. data/lib/sqreen/util.rb +1 -1
  165. data/lib/sqreen/util/capped_array.rb +1 -1
  166. data/lib/sqreen/util/capped_hash.rb +1 -1
  167. data/lib/sqreen/util/capped_string.rb +1 -1
  168. data/lib/sqreen/util/capper.rb +1 -1
  169. data/lib/sqreen/version.rb +2 -2
  170. data/lib/sqreen/waf_error.rb +1 -1
  171. data/lib/sqreen/weave.rb +1 -1
  172. data/lib/sqreen/weave/budget.rb +1 -1
  173. data/lib/sqreen/weave/hardcoded.rb +1 -1
  174. data/lib/sqreen/weave/instrumentor.rb +1 -1
  175. data/lib/sqreen/weave/legacy.rb +1 -1
  176. data/lib/sqreen/weave/legacy/instrumentation.rb +112 -12
  177. data/lib/sqreen/web_server/generic.rb +1 -1
  178. data/lib/sqreen/web_server/webrick.rb +1 -1
  179. data/lib/sqreen/worker.rb +1 -1
  180. metadata +21 -11
data/lib/sqreen/event.rb CHANGED
@@ -1,4 +1,4 @@
1
- # typed: true
1
+ # typed: ignore
2
2
 
3
3
  # Copyright (c) 2015 Sqreen. All Rights Reserved.
4
4
  # Please refer to our terms for more information: https://www.sqreen.com/terms.html
@@ -1,4 +1,4 @@
1
- # typed: true
1
+ # typed: ignore
2
2
 
3
3
  # Copyright (c) 2015 Sqreen. All Rights Reserved.
4
4
  # Please refer to our terms for more information: https://www.sqreen.com/terms.html
@@ -1,4 +1,4 @@
1
- # typed: true
1
+ # typed: ignore
2
2
 
3
3
  # Copyright (c) 2015 Sqreen. All Rights Reserved.
4
4
  # Please refer to our terms for more information: https://www.sqreen.com/terms.html
@@ -1,4 +1,4 @@
1
- # typed: false
1
+ # typed: ignore
2
2
 
3
3
  # Copyright (c) 2015 Sqreen. All Rights Reserved.
4
4
  # Please refer to our terms for more information: https://www.sqreen.com/terms.html
@@ -1,4 +1,4 @@
1
- # typed: false
1
+ # typed: ignore
2
2
 
3
3
  # Copyright (c) 2015 Sqreen. All Rights Reserved.
4
4
  # Please refer to our terms for more information: https://www.sqreen.com/terms.html
@@ -1,4 +1,4 @@
1
- # typed: true
1
+ # typed: ignore
2
2
 
3
3
  # Copyright (c) 2015 Sqreen. All Rights Reserved.
4
4
  # Please refer to our terms for more information: https://www.sqreen.com/terms.html
@@ -1,4 +1,4 @@
1
- # typed: true
1
+ # typed: ignore
2
2
 
3
3
  # Copyright (c) 2015 Sqreen. All Rights Reserved.
4
4
  # Please refer to our terms for more information: https://www.sqreen.com/terms.html
@@ -377,6 +377,10 @@ module Sqreen
377
377
  end
378
378
  end
379
379
 
380
+ def graphql_args=(args)
381
+ request.env['sqreen.request.graphql_args'] = args if request
382
+ end
383
+
380
384
  def self.parameters_from_request(request)
381
385
  return {} unless request
382
386
 
@@ -388,6 +392,8 @@ module Sqreen
388
392
  if (p = rack_params(request))
389
393
  r[P_RACK] = p
390
394
  end
395
+ p = request.env['sqreen.request.graphql_args']
396
+ r['graphql'] = p if p
391
397
  # Add grape parameters if seen
392
398
  p = request.env['grape.request.params']
393
399
  r[P_GRAPE] = p if p
@@ -400,6 +406,18 @@ module Sqreen
400
406
  r
401
407
  end
402
408
 
409
+ def body
410
+ return nil unless request.respond_to?(:body)
411
+ return nil unless request.body.respond_to?(:read)
412
+ return nil unless request.body.respond_to?(:rewind)
413
+
414
+ body_io = request.body
415
+ body = body_io.read(4096)
416
+ body_io.rewind
417
+
418
+ body
419
+ end
420
+
403
421
  # Expose current working directory
404
422
  def cwd
405
423
  Dir.getwd
@@ -1,4 +1,4 @@
1
- # typed: true
1
+ # typed: ignore
2
2
 
3
3
  # Copyright (c) 2015 Sqreen. All Rights Reserved.
4
4
  # Please refer to our terms for more information: https://www.sqreen.com/terms.html
data/lib/sqreen/graft.rb CHANGED
@@ -1,4 +1,4 @@
1
- # typed: strong
1
+ # typed: ignore
2
2
 
3
3
  # Copyright (c) 2015 Sqreen. All Rights Reserved.
4
4
  # Please refer to our terms for more information: https://www.sqreen.com/terms.html
@@ -1,4 +1,4 @@
1
- # typed: false
1
+ # typed: ignore
2
2
 
3
3
  # Copyright (c) 2015 Sqreen. All Rights Reserved.
4
4
  # Please refer to our terms for more information: https://www.sqreen.com/terms.html
@@ -1,4 +1,4 @@
1
- # typed: false
1
+ # typed: ignore
2
2
 
3
3
  # Copyright (c) 2015 Sqreen. All Rights Reserved.
4
4
  # Please refer to our terms for more information: https://www.sqreen.com/terms.html
@@ -1,12 +1,11 @@
1
- # typed: false
1
+ # typed: ignore
2
2
 
3
3
  # Copyright (c) 2015 Sqreen. All Rights Reserved.
4
4
  # Please refer to our terms for more information: https://www.sqreen.com/terms.html
5
5
 
6
6
  require 'sqreen/graft'
7
- require 'sqreen/graft/call'
8
- require 'sqreen/graft/callback'
9
7
  require 'sqreen/graft/hook_point'
8
+ require 'sqreen/graft/callback'
10
9
 
11
10
  module Sqreen
12
11
  module Graft
@@ -124,297 +123,12 @@ module Sqreen
124
123
  @raised = []
125
124
  @ensured = []
126
125
  end
127
-
128
- def self.wrapper(hook)
129
- timed_hooks_proc = proc do |t|
130
- if (request = Thread.current[:sqreen_http_request])
131
- request[:timed_hooks] << t if request[:timed_level] >= 1
132
- end
133
- end
134
- timed_callbacks_proc = proc do |t|
135
- if (request = Thread.current[:sqreen_http_request])
136
- request[:timed_callbacks] << t if request[:timed_level] >= 1
137
- end
138
- end
139
-
140
- Proc.new do |*args, &block|
141
- request = Thread.current[:sqreen_http_request]
142
-
143
- if Thread.current[:sqreen_hook_entered]
144
- if hook.point.super?
145
- return super(*args, &block)
146
- else
147
- return hook.point.apply(self, 'sqreen_hook', *args, &block)
148
- end
149
- end
150
-
151
- if request && request[:time_budget_expended] && (hook.before + hook.after + hook.raised + hook.ensured).none?(&:mandatory)
152
- if request[:timed_level] >= 2
153
- begin
154
- request[:skipped_callbacks].concat(hook.before)
155
-
156
- if hook.point.super?
157
- return super(*args, &block)
158
- else
159
- return hook.point.apply(self, 'sqreen_hook', *args, &block)
160
- end
161
- rescue ::Exception # rubocop:disable Lint/RescueException
162
- request[:skipped_callbacks].concat(hook.raised)
163
- raise
164
- else
165
- request[:skipped_callbacks].concat(hook.after)
166
- ensure
167
- request[:skipped_callbacks].concat(hook.ensured)
168
- end
169
- else
170
- if hook.point.super? # rubocop:disable Style/IfInsideElse
171
- return super(*args, &block)
172
- else
173
- return hook.point.apply(self, 'sqreen_hook', *args, &block)
174
- end
175
- end
176
- end
177
-
178
- hook_point_super = hook.point.super?
179
- logger = Sqreen::Graft.logger
180
- logger_debug = Sqreen::Graft.logger.debug?
181
-
182
- Timer.new(hook.point, &timed_hooks_proc).measure do |chrono|
183
- # budget implies request
184
- # TODO: make budget depend on a generic context (currently "request")
185
- budget = request[:time_budget] if request
186
- if budget
187
- budget_threshold = request[:time_budget_threshold]
188
- budget_ratio = request[:time_budget_ratio]
189
- sqreen_timer = request[:sqreen_timer]
190
- request_timer = request[:request_timer]
191
- end
192
-
193
- hooked_call = HookedCall.new(self, args)
194
-
195
- begin
196
- begin
197
- sqreen_timer.start if budget
198
- Thread.current[:sqreen_hook_entered] = true
199
-
200
- # TODO: make Call have #ball to throw by cb
201
- # TODO: can Call be the ball? r = catch(Call.new, &c)
202
- # TODO: is catch return value a Call? a #dispatch?
203
- # TODO: make before/after/raised return a CallbackCollection << Array (or extend with module)
204
- # TODO: add CallbackCollection#each_with_call(instance, args) { |call| ... } ?
205
- # TODO: HookCall x CallbackCollection#each_with_call x Flow
206
- # TODO: TimedHookCall TimedCallbackCall
207
- # TODO: TimeBoundHookCall TimeBoundCallbackCall TimeBoundFlow?
208
-
209
- request_elapsed = request_timer.elapsed if budget
210
-
211
- hook.before.each do |c|
212
- next if c.ignore && c.ignore.call
213
-
214
- if budget && !c.mandatory
215
- sqreen_elapsed = sqreen_timer.elapsed
216
- if budget_ratio && !request[:time_budget_expended]
217
- fixed_budget = budget_threshold
218
- proportional_budget = (request_elapsed - sqreen_elapsed) * budget_ratio
219
- remaining = (fixed_budget > proportional_budget ? fixed_budget : proportional_budget) - sqreen_elapsed
220
- else
221
- remaining = budget_threshold - sqreen_elapsed
222
- end
223
- unless remaining > 0
224
- request[:skipped_callbacks] << c
225
- request[:time_budget_expended] = true
226
- next
227
- end
228
- end
229
-
230
- flow = catch(Ball.new) do |ball|
231
- Timer.new(c.name, &timed_callbacks_proc).measure(ignore: chrono) do
232
- c.call(CallbackCall.new(c, remaining, hooked_call.instance, hooked_call.args_passed), ball)
233
- end
234
- end
235
-
236
- next unless c.flow && flow.is_a?(Flow)
237
- hooked_call.raise = flow.raise and hooked_call.raising = true if flow.raise?
238
- hooked_call.args_pass = flow.args and hooked_call.args_passing = true if flow.args?
239
- hooked_call.return = flow.return and hooked_call.returning = true if flow.return?
240
- break if flow.break?
241
- end unless hook.disabled?
242
- rescue StandardError => e
243
- Sqreen::Weave.logger.debug { "exception:#{e.class} message:'#{e.message}' location:\"#{e.backtrace[0]}\"" }
244
- Sqreen::RemoteException.record(e) if Sqreen.queue
245
- end
246
-
247
- raise hooked_call.raise if hooked_call.raising
248
- return hooked_call.return if hooked_call.returning
249
- ensure
250
- Thread.current[:sqreen_hook_entered] = false
251
- sqreen_timer.stop if budget
252
- end unless hook.before.empty?
253
-
254
- begin
255
- chrono.ignore do
256
- if hook_point_super
257
- hooked_call.returned = super(*(hooked_call.args_passing ? hooked_call.args_pass : hooked_call.args_passed), &block)
258
- else
259
- hooked_call.returned = hook.point.apply(hooked_call.instance, 'sqreen_hook', *(hooked_call.args_passing ? hooked_call.args_pass : hooked_call.args_passed), &block)
260
- end
261
- end
262
- rescue ::Exception => e # rubocop:disable Lint/RescueException
263
- begin
264
- sqreen_timer.start if budget
265
- Thread.current[:sqreen_hook_entered] = true
266
- hooked_call.raised = e
267
-
268
- logger.debug { "[#{Process.pid}] Hook #{hook.point} disabled:#{hook.disabled?} exception:#{e}" } if logger_debug
269
- raise if hook.raised.empty?
270
-
271
- request_elapsed = request_timer.elapsed if budget
272
-
273
- hook.raised.each do |c|
274
- next if c.ignore && c.ignore.call
275
-
276
- if budget && !c.mandatory
277
- sqreen_elapsed = sqreen_timer.elapsed
278
- if budget_ratio && !request[:time_budget_expended]
279
- fixed_budget = budget_threshold
280
- proportional_budget = (request_elapsed - sqreen_elapsed) * budget_ratio
281
- remaining = (fixed_budget > proportional_budget ? fixed_budget : proportional_budget) - sqreen_elapsed
282
- else
283
- remaining = budget_threshold - sqreen_elapsed
284
- end
285
- unless remaining > 0
286
- request[:skipped_callbacks] << c
287
- request[:time_budget_expended] = true
288
- next
289
- end
290
- end
291
-
292
- flow = catch(Ball.new) do |ball|
293
- Timer.new(c.name, &timed_callbacks_proc).measure(ignore: chrono) do
294
- c.call(CallbackCall.new(c, remaining, hooked_call.instance, hooked_call.args_passing ? hooked_call.args_pass : hooked_call.args_passed, hooked_call.raised), ball)
295
- end
296
- end
297
-
298
- next unless c.flow && flow.is_a?(Flow)
299
- hooked_call.raise = flow.raise and hooked_call.raising = true if flow.raise?
300
- hooked_call.return = flow.return and hooked_call.returning = true if flow.return?
301
- hooked_call.retrying = true if flow.retry?
302
- break if flow.break?
303
- end unless hook.disabled?
304
- rescue StandardError => e
305
- Sqreen::Weave.logger.debug { "exception:#{e.class} message:'#{e.message}' location:\"#{e.backtrace[0]}\"" }
306
- Sqreen::RemoteException.record(e) if Sqreen.queue
307
- end
308
-
309
- retry if hooked_call.retrying
310
- raise hooked_call.raise if hooked_call.raising
311
- return hooked_call.return if hooked_call.returning
312
- raise
313
- else
314
- begin
315
- sqreen_timer.start if budget
316
- Thread.current[:sqreen_hook_entered] = true
317
-
318
- # TODO: hooked_call.returning should be always false here?
319
- return hooked_call.returning ? hooked_call.return : hooked_call.returned if hook.after.empty?
320
-
321
- request_elapsed = request_timer.elapsed if budget
322
-
323
- hook.after.each do |c|
324
- next if c.ignore && c.ignore.call
325
-
326
- if budget && !c.mandatory
327
- sqreen_elapsed = sqreen_timer.elapsed
328
- if budget_ratio && !request[:time_budget_expended]
329
- fixed_budget = budget_threshold
330
- proportional_budget = (request_elapsed - sqreen_elapsed) * budget_ratio
331
- remaining = (fixed_budget > proportional_budget ? fixed_budget : proportional_budget) - sqreen_elapsed
332
- else
333
- remaining = budget_threshold - sqreen_elapsed
334
- end
335
- unless remaining > 0
336
- request[:skipped_callbacks] << c
337
- request[:time_budget_expended] = true
338
- next
339
- end
340
- end
341
-
342
- flow = catch(Ball.new) do |ball|
343
- Timer.new(c.name, &timed_callbacks_proc).measure(ignore: chrono) do
344
- c.call(CallbackCall.new(c, remaining, hooked_call.instance, hooked_call.args_passing ? hooked_call.args_pass : hooked_call.args_passed, nil, hooked_call.returned), ball)
345
- end
346
- end
347
-
348
- next unless c.flow && flow.is_a?(Flow)
349
- hooked_call.raise = flow.raise and hooked_call.raising = true if flow.raise?
350
- hooked_call.return = flow.return and hooked_call.returning = true if flow.return?
351
- break if flow.break?
352
- end unless hook.disabled?
353
- rescue StandardError => e
354
- Sqreen::Weave.logger.debug { "exception:#{e.class} message:'#{e.message}' location:\"#{e.backtrace[0]}\"" }
355
- Sqreen::RemoteException.record(e) if Sqreen.queue
356
- end
357
-
358
- raise hooked_call.raise if hooked_call.raising
359
- return hooked_call.returning ? hooked_call.return : hooked_call.returned
360
- ensure
361
- begin
362
- # TODO: sqreen_timer.start if someone has thrown?
363
- # TODO: sqreen_timer.stop at end of rescue+else?
364
- # TODO: Thread.current[:sqreen_hook_entered] = true if neither rescue nor else ie thrown?
365
- # TODO: Thread.current[:sqreen_hook_entered] = false at end of rescue+else? (risky?)
366
-
367
- # TODO: uniform early bail out? (but don't forget sqreen_hook_entered and sqreen_timer)
368
- # return hooked_call.returning ? hooked_call.return : hooked_call.returned if hook.ensured.empty?
369
-
370
- # done at either rescue or else
371
- # request_elapsed = request_timer.elapsed if budget # && !hook.ensured.empty?
372
-
373
- hook.ensured.each do |c|
374
- next if c.ignore && c.ignore.call
375
-
376
- if budget && !c.mandatory
377
- sqreen_elapsed = sqreen_timer.elapsed
378
- if budget_ratio && !request[:time_budget_expended]
379
- fixed_budget = budget_threshold
380
- proportional_budget = (request_elapsed - sqreen_elapsed) * budget_ratio
381
- remaining = (fixed_budget > proportional_budget ? fixed_budget : proportional_budget) - sqreen_elapsed
382
- else
383
- remaining = budget_threshold - sqreen_elapsed
384
- end
385
- unless remaining > 0
386
- request[:skipped_callbacks] << c
387
- request[:time_budget_expended] = true
388
- next
389
- end
390
- end
391
-
392
- flow = catch(Ball.new) do |ball|
393
- Timer.new(c.name, &timed_callbacks_proc).measure(ignore: chrono) do
394
- c.call(CallbackCall.new(c, remaining, hooked_call.instance, hooked_call.args_passing ? hooked_call.args_pass : hooked_call.args_passed, nil, hooked_call.returned), ball)
395
- end
396
- end
397
-
398
- next unless c.flow && flow.is_a?(Flow)
399
- hooked_call.raise = flow.raise and hooked_call.raising = true if flow.raise?
400
- hooked_call.return = flow.return and hooked_call.returning = true if flow.return?
401
- break if flow.break?
402
- end unless hook.ensured.empty? || hook.disabled?
403
-
404
- Thread.current[:sqreen_hook_entered] = false
405
- sqreen_timer.stop if budget
406
- rescue StandardError => e
407
- Sqreen::Weave.logger.debug { "exception:#{e.class} message:'#{e.message}' location:\"#{e.backtrace[0]}\"" }
408
- Sqreen::RemoteException.record(e) if Sqreen.queue
409
- end
410
-
411
- # TODO: should we run the following?
412
- # raise hooked_call.raise if hooked_call.raising
413
- # return hooked_call.returning ? hooked_call.return : hooked_call.returned
414
- end
415
- end # chrono
416
- end
417
- end
418
126
  end
419
127
  end
420
128
  end
129
+
130
+ if RUBY_VERSION =~ /^2\./
131
+ load File.join(__dir__, 'hook.ruby_2.rb')
132
+ else
133
+ load File.join(__dir__, 'hook.ruby_3.rb')
134
+ end
@@ -0,0 +1,305 @@
1
+ # typed: ignore
2
+
3
+ # Copyright (c) 2015 Sqreen. All Rights Reserved.
4
+ # Please refer to our terms for more information: https://www.sqreen.com/terms.html
5
+
6
+ require 'sqreen/graft/call'
7
+
8
+ module Sqreen
9
+ module Graft
10
+ class Hook
11
+ def self.wrapper(hook)
12
+ timed_hooks_proc = proc do |t|
13
+ if (request = Thread.current[:sqreen_http_request])
14
+ request[:timed_hooks] << t if request[:timed_level] >= 1
15
+ end
16
+ end
17
+ timed_callbacks_proc = proc do |t|
18
+ if (request = Thread.current[:sqreen_http_request])
19
+ request[:timed_callbacks] << t if request[:timed_level] >= 1
20
+ end
21
+ end
22
+
23
+ Proc.new do |*args, &block|
24
+ request = Thread.current[:sqreen_http_request]
25
+
26
+ if Thread.current[:sqreen_hook_entered]
27
+ if hook.point.super?
28
+ return super(*args, &block)
29
+ else
30
+ return hook.point.apply(self, 'sqreen_hook', *args, &block)
31
+ end
32
+ end
33
+
34
+ if request && request[:time_budget_expended] && (hook.before + hook.after + hook.raised + hook.ensured).none?(&:mandatory)
35
+ if request[:timed_level] >= 2
36
+ begin
37
+ request[:skipped_callbacks].concat(hook.before)
38
+
39
+ if hook.point.super?
40
+ return super(*args, &block)
41
+ else
42
+ return hook.point.apply(self, 'sqreen_hook', *args, &block)
43
+ end
44
+ rescue ::Exception # rubocop:disable Lint/RescueException
45
+ request[:skipped_callbacks].concat(hook.raised)
46
+ raise
47
+ else
48
+ request[:skipped_callbacks].concat(hook.after)
49
+ ensure
50
+ request[:skipped_callbacks].concat(hook.ensured)
51
+ end
52
+ else
53
+ if hook.point.super? # rubocop:disable Style/IfInsideElse
54
+ return super(*args, &block)
55
+ else
56
+ return hook.point.apply(self, 'sqreen_hook', *args, &block)
57
+ end
58
+ end
59
+ end
60
+
61
+ hook_point_super = hook.point.super?
62
+ logger = Sqreen::Graft.logger
63
+ logger_debug = Sqreen::Graft.logger.debug?
64
+
65
+ Timer.new(hook.point, &timed_hooks_proc).measure do |chrono|
66
+ # budget implies request
67
+ # TODO: make budget depend on a generic context (currently "request")
68
+ budget = request[:time_budget] if request
69
+ if budget
70
+ budget_threshold = request[:time_budget_threshold]
71
+ budget_ratio = request[:time_budget_ratio]
72
+ sqreen_timer = request[:sqreen_timer]
73
+ request_timer = request[:request_timer]
74
+ end
75
+
76
+ hooked_call = HookedCall.new(self, args)
77
+
78
+ begin
79
+ begin
80
+ sqreen_timer.start if budget
81
+ Thread.current[:sqreen_hook_entered] = true
82
+
83
+ # TODO: make Call have #ball to throw by cb
84
+ # TODO: can Call be the ball? r = catch(Call.new, &c)
85
+ # TODO: is catch return value a Call? a #dispatch?
86
+ # TODO: make before/after/raised return a CallbackCollection << Array (or extend with module)
87
+ # TODO: add CallbackCollection#each_with_call(instance, args) { |call| ... } ?
88
+ # TODO: HookCall x CallbackCollection#each_with_call x Flow
89
+ # TODO: TimedHookCall TimedCallbackCall
90
+ # TODO: TimeBoundHookCall TimeBoundCallbackCall TimeBoundFlow?
91
+
92
+ request_elapsed = request_timer.elapsed if budget
93
+
94
+ hook.before.each do |c|
95
+ next if c.ignore && c.ignore.call
96
+
97
+ if budget && !c.mandatory
98
+ sqreen_elapsed = sqreen_timer.elapsed
99
+ if budget_ratio && !request[:time_budget_expended]
100
+ fixed_budget = budget_threshold
101
+ proportional_budget = (request_elapsed - sqreen_elapsed) * budget_ratio
102
+ remaining = (fixed_budget > proportional_budget ? fixed_budget : proportional_budget) - sqreen_elapsed
103
+ else
104
+ remaining = budget_threshold - sqreen_elapsed
105
+ end
106
+ unless remaining > 0
107
+ request[:skipped_callbacks] << c
108
+ request[:time_budget_expended] = true
109
+ next
110
+ end
111
+ end
112
+
113
+ flow = catch(Ball.new) do |ball|
114
+ Timer.new(c.name, &timed_callbacks_proc).measure(ignore: chrono) do
115
+ c.call(CallbackCall.new(c, remaining, hooked_call.instance, hooked_call.args_passed), ball)
116
+ end
117
+ end
118
+
119
+ next unless c.flow && flow.is_a?(Flow)
120
+ hooked_call.raise = flow.raise and hooked_call.raising = true if flow.raise?
121
+ hooked_call.args_pass = flow.args and hooked_call.args_passing = true if flow.args?
122
+ hooked_call.return = flow.return and hooked_call.returning = true if flow.return?
123
+ break if flow.break?
124
+ end unless hook.disabled?
125
+ rescue StandardError => e
126
+ Sqreen::Weave.logger.debug { "exception:#{e.class} when:before message:'#{e.message}' location:\"#{e.backtrace[0]}\"" }
127
+ Sqreen::RemoteException.record(e) if Sqreen.queue
128
+ end
129
+
130
+ raise hooked_call.raise if hooked_call.raising
131
+ return hooked_call.return if hooked_call.returning
132
+ ensure
133
+ Thread.current[:sqreen_hook_entered] = false
134
+ sqreen_timer.stop if budget
135
+ end unless hook.before.empty?
136
+
137
+ begin
138
+ chrono.ignore do
139
+ if hook_point_super
140
+ hooked_call.returned = super(*(hooked_call.args_passing ? hooked_call.args_pass : hooked_call.args_passed), &block)
141
+ else
142
+ hooked_call.returned = hook.point.apply(hooked_call.instance, 'sqreen_hook', *(hooked_call.args_passing ? hooked_call.args_pass : hooked_call.args_passed), &block)
143
+ end
144
+ end
145
+ rescue ::Exception => e # rubocop:disable Lint/RescueException
146
+ begin
147
+ sqreen_timer.start if budget
148
+ Thread.current[:sqreen_hook_entered] = true
149
+ hooked_call.raised = e
150
+
151
+ logger.debug { "[#{Process.pid}] Hook #{hook.point} disabled:#{hook.disabled?} exception:#{e}" } if logger_debug
152
+
153
+ # TODO: early escape causes raise too early then caught by ensure which mistakenly reports legit errors to sqreen
154
+ # raise if hook.raised.empty?
155
+
156
+ request_elapsed = request_timer.elapsed if budget
157
+
158
+ hook.raised.each do |c|
159
+ next if c.ignore && c.ignore.call
160
+
161
+ if budget && !c.mandatory
162
+ sqreen_elapsed = sqreen_timer.elapsed
163
+ if budget_ratio && !request[:time_budget_expended]
164
+ fixed_budget = budget_threshold
165
+ proportional_budget = (request_elapsed - sqreen_elapsed) * budget_ratio
166
+ remaining = (fixed_budget > proportional_budget ? fixed_budget : proportional_budget) - sqreen_elapsed
167
+ else
168
+ remaining = budget_threshold - sqreen_elapsed
169
+ end
170
+ unless remaining > 0
171
+ request[:skipped_callbacks] << c
172
+ request[:time_budget_expended] = true
173
+ next
174
+ end
175
+ end
176
+
177
+ flow = catch(Ball.new) do |ball|
178
+ Timer.new(c.name, &timed_callbacks_proc).measure(ignore: chrono) do
179
+ c.call(CallbackCall.new(c, remaining, hooked_call.instance, hooked_call.args_passing ? hooked_call.args_pass : hooked_call.args_passed, hooked_call.raised), ball)
180
+ end
181
+ end
182
+
183
+ next unless c.flow && flow.is_a?(Flow)
184
+ hooked_call.raise = flow.raise and hooked_call.raising = true if flow.raise?
185
+ hooked_call.return = flow.return and hooked_call.returning = true if flow.return?
186
+ hooked_call.retrying = true if flow.retry?
187
+ break if flow.break?
188
+ end unless hook.disabled?
189
+ rescue StandardError => e
190
+ Sqreen::Weave.logger.debug { "exception:#{e.class} when:raised message:'#{e.message}' location:\"#{e.backtrace[0]}\"" }
191
+ Sqreen::RemoteException.record(e) if Sqreen.queue
192
+ end
193
+
194
+ retry if hooked_call.retrying
195
+ raise hooked_call.raise if hooked_call.raising
196
+ return hooked_call.return if hooked_call.returning
197
+ raise
198
+ else
199
+ begin
200
+ sqreen_timer.start if budget
201
+ Thread.current[:sqreen_hook_entered] = true
202
+
203
+ # TODO: hooked_call.returning should be always false here?
204
+ return hooked_call.returning ? hooked_call.return : hooked_call.returned if hook.after.empty?
205
+
206
+ request_elapsed = request_timer.elapsed if budget
207
+
208
+ hook.after.each do |c|
209
+ next if c.ignore && c.ignore.call
210
+
211
+ if budget && !c.mandatory
212
+ sqreen_elapsed = sqreen_timer.elapsed
213
+ if budget_ratio && !request[:time_budget_expended]
214
+ fixed_budget = budget_threshold
215
+ proportional_budget = (request_elapsed - sqreen_elapsed) * budget_ratio
216
+ remaining = (fixed_budget > proportional_budget ? fixed_budget : proportional_budget) - sqreen_elapsed
217
+ else
218
+ remaining = budget_threshold - sqreen_elapsed
219
+ end
220
+ unless remaining > 0
221
+ request[:skipped_callbacks] << c
222
+ request[:time_budget_expended] = true
223
+ next
224
+ end
225
+ end
226
+
227
+ flow = catch(Ball.new) do |ball|
228
+ Timer.new(c.name, &timed_callbacks_proc).measure(ignore: chrono) do
229
+ c.call(CallbackCall.new(c, remaining, hooked_call.instance, hooked_call.args_passing ? hooked_call.args_pass : hooked_call.args_passed, nil, hooked_call.returned), ball)
230
+ end
231
+ end
232
+
233
+ next unless c.flow && flow.is_a?(Flow)
234
+ hooked_call.raise = flow.raise and hooked_call.raising = true if flow.raise?
235
+ hooked_call.return = flow.return and hooked_call.returning = true if flow.return?
236
+ break if flow.break?
237
+ end unless hook.disabled?
238
+ rescue StandardError => e
239
+ Sqreen::Weave.logger.debug { "exception:#{e.class} when:after message:'#{e.message}' location:\"#{e.backtrace[0]}\"" }
240
+ Sqreen::RemoteException.record(e) if Sqreen.queue
241
+ end
242
+
243
+ raise hooked_call.raise if hooked_call.raising
244
+ return hooked_call.returning ? hooked_call.return : hooked_call.returned
245
+ ensure
246
+ begin
247
+ # TODO: sqreen_timer.start if someone has thrown?
248
+ # TODO: sqreen_timer.stop at end of rescue+else?
249
+ # TODO: Thread.current[:sqreen_hook_entered] = true if neither rescue nor else ie thrown?
250
+ # TODO: Thread.current[:sqreen_hook_entered] = false at end of rescue+else? (risky?)
251
+
252
+ # TODO: uniform early bail out? (but don't forget sqreen_hook_entered and sqreen_timer)
253
+ # return hooked_call.returning ? hooked_call.return : hooked_call.returned if hook.ensured.empty?
254
+
255
+ # done at either rescue or else
256
+ # request_elapsed = request_timer.elapsed if budget # && !hook.ensured.empty?
257
+
258
+ hook.ensured.each do |c|
259
+ next if c.ignore && c.ignore.call
260
+
261
+ if budget && !c.mandatory
262
+ sqreen_elapsed = sqreen_timer.elapsed
263
+ if budget_ratio && !request[:time_budget_expended]
264
+ fixed_budget = budget_threshold
265
+ proportional_budget = (request_elapsed - sqreen_elapsed) * budget_ratio
266
+ remaining = (fixed_budget > proportional_budget ? fixed_budget : proportional_budget) - sqreen_elapsed
267
+ else
268
+ remaining = budget_threshold - sqreen_elapsed
269
+ end
270
+ unless remaining > 0
271
+ request[:skipped_callbacks] << c
272
+ request[:time_budget_expended] = true
273
+ next
274
+ end
275
+ end
276
+
277
+ flow = catch(Ball.new) do |ball|
278
+ Timer.new(c.name, &timed_callbacks_proc).measure(ignore: chrono) do
279
+ c.call(CallbackCall.new(c, remaining, hooked_call.instance, hooked_call.args_passing ? hooked_call.args_pass : hooked_call.args_passed, nil, hooked_call.returned), ball)
280
+ end
281
+ end
282
+
283
+ next unless c.flow && flow.is_a?(Flow)
284
+ hooked_call.raise = flow.raise and hooked_call.raising = true if flow.raise?
285
+ hooked_call.return = flow.return and hooked_call.returning = true if flow.return?
286
+ break if flow.break?
287
+ end unless hook.ensured.empty? || hook.disabled?
288
+
289
+ Thread.current[:sqreen_hook_entered] = false
290
+ sqreen_timer.stop if budget
291
+ rescue StandardError => e
292
+ Sqreen::Weave.logger.debug { "exception:#{e.class} when:ensured message:'#{e.message}' location:\"#{e.backtrace[0]}\"" }
293
+ Sqreen::RemoteException.record(e) if Sqreen.queue
294
+ end
295
+
296
+ # TODO: should we run the following?
297
+ # raise hooked_call.raise if hooked_call.raising
298
+ # return hooked_call.returning ? hooked_call.return : hooked_call.returned
299
+ end
300
+ end # chrono
301
+ end
302
+ end
303
+ end
304
+ end
305
+ end