sqreen 1.20.4-java → 1.21.0.beta3-java

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 (54) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +15 -24
  3. data/lib/sqreen/condition_evaluator.rb +6 -5
  4. data/lib/sqreen/conditionable.rb +24 -6
  5. data/lib/sqreen/deliveries/batch.rb +8 -1
  6. data/lib/sqreen/ecosystem/dispatch_table.rb +43 -0
  7. data/lib/sqreen/ecosystem/exception_reporting.rb +26 -0
  8. data/lib/sqreen/ecosystem/http/net_http.rb +50 -0
  9. data/lib/sqreen/ecosystem/http/rack_request.rb +39 -0
  10. data/lib/sqreen/ecosystem/loggable.rb +13 -0
  11. data/lib/sqreen/ecosystem/module_api/event_listener.rb +18 -0
  12. data/lib/sqreen/ecosystem/module_api/instrumentation.rb +23 -0
  13. data/lib/sqreen/ecosystem/module_api/message_producer.rb +51 -0
  14. data/lib/sqreen/ecosystem/module_api/signal_producer.rb +24 -0
  15. data/lib/sqreen/ecosystem/module_api/tracing/client_data.rb +31 -0
  16. data/lib/sqreen/ecosystem/module_api/tracing/server_data.rb +27 -0
  17. data/lib/sqreen/ecosystem/module_api/tracing.rb +45 -0
  18. data/lib/sqreen/ecosystem/module_api/tracing_id_generation.rb +16 -0
  19. data/lib/sqreen/ecosystem/module_api/transaction_storage.rb +71 -0
  20. data/lib/sqreen/ecosystem/module_api.rb +30 -0
  21. data/lib/sqreen/ecosystem/module_registry.rb +44 -0
  22. data/lib/sqreen/ecosystem/redis/redis_connection.rb +43 -0
  23. data/lib/sqreen/ecosystem/tracing/modules/client.rb +31 -0
  24. data/lib/sqreen/ecosystem/tracing/modules/server.rb +30 -0
  25. data/lib/sqreen/ecosystem/tracing/sampler.rb +160 -0
  26. data/lib/sqreen/ecosystem/tracing/sampling_configuration.rb +150 -0
  27. data/lib/sqreen/ecosystem/tracing/signals/tracing_client.rb +53 -0
  28. data/lib/sqreen/ecosystem/tracing/signals/tracing_server.rb +53 -0
  29. data/lib/sqreen/ecosystem/tracing_broker.rb +101 -0
  30. data/lib/sqreen/ecosystem/tracing_id_setup.rb +34 -0
  31. data/lib/sqreen/ecosystem/transaction_storage.rb +64 -0
  32. data/lib/sqreen/ecosystem/util/call_writers_from_init.rb +13 -0
  33. data/lib/sqreen/ecosystem.rb +96 -0
  34. data/lib/sqreen/ecosystem_integration/around_callbacks.rb +99 -0
  35. data/lib/sqreen/ecosystem_integration/instrumentation_service.rb +42 -0
  36. data/lib/sqreen/ecosystem_integration/request_lifecycle_tracking.rb +58 -0
  37. data/lib/sqreen/ecosystem_integration/signal_consumption.rb +35 -0
  38. data/lib/sqreen/ecosystem_integration.rb +87 -0
  39. data/lib/sqreen/frameworks/generic.rb +15 -1
  40. data/lib/sqreen/graft/call.rb +30 -1
  41. data/lib/sqreen/graft/hook.rb +88 -78
  42. data/lib/sqreen/graft/hook_point.rb +17 -10
  43. data/lib/sqreen/legacy/old_event_submission_strategy.rb +7 -1
  44. data/lib/sqreen/metrics/req_detailed.rb +41 -0
  45. data/lib/sqreen/metrics.rb +1 -0
  46. data/lib/sqreen/remote_command.rb +3 -0
  47. data/lib/sqreen/rules/rule_cb.rb +2 -2
  48. data/lib/sqreen/runner.rb +44 -15
  49. data/lib/sqreen/session.rb +2 -0
  50. data/lib/sqreen/signals/conversions.rb +6 -1
  51. data/lib/sqreen/version.rb +1 -1
  52. data/lib/sqreen/weave/budget.rb +3 -14
  53. data/lib/sqreen/weave/legacy/instrumentation.rb +145 -94
  54. metadata +41 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 67f60f1ad0bd4392e5a60272ef50f406aa511a5e
4
- data.tar.gz: bbd2e7baacc6c6cdaa7bb95d06300fa325a5ef09
3
+ metadata.gz: 00e4d67d3fbef516336bc81d189df526cfd4e67c
4
+ data.tar.gz: d66dc33e04ec02c6f7e3118ba7d2727ee20dbd4d
5
5
  SHA512:
6
- metadata.gz: 86bdc374c4a1e7a01cfc371ef975fd17d6e58709a06dde323a8b7006766472cd974f4fb22ce663c693b840d3cbb19556d7cb0310df931217872283da5f1c2292
7
- data.tar.gz: 6ee3811d3d1292d8b4d818323624b98837cb24c4f62f994f83a6c1b6d0eb3616961067073f20527ef0f246ad5f2665fe0c193d2b8ed79d95642ccb02d2125d7c
6
+ metadata.gz: b9ea001f33c1daf64e8e6cecfdb3463f70c67bbec7db64b1b138216178a769451b0190d3101a67d0b0d5326f7cb3d717fb0b277720fbedcdeefb9bfcaf05018a
7
+ data.tar.gz: f56453335a9e3340e5434b376322a8e0993df25ddfb16df34c26e88aa30eccb3bab4bb31c04a0c6174f5119f65a2ede9d3732103809ee12ffa8da1d22213c361
data/CHANGELOG.md CHANGED
@@ -1,27 +1,18 @@
1
- ## 1.20.4
2
-
3
- * Fix missing budget check
4
- * Improve performance
5
- * Align internal setting name for WAF
6
- * Include response information in all payloads
7
- * Improve robustness against invalid Unicode
8
- * Prevent rule execution to pursue in early block cases
9
-
10
- ## 1.20.4.beta1
11
-
12
- * Add optional dynamic time budget
13
- * Add advanced per request metrics
14
- * Improve robustness against exception in instrumentation
15
- * Improve metric engine thread safety
16
- * Restrict deferred logger to final logger severity on agent boot
17
-
18
- ## 1.20.3
19
-
20
- * Fix signature check
21
-
22
- ## 1.20.2
23
-
24
- * Fix performance regression in instrumentation engine
1
+ ## 1.21.0.beta3
2
+
3
+ * Avoid fd leak in `custom_error_cb` (ARB-109)
4
+ * Support `skip_rem_cbs` (ARB-107)
5
+ * Fix instrumentation in Ruby 2.0
6
+ * Fix encoding exception on `hash_key_include` (ARB-53)
7
+ * Fix erroneous start in non-Rails context (SQREEN-880)
8
+ * Make metrics thread-safe
9
+ * Add restart command
10
+ * Fix `overtime_cb`
11
+ * Add `perf_level` 2
12
+ * Several performance optimizations
13
+ * WAF: rename `budget_in_ms` to `max_budget_ms`
14
+ * Transport/Tracing with http module
15
+ * Update the blocking page
25
16
 
26
17
  ## 1.20.1
27
18
 
@@ -81,11 +81,12 @@ module Sqreen
81
81
  if hkey.respond_to?(:empty?) && hkey.empty?
82
82
  false
83
83
  else
84
- key_incl = if values.is_a?(String)
85
- str_include?(values, hkey.to_s)
86
- else
87
- values.include?(hkey.to_s)
88
- end
84
+ key_incl =
85
+ if values.is_a?(String)
86
+ str_include? values, hkey.to_s
87
+ else
88
+ values.include?(hkey.to_s)
89
+ end
89
90
 
90
91
  key_incl || hash_key_include?(values, hval, min_value_size, rem - 1)
91
92
  end
@@ -28,21 +28,39 @@ module Sqreen
28
28
  end
29
29
 
30
30
  def pre_with_conditions(inst, args, budget = nil, &block)
31
+ return pre_without_conditions(inst, args, budget, &block) if pre_conditions.nil?
32
+
31
33
  eargs = [nil, framework, inst, args, @data, nil]
32
- return nil if !pre_conditions.nil? && !pre_conditions.evaluate(*eargs)
33
- pre_without_conditions(inst, args, budget, &block)
34
+ return nil unless pre_conditions.evaluate(*eargs)
35
+
36
+ res = pre_without_conditions(inst, args, budget, &block)
37
+ return { passed_conditions: true } unless res.is_a?(Hash)
38
+ res[:passed_conditions] = true
39
+ res
34
40
  end
35
41
 
36
42
  def post_with_conditions(rv, inst, args, budget = nil, &block)
43
+ return post_without_conditions(rv, inst, args, budget, &block) if post_conditions.nil?
44
+
37
45
  eargs = [nil, framework, inst, args, @data, rv]
38
- return nil if !post_conditions.nil? && !post_conditions.evaluate(*eargs)
39
- post_without_conditions(rv, inst, args, budget, &block)
46
+ return nil unless post_conditions.evaluate(*eargs)
47
+
48
+ res = post_without_conditions(rv, inst, args, budget, &block)
49
+ return { passed_conditions: true } if res.nil?
50
+ res[:passed_conditions] = true
51
+ res
40
52
  end
41
53
 
42
54
  def failing_with_conditions(rv, inst, args, budget = nil, &block)
55
+ return failing_without_conditions(rv, inst, args, budget, &block) if failing_conditions.nil?
56
+
43
57
  eargs = [nil, framework, inst, args, @data, rv]
44
- return nil if !failing_conditions.nil? && !failing_conditions.evaluate(*eargs)
45
- failing_without_conditions(rv, inst, args, budget, &block)
58
+ return nil unless failing_conditions.evaluate(*eargs)
59
+
60
+ res = failing_without_conditions(rv, inst, args, budget, &block)
61
+ return { passed_conditions: true } if res.nil?
62
+ res[:passed_conditions] = true
63
+ res
46
64
  end
47
65
 
48
66
  protected
@@ -13,6 +13,8 @@ require 'sqreen/events/attack'
13
13
  require 'sqreen/events/remote_exception'
14
14
  require 'sqreen/mono_time'
15
15
  require 'sqreen/deliveries/simple'
16
+ require 'sqreen/kit/signals/signal'
17
+ require 'sqreen/kit/signals/trace'
16
18
 
17
19
  module Sqreen
18
20
  module Deliveries
@@ -58,7 +60,7 @@ module Sqreen
58
60
  def post_batch_needed?(event)
59
61
  now = Sqreen.time
60
62
  # do not use any? {} due to side effects inside block
61
- event_keys(event).map do |key|
63
+ event_keys(event).uniq.map do |key|
62
64
  was = @first_seen[key]
63
65
  @first_seen[key] ||= now
64
66
  was.nil? || current_batch.size > max_batch || now > (was + max_staleness)
@@ -86,6 +88,7 @@ module Sqreen
86
88
  res += event.observed.fetch(:sdk, []).select { |e|
87
89
  e[0] == :track
88
90
  }.map { |e| "sdk-track".freeze }
91
+ res += event.observed.fetch(:signals, []).map { "signal".freeze }
89
92
  return res
90
93
  end
91
94
 
@@ -97,6 +100,10 @@ module Sqreen
97
100
  "rex-#{event.klass}"
98
101
  when Sqreen::AggregatedMetric
99
102
  "agg-metric"
103
+ when Sqreen::Kit::Signals::Signal
104
+ "signal"
105
+ when Sqreen::Kit::Signals::Trace
106
+ "signal"
100
107
  end
101
108
  end
102
109
  end
@@ -0,0 +1,43 @@
1
+ require 'logger'
2
+
3
+ module Sqreen
4
+ module Ecosystem
5
+ # Configured by the ecosystem client
6
+ module DispatchTable
7
+ class << self
8
+ # data consumption
9
+ # argument: +Sqreen::Kit::Signals::Signal+
10
+ # see +Sqreen::EcosystemIntegration::SignalConsumption#consume_signal+
11
+ attr_accessor :consume_signal
12
+
13
+ # argument: block taking a Rack::Request
14
+ # see +Sqreen::EcosystemIntegration::RequestLifecycleTracking#add_start_observer+
15
+ attr_accessor :add_request_start_listener
16
+
17
+ attr_accessor :fetch_logger
18
+
19
+ # argument: callback taking:
20
+ # * the method to instrument
21
+ # * A Hash{Symbol=>Proc} with the advice. The proc takes the
22
+ # arguments and the ball, so these details of the instrumentation
23
+ # implementation leak through the abstraction
24
+ # see +Sqreen::EcosystemIntegration::InstrumentationService+
25
+ attr_accessor :instrument
26
+
27
+ def reset
28
+ instance_variables.each do |ia|
29
+ instance_variable_set(ia, nil)
30
+ end
31
+
32
+ # set default logger
33
+ logger = ::Logger.new(STDERR)
34
+ logger.level = ::Logger::WARN
35
+ logger.progname = 'sqreen-ecosystem'
36
+ self.fetch_logger = proc { logger }
37
+ end
38
+ end
39
+
40
+ reset
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,26 @@
1
+ require 'sqreen/ecosystem/dispatch_table'
2
+ require 'sqreen/ecosystem/loggable'
3
+ require 'sqreen/kit/signals/specialized/sqreen_exception'
4
+
5
+ module Sqreen
6
+ module Ecosystem
7
+ module ExceptionReporting
8
+ include Loggable
9
+
10
+ private
11
+
12
+ # @param [String] message
13
+ # @param [Exception] e
14
+ def report_exception(message, e)
15
+ logger.warn { "#{message}: #{e.message}" }
16
+ logger.debug { e.backtrace.map { |x| " #{x}" }.join("\n") }
17
+
18
+ signal = Sqreen::Kit::Signals::Specialized::SqreenException.new(
19
+ ruby_exception: e
20
+ )
21
+
22
+ DispatchTable.consume_signal signal
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,50 @@
1
+ require 'sqreen/ecosystem/module_api'
2
+ require 'sqreen/ecosystem/module_api/instrumentation'
3
+ require 'sqreen/ecosystem/module_api/message_producer'
4
+ require 'sqreen/ecosystem/module_api/tracing_id_generation'
5
+ require 'sqreen/ecosystem/module_api/tracing/client_data'
6
+
7
+ module Sqreen
8
+ module Ecosystem
9
+ module Http
10
+ class NetHttp
11
+ class HttpConnectionData
12
+ include ModuleApi::Tracing::ClientData
13
+ end
14
+
15
+ include ModuleApi::Instrumentation
16
+ include ModuleApi::MessageProducer
17
+ include ModuleApi::TracingIdGeneration
18
+
19
+ def setup
20
+ advice = wrap_for_interest(HttpConnectionData, &method(:before_advice))
21
+ instrument 'Net::HTTP#request', before: advice
22
+ end
23
+
24
+ private
25
+
26
+ # instr. def request(req, body = nil, &block) # :yield: +response+
27
+ # req is of type +Net::HTTPGenericRequest+
28
+ def before_advice(call, _ball)
29
+ tracing_id = create_tracing_id
30
+
31
+ # build & submit signal
32
+ host = call.instance.address
33
+ port = call.instance.port
34
+
35
+ # add tracing header
36
+ req = call.args[0]
37
+ req[ModuleApi::TRACE_ID_HEADER] = tracing_id
38
+
39
+ host += ':' + port.to_s if port != 80 && port != 443
40
+
41
+ HttpConnectionData.new(
42
+ transport: 'http',
43
+ host: host,
44
+ tracing_identifier: tracing_id
45
+ )
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,39 @@
1
+ require 'sqreen/ecosystem/module_api'
2
+ require 'sqreen/ecosystem/module_api/event_listener'
3
+ require 'sqreen/ecosystem/module_api/message_producer'
4
+ require 'sqreen/ecosystem/module_api/tracing/server_data'
5
+
6
+ module Sqreen
7
+ module Ecosystem
8
+ module Http
9
+ class RackRequest
10
+ class HttpServerData
11
+ include ModuleApi::Tracing::ServerData
12
+ end
13
+
14
+ include ModuleApi::EventListener
15
+ include ModuleApi::MessageProducer
16
+
17
+ def setup
18
+ advice = wrap_for_interest(
19
+ ModuleApi::Tracing::ServerData,
20
+ &method(:handle_request)
21
+ )
22
+ on_request_start(&advice)
23
+ end
24
+
25
+ private
26
+
27
+ def handle_request(rack_request)
28
+ trace_id = rack_request.env[ModuleApi::TRACE_ID_ENV_KEY]
29
+
30
+ HttpServerData.new(
31
+ transport: 'http',
32
+ client_ip: rack_request.ip,
33
+ tracing_identifier: trace_id
34
+ )
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,13 @@
1
+ require 'sqreen/ecosystem/dispatch_table'
2
+
3
+ module Sqreen
4
+ module Ecosystem
5
+ module Loggable
6
+ private
7
+
8
+ def logger
9
+ DispatchTable.fetch_logger.call
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,18 @@
1
+ require 'sqreen/ecosystem/dispatch_table'
2
+
3
+ module Sqreen
4
+ module Ecosystem
5
+ module ModuleApi
6
+ module EventListener
7
+ private
8
+
9
+ # XXX: callbacks need to be wrapped in order ot handle
10
+ # perfcap, exceptions, and maybe other concerns applying
11
+ # across the board
12
+ def on_request_start(&cb)
13
+ DispatchTable.add_request_start_listener.call(cb)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,23 @@
1
+ require 'sqreen/ecosystem/module_api'
2
+
3
+ module Sqreen
4
+ module Ecosystem
5
+ module ModuleApi
6
+ module Instrumentation
7
+ def self.included(mod)
8
+ mod.send :include, ModuleApi unless mod.ancestors.include?(ModuleApi)
9
+ end
10
+
11
+ private
12
+
13
+ # Just forwards the call to the instrumentation service
14
+ # @param [String] method
15
+ # @param [Hash{Symbol=>Proc}] advice keys are one of: :before, :after,
16
+ # :raised,
17
+ def instrument(method, advice)
18
+ DispatchTable.instrument.call(self.class.module_name, method, advice)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,51 @@
1
+ require 'sqreen/ecosystem/loggable'
2
+
3
+ module Sqreen
4
+ module Ecosystem
5
+ module ModuleApi
6
+ module MessageProducer
7
+ include Loggable
8
+
9
+ # method for ecosystem to inject the config
10
+ # @param [Sqreen::Ecosystem::TracingBroker]
11
+ attr_writer :tracing_broker
12
+
13
+ private
14
+
15
+ def determine_interest(type, hints = {})
16
+ @tracing_broker.interested_consumers(type, hints)
17
+ end
18
+
19
+ def publish(data, interested)
20
+ @tracing_broker.publish(data, interested)
21
+ end
22
+
23
+ # Convenience wrapper.
24
+ # Wraps a callback, skipping it if there is no interest in the type
25
+ # produced and submitting the return value as a message to the
26
+ # tracing broker
27
+ def wrap_for_interest(type, gen_hints = nil, &block)
28
+ raise ArgumentError, 'no block passed' if block.nil?
29
+
30
+ proc do |*args|
31
+ hints = gen_hints[*args] if gen_hints
32
+ interested = determine_interest(type, hints || {})
33
+
34
+ unless interested
35
+ logger.debug { "No interested consumers in #{type}" }
36
+ next
37
+ end
38
+
39
+ res = block[*args]
40
+
41
+ next if res.nil?
42
+
43
+ raise 'unexpected return type' unless res.is_a?(type)
44
+
45
+ @tracing_broker.publish(res, interested)
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,24 @@
1
+ require 'sqreen/ecosystem/dispatch_table'
2
+
3
+ module Sqreen
4
+ module Ecosystem
5
+ module ModuleApi
6
+ module SignalProducer
7
+ # for injection
8
+ # callable taking no arguments and generating a tracing id
9
+ attr_writer :tracing_id_producer
10
+
11
+ private
12
+
13
+ def create_tracing_id
14
+ @tracing_id_producer.call
15
+ end
16
+
17
+ # @param [Sqreen::Kit::Signals::Signal] signal
18
+ def submit_signal(signal)
19
+ DispatchTable.consume_signal.call(signal)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,31 @@
1
+ require 'sqreen/ecosystem/util/call_writers_from_init'
2
+
3
+ module Sqreen
4
+ module Ecosystem
5
+ module ModuleApi
6
+ module Tracing
7
+ # The data the tracing module needs in order to populate
8
+ # +Sqreen::Ecosystem::Tracing::Signals::TracingClient::Payload+
9
+ #
10
+ # Signals are not produced by the data producers (transport)
11
+ # because of superior orders, as the only current use of this
12
+ # data is to generate signals.
13
+ module ClientData
14
+ include Util::CallWritersFromInit
15
+
16
+ # @return [Symbol]
17
+ attr_accessor :transport
18
+
19
+ # @return [String]
20
+ attr_accessor :host
21
+
22
+ # @return [String]
23
+ attr_accessor :ip
24
+
25
+ # @return [String]
26
+ attr_accessor :tracing_identifier
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,27 @@
1
+ require 'sqreen/ecosystem/util/call_writers_from_init'
2
+
3
+ module Sqreen
4
+ module Ecosystem
5
+ module ModuleApi
6
+ module Tracing
7
+ # The data the tracing module needs in order to populate
8
+ # +Sqreen::Ecosystem::Tracing::Signals::TracingServer::Payload+
9
+ module ServerData
10
+ include Util::CallWritersFromInit
11
+
12
+ # @return [Symbol]
13
+ attr_accessor :transport
14
+
15
+ # @return [String]
16
+ attr_accessor :client_ip
17
+
18
+ # @return [Array<String>]
19
+ attr_accessor :previous_hops
20
+
21
+ # @return [String]
22
+ attr_accessor :tracing_identifier
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,45 @@
1
+ require 'sqreen/ecosystem/module_api/signal_producer'
2
+
3
+ module Sqreen
4
+ module Ecosystem
5
+ module ModuleApi
6
+ module Tracing
7
+ include SignalProducer
8
+
9
+ def self.included(mod)
10
+ mod.extend(ClassMethods)
11
+ end
12
+
13
+ module ClassMethods
14
+ private
15
+
16
+ # @param [Module] type The type the including module is interested in
17
+ def consumes(type)
18
+ @consumes = type
19
+ end
20
+
21
+ # A fixed (non-virtual) scope for this tracing module
22
+ # @param [String] scope
23
+ def fixed_scope(scope)
24
+ @fixed_scope = scope
25
+ end
26
+ end
27
+
28
+ def consumed_type
29
+ self.class.instance_variable_get(:@consumes) \
30
+ || raise('@consumes not specified')
31
+ end
32
+
33
+ def scope(_hints = {})
34
+ self.class.instance_variable_get(:@fixed_scope) \
35
+ || raise('@fixed_scope not set')
36
+ end
37
+
38
+ # including class must implement it
39
+ def receive(_data)
40
+ raise NotImplementedError
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,16 @@
1
+ module Sqreen
2
+ module Ecosystem
3
+ module ModuleApi
4
+ module TracingIdGeneration
5
+ # for injection
6
+ attr_writer :tracing_id_producer
7
+
8
+ private
9
+
10
+ def create_tracing_id
11
+ @tracing_id_producer.call
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,71 @@
1
+ require 'sqreen/ecosystem/transaction_storage'
2
+ require 'sqreen/ecosystem/loggable'
3
+
4
+ module Sqreen
5
+ module Ecosystem
6
+ module ModuleApi
7
+ module TransactionStorage
8
+ class TxLocalVariables
9
+ class << self
10
+ class << self
11
+ include Sqreen::Ecosystem::Loggable
12
+
13
+ private
14
+
15
+ def attr_reader(attr, _opts = {})
16
+ define_method attr do
17
+ tx_storage = Ecosystem::TransactionStorage.fetch_thread_local
18
+ return unless tx_storage
19
+ tx_storage[attr]
20
+ end
21
+ end
22
+
23
+ def attr_accessor(attr, opts = {})
24
+ # reader
25
+ attr_reader attr, opts
26
+
27
+ # writer (2 variants)
28
+ do_assign = proc do |value|
29
+ tx_storage = Ecosystem::TransactionStorage.fetch_thread_local
30
+ unless tx_storage
31
+ logger.debug do
32
+ "Assignment of tx local attribute #{attr} to #{value} has no effect"
33
+ end
34
+ return
35
+ end
36
+
37
+ tx_storage[attr] = value
38
+ end
39
+
40
+ if opts.fetch(:allow_overwrite, false)
41
+ define "#{attr}=", &do_assign
42
+ else
43
+ define_method "#{attr}=" do |value|
44
+ cur = public_send(attr)
45
+ unless cur.nil?
46
+ raise "Cannot override value of #{attr} from #{cur} with #{value}"
47
+ end
48
+
49
+ do_assign.call(value)
50
+ end
51
+ end
52
+ end
53
+ end # TxLocalVariables.singleton_class.singleton_class
54
+
55
+ # usage:
56
+ # attr_reader :xxx
57
+
58
+ # in the future, we'll possibly need to expose the full
59
+ # TransactionStorage to the modules, at least if we don't
60
+ # opt for a more structured fashion of data exchange between
61
+ # the modules.
62
+ end # TxLocalVariables.singleton_class
63
+ end # TxLocalVariables
64
+
65
+ def tx_local_vars
66
+ TxLocalVariables
67
+ end
68
+ end # TransactionStorage module
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,30 @@
1
+ require 'sqreen/ecosystem/loggable'
2
+
3
+ module Sqreen
4
+ module Ecosystem
5
+ # The API that the transport/tracing modules are written against
6
+ module ModuleApi
7
+ TRACE_ID_HEADER = 'X-Sqreen-Trace-Identifier'.freeze
8
+ TRACE_ID_ENV_KEY = 'HTTP_X_SQREEN_TRACE_IDENTIFIER'.freeze
9
+
10
+ Loggable = Sqreen::Ecosystem::Loggable
11
+
12
+ module ClassMethods
13
+ attr_writer :module_name
14
+
15
+ def module_name
16
+ if instance_variable_defined?(:@module_name)
17
+ @module_name
18
+ else
19
+ # to snake case
20
+ @module_name = to_s.sub(/.*::/, '').gsub(/([a-z])([A-Z])/, '\1_\2').downcase
21
+ end
22
+ end
23
+ end
24
+
25
+ def self.included(mod)
26
+ mod.extend(ClassMethods)
27
+ end
28
+ end
29
+ end
30
+ end