sqreen 1.20.1-java → 1.22.0-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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +40 -0
- data/lib/sqreen/actions/block_user.rb +1 -1
- data/lib/sqreen/actions/redirect_ip.rb +1 -1
- data/lib/sqreen/actions/redirect_user.rb +1 -1
- data/lib/sqreen/attack_detected.html +1 -2
- data/lib/sqreen/condition_evaluator.rb +8 -2
- data/lib/sqreen/configuration.rb +1 -1
- data/lib/sqreen/deferred_logger.rb +50 -14
- data/lib/sqreen/deliveries/batch.rb +8 -1
- data/lib/sqreen/dependency/detector.rb +11 -3
- data/lib/sqreen/dependency/new_relic.rb +10 -1
- data/lib/sqreen/deprecation.rb +38 -0
- data/lib/sqreen/ecosystem.rb +123 -0
- data/lib/sqreen/ecosystem/databases/database_connection_data.rb +23 -0
- data/lib/sqreen/ecosystem/databases/mongo.rb +39 -0
- data/lib/sqreen/ecosystem/databases/mysql.rb +54 -0
- data/lib/sqreen/ecosystem/databases/postgres.rb +51 -0
- data/lib/sqreen/ecosystem/databases/redis.rb +36 -0
- data/lib/sqreen/ecosystem/dispatch_table.rb +43 -0
- data/lib/sqreen/ecosystem/exception_reporting.rb +28 -0
- data/lib/sqreen/ecosystem/http/net_http.rb +50 -0
- data/lib/sqreen/ecosystem/http/rack_request.rb +39 -0
- data/lib/sqreen/ecosystem/loggable.rb +13 -0
- data/lib/sqreen/ecosystem/messaging/bunny.rb +61 -0
- data/lib/sqreen/ecosystem/messaging/kafka.rb +70 -0
- data/lib/sqreen/ecosystem/messaging/kinesis.rb +66 -0
- data/lib/sqreen/ecosystem/messaging/sqs.rb +68 -0
- data/lib/sqreen/ecosystem/module_api.rb +30 -0
- data/lib/sqreen/ecosystem/module_api/event_listener.rb +18 -0
- data/lib/sqreen/ecosystem/module_api/instrumentation.rb +23 -0
- data/lib/sqreen/ecosystem/module_api/message_producer.rb +57 -0
- data/lib/sqreen/ecosystem/module_api/signal_producer.rb +24 -0
- data/lib/sqreen/ecosystem/module_api/tracing.rb +45 -0
- data/lib/sqreen/ecosystem/module_api/tracing/client_data.rb +31 -0
- data/lib/sqreen/ecosystem/module_api/tracing/consumer_data.rb +13 -0
- data/lib/sqreen/ecosystem/module_api/tracing/messaging_data.rb +35 -0
- data/lib/sqreen/ecosystem/module_api/tracing/producer_data.rb +13 -0
- data/lib/sqreen/ecosystem/module_api/tracing/server_data.rb +27 -0
- data/lib/sqreen/ecosystem/module_api/tracing_id_generation.rb +16 -0
- data/lib/sqreen/ecosystem/module_api/transaction_storage.rb +71 -0
- data/lib/sqreen/ecosystem/module_registry.rb +48 -0
- data/lib/sqreen/ecosystem/tracing/modules/client.rb +35 -0
- data/lib/sqreen/ecosystem/tracing/modules/consumer.rb +35 -0
- data/lib/sqreen/ecosystem/tracing/modules/determine_ip.rb +28 -0
- data/lib/sqreen/ecosystem/tracing/modules/producer.rb +35 -0
- data/lib/sqreen/ecosystem/tracing/modules/server.rb +30 -0
- data/lib/sqreen/ecosystem/tracing/sampler.rb +160 -0
- data/lib/sqreen/ecosystem/tracing/sampling_configuration.rb +150 -0
- data/lib/sqreen/ecosystem/tracing/signals/tracing_client.rb +53 -0
- data/lib/sqreen/ecosystem/tracing/signals/tracing_consumer.rb +56 -0
- data/lib/sqreen/ecosystem/tracing/signals/tracing_producer.rb +56 -0
- data/lib/sqreen/ecosystem/tracing/signals/tracing_server.rb +53 -0
- data/lib/sqreen/ecosystem/tracing_broker.rb +101 -0
- data/lib/sqreen/ecosystem/tracing_id_setup.rb +34 -0
- data/lib/sqreen/ecosystem/transaction_storage.rb +64 -0
- data/lib/sqreen/ecosystem/util/call_writers_from_init.rb +13 -0
- data/lib/sqreen/ecosystem_integration.rb +81 -0
- data/lib/sqreen/ecosystem_integration/around_callbacks.rb +89 -0
- data/lib/sqreen/ecosystem_integration/instrumentation_service.rb +38 -0
- data/lib/sqreen/ecosystem_integration/request_lifecycle_tracking.rb +58 -0
- data/lib/sqreen/ecosystem_integration/signal_consumption.rb +35 -0
- data/lib/sqreen/events/request_record.rb +0 -1
- data/lib/sqreen/frameworks/generic.rb +36 -1
- data/lib/sqreen/frameworks/rails.rb +0 -7
- data/lib/sqreen/frameworks/request_recorder.rb +2 -0
- data/lib/sqreen/graft/call.rb +85 -18
- data/lib/sqreen/graft/callback.rb +1 -1
- data/lib/sqreen/graft/hook.rb +192 -88
- data/lib/sqreen/graft/hook_point.rb +18 -11
- data/lib/sqreen/kit/signals/specialized/sqreen_exception.rb +2 -0
- data/lib/sqreen/legacy/instrumentation.rb +22 -10
- data/lib/sqreen/legacy/old_event_submission_strategy.rb +9 -2
- data/lib/sqreen/log.rb +3 -2
- data/lib/sqreen/log/loggable.rb +1 -0
- data/lib/sqreen/logger.rb +24 -0
- data/lib/sqreen/metrics_store.rb +11 -0
- data/lib/sqreen/null_logger.rb +22 -0
- data/lib/sqreen/remote_command.rb +4 -0
- data/lib/sqreen/rules.rb +8 -4
- data/lib/sqreen/rules/blacklist_ips_cb.rb +2 -2
- data/lib/sqreen/rules/custom_error_cb.rb +3 -3
- data/lib/sqreen/rules/rule_cb.rb +2 -0
- data/lib/sqreen/rules/waf_cb.rb +3 -3
- data/lib/sqreen/runner.rb +47 -7
- data/lib/sqreen/session.rb +2 -0
- data/lib/sqreen/signals/conversions.rb +6 -1
- data/lib/sqreen/version.rb +1 -1
- data/lib/sqreen/weave/budget.rb +46 -0
- data/lib/sqreen/weave/legacy/instrumentation.rb +252 -109
- data/lib/sqreen/worker.rb +6 -2
- metadata +60 -11
- data/lib/sqreen/encoding_sanitizer.rb +0 -27
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
require 'thread'
|
|
2
|
+
require 'sqreen/ecosystem/loggable'
|
|
3
|
+
require 'sqreen/ecosystem/tracing/sampler'
|
|
4
|
+
|
|
5
|
+
module Sqreen
|
|
6
|
+
module Ecosystem
|
|
7
|
+
module Tracing
|
|
8
|
+
# tracing sampling configuration, as specified by the 2nd argument of the
|
|
9
|
+
# tracing_enable command.
|
|
10
|
+
# See https://github.com/sqreen/TechDoc/blob/master/content/specs/spec000025-enabling-tracing.md
|
|
11
|
+
class SamplingConfiguration
|
|
12
|
+
include Loggable
|
|
13
|
+
|
|
14
|
+
DEFAULT_SCOPE = '*'.freeze
|
|
15
|
+
|
|
16
|
+
def initialize(sampling_config)
|
|
17
|
+
@sampling_config = sampling_config
|
|
18
|
+
@samplers = {}
|
|
19
|
+
@samplers_virtual = build_virtual_holders(sampling_config)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# @param [String] scope either the scope or the part behind @ in a virtual scope
|
|
23
|
+
# @param [String] qualifier the part after @ in a virtual scope or nil
|
|
24
|
+
def should_sample?(scope, qualifier = nil)
|
|
25
|
+
if qualifier
|
|
26
|
+
fetch_sampler_virtual(scope, qualifier).should_sample?
|
|
27
|
+
else
|
|
28
|
+
fetch_sampler(scope).should_sample?
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def forget_virtual_scope(scope, qualifier)
|
|
33
|
+
holder = @samplers_virtual[scope]
|
|
34
|
+
return unless holder.delete!(qualifier)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
private
|
|
38
|
+
|
|
39
|
+
def fetch_sampler_virtual(scope, qualifier)
|
|
40
|
+
holder = @samplers_virtual[scope]
|
|
41
|
+
|
|
42
|
+
# no virtual scope configured, fallback to plain scope
|
|
43
|
+
return fetch_sampler(scope) unless holder
|
|
44
|
+
|
|
45
|
+
holder[qualifier]
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def fetch_sampler(scope)
|
|
49
|
+
sampler = @samplers[scope]
|
|
50
|
+
return sampler if sampler
|
|
51
|
+
|
|
52
|
+
cfg = @sampling_config[scope] || @sampling_config[DEFAULT_SCOPE]
|
|
53
|
+
if cfg
|
|
54
|
+
@samplers[scope] = SamplingConfiguration.build_sampler(scope, cfg)
|
|
55
|
+
else
|
|
56
|
+
logger.info { "Disabling scope #{scope} due to its not being configured" }
|
|
57
|
+
@samplers[scope] = DisabledScopeSampler
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def build_virtual_holders(sampling_config)
|
|
62
|
+
Hash[
|
|
63
|
+
sampling_config
|
|
64
|
+
.select { |scope, _cfg| scope.end_with?('@*') }
|
|
65
|
+
.map do |scope, cfg|
|
|
66
|
+
parent = scope[0...-2] # remove trailing @*
|
|
67
|
+
[parent, VirtualScopesHolder.new(parent, cfg)]
|
|
68
|
+
end
|
|
69
|
+
]
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
class << self
|
|
73
|
+
include Loggable
|
|
74
|
+
|
|
75
|
+
def build_sampler(scope, cfg)
|
|
76
|
+
do_build_sampler(cfg['enabled'], cfg['sampling'] || [{}])
|
|
77
|
+
rescue StandardError => e
|
|
78
|
+
logger.warn "Invalid sampling configuration for #{scope}: #{e.inspect}"
|
|
79
|
+
logger.debug { e.backtrace }
|
|
80
|
+
DisabledScopeSampler
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
private
|
|
84
|
+
|
|
85
|
+
def do_build_sampler(enabled, sampling)
|
|
86
|
+
if enabled
|
|
87
|
+
Sampler.new(sampling)
|
|
88
|
+
else
|
|
89
|
+
logger.debug { "Disabling scope #{scope}" }
|
|
90
|
+
DisabledScopeSampler
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
class VirtualScopesHolder
|
|
97
|
+
include Loggable
|
|
98
|
+
|
|
99
|
+
MAX_VIRTUAL_SCOPES = 120
|
|
100
|
+
DISCARD_SIZE = 20
|
|
101
|
+
|
|
102
|
+
def initialize(parent, cfg)
|
|
103
|
+
@parent = parent
|
|
104
|
+
@cfg = cfg
|
|
105
|
+
@virtual_scopes = {}
|
|
106
|
+
@mutex = Mutex.new
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def [](qualifier)
|
|
110
|
+
return false unless @cfg['enabled']
|
|
111
|
+
|
|
112
|
+
@mutex.synchronize do
|
|
113
|
+
sampler = @virtual_scopes[qualifier]
|
|
114
|
+
return sampler if sampler
|
|
115
|
+
|
|
116
|
+
@virtual_scopes[qualifier] = create_virtual(qualifier)
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def delete!(qualifier)
|
|
121
|
+
@virtual_scopes.delete(qualifier)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
private
|
|
125
|
+
|
|
126
|
+
def create_virtual(qualifier)
|
|
127
|
+
discard if @virtual_scopes.size >= MAX_VIRTUAL_SCOPES
|
|
128
|
+
|
|
129
|
+
@virtual_scopes[qualifier] =
|
|
130
|
+
SamplingConfiguration.build_sampler("#{@parent}@#{qualifier}", @cfg)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def discard
|
|
134
|
+
logger.info { "Discarding excess virtual scopes for scope '#{@parent}'" }
|
|
135
|
+
discard_keys = @virtual_scopes.keys.sample(DISCARD_SIZE)
|
|
136
|
+
@virtual_scopes.delete_if { |k, _v| discard_keys.include? k }
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# fake sampler that always returns false
|
|
141
|
+
class DisabledScopeSampler
|
|
142
|
+
class << self
|
|
143
|
+
def should_sample?
|
|
144
|
+
false
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
require 'sqreen/kit/configuration'
|
|
2
|
+
require 'sqreen/kit/signals/point'
|
|
3
|
+
require 'sqreen/kit/signals/dto_helper'
|
|
4
|
+
|
|
5
|
+
# reference: https://github.com/sqreen/SignalsSchemas/blob/master/schemas/payload/tracing/client-2020-04-21/schema.cue
|
|
6
|
+
|
|
7
|
+
module Sqreen
|
|
8
|
+
module Ecosystem
|
|
9
|
+
module Tracing
|
|
10
|
+
module Signals
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
class Sqreen::Ecosystem::Tracing::Signals::TracingClient < Sqreen::Kit::Signals::Point
|
|
17
|
+
readonly_attrs :payload_schema, :source, :signal_name
|
|
18
|
+
|
|
19
|
+
def initialize(values = {})
|
|
20
|
+
self.payload_schema = Payload::SCHEMA_VERSION
|
|
21
|
+
self.source = Sqreen::Kit::Configuration.default_source
|
|
22
|
+
self.signal_name = 'tracing.client'
|
|
23
|
+
self.time = values[:time] || Time.now
|
|
24
|
+
super
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def payload=(payload)
|
|
28
|
+
unless payload.is_a?(Payload)
|
|
29
|
+
raise ArgumentError, "Payload should be a #{Payload}"
|
|
30
|
+
end
|
|
31
|
+
super
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
class Payload
|
|
35
|
+
include Sqreen::Kit::Signals::DtoHelper
|
|
36
|
+
|
|
37
|
+
add_mandatory_attrs :transport, :host
|
|
38
|
+
|
|
39
|
+
SCHEMA_VERSION = 'tracing/client-2020-04-21'.freeze
|
|
40
|
+
|
|
41
|
+
# @return [Symbol]
|
|
42
|
+
attr_accessor :transport
|
|
43
|
+
|
|
44
|
+
# @return [String]
|
|
45
|
+
attr_accessor :host
|
|
46
|
+
|
|
47
|
+
# @return [String]
|
|
48
|
+
attr_accessor :ip
|
|
49
|
+
|
|
50
|
+
# @return [String]
|
|
51
|
+
attr_accessor :tracing_identifier
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
require 'sqreen/kit/configuration'
|
|
2
|
+
require 'sqreen/kit/signals/point'
|
|
3
|
+
require 'sqreen/kit/signals/dto_helper'
|
|
4
|
+
|
|
5
|
+
# reference: https://github.com/sqreen/SignalsSchemas/blob/master/schemas/payload/tracing/consumer-2020-04-21/schema.cue
|
|
6
|
+
|
|
7
|
+
module Sqreen
|
|
8
|
+
module Ecosystem
|
|
9
|
+
module Tracing
|
|
10
|
+
module Signals
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
class Sqreen::Ecosystem::Tracing::Signals::TracingConsumer < Sqreen::Kit::Signals::Point
|
|
17
|
+
readonly_attrs :payload_schema, :source, :signal_name
|
|
18
|
+
|
|
19
|
+
def initialize(values = {})
|
|
20
|
+
self.payload_schema = Payload::SCHEMA_VERSION
|
|
21
|
+
self.source = Sqreen::Kit::Configuration.default_source
|
|
22
|
+
self.signal_name = 'tracing.consumer'
|
|
23
|
+
self.time = values[:time] || Time.now
|
|
24
|
+
super
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def payload=(payload)
|
|
28
|
+
unless payload.is_a?(Payload)
|
|
29
|
+
raise ArgumentError, "Payload should be a #{Payload}"
|
|
30
|
+
end
|
|
31
|
+
super
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
class Payload
|
|
35
|
+
include Sqreen::Kit::Signals::DtoHelper
|
|
36
|
+
|
|
37
|
+
add_mandatory_attrs :message_type, :host, :tracing_identifier
|
|
38
|
+
|
|
39
|
+
SCHEMA_VERSION = 'tracing/consumer-2020-04-21'.freeze
|
|
40
|
+
|
|
41
|
+
# @return [Symbol]
|
|
42
|
+
attr_accessor :message_type
|
|
43
|
+
|
|
44
|
+
# @return [String]
|
|
45
|
+
attr_accessor :host
|
|
46
|
+
|
|
47
|
+
# @return [String]
|
|
48
|
+
attr_accessor :ip
|
|
49
|
+
|
|
50
|
+
# @return [String]
|
|
51
|
+
attr_accessor :topic
|
|
52
|
+
|
|
53
|
+
# @return [String]
|
|
54
|
+
attr_accessor :tracing_identifier
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
require 'sqreen/kit/configuration'
|
|
2
|
+
require 'sqreen/kit/signals/point'
|
|
3
|
+
require 'sqreen/kit/signals/dto_helper'
|
|
4
|
+
|
|
5
|
+
# reference: https://github.com/sqreen/SignalsSchemas/blob/master/schemas/payload/tracing/producer-2020-04-21/schema.cue
|
|
6
|
+
|
|
7
|
+
module Sqreen
|
|
8
|
+
module Ecosystem
|
|
9
|
+
module Tracing
|
|
10
|
+
module Signals
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
class Sqreen::Ecosystem::Tracing::Signals::TracingProducer < Sqreen::Kit::Signals::Point
|
|
17
|
+
readonly_attrs :payload_schema, :source, :signal_name
|
|
18
|
+
|
|
19
|
+
def initialize(values = {})
|
|
20
|
+
self.payload_schema = Payload::SCHEMA_VERSION
|
|
21
|
+
self.source = Sqreen::Kit::Configuration.default_source
|
|
22
|
+
self.signal_name = 'tracing.producer'
|
|
23
|
+
self.time = values[:time] || Time.now
|
|
24
|
+
super
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def payload=(payload)
|
|
28
|
+
unless payload.is_a?(Payload)
|
|
29
|
+
raise ArgumentError, "Payload should be a #{Payload}"
|
|
30
|
+
end
|
|
31
|
+
super
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
class Payload
|
|
35
|
+
include Sqreen::Kit::Signals::DtoHelper
|
|
36
|
+
|
|
37
|
+
add_mandatory_attrs :message_type, :host, :tracing_identifier
|
|
38
|
+
|
|
39
|
+
SCHEMA_VERSION = 'tracing/producer-2020-04-21'.freeze
|
|
40
|
+
|
|
41
|
+
# @return [Symbol]
|
|
42
|
+
attr_accessor :message_type
|
|
43
|
+
|
|
44
|
+
# @return [String]
|
|
45
|
+
attr_accessor :host
|
|
46
|
+
|
|
47
|
+
# @return [String]
|
|
48
|
+
attr_accessor :ip
|
|
49
|
+
|
|
50
|
+
# @return [String]
|
|
51
|
+
attr_accessor :topic
|
|
52
|
+
|
|
53
|
+
# @return [String]
|
|
54
|
+
attr_accessor :tracing_identifier
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
require 'sqreen/kit/configuration'
|
|
2
|
+
require 'sqreen/kit/signals/point'
|
|
3
|
+
require 'sqreen/kit/signals/dto_helper'
|
|
4
|
+
|
|
5
|
+
# reference: https://github.com/sqreen/SignalsSchemas/blob/master/schemas/payload/tracing/server-2020-04-21/schema.cue
|
|
6
|
+
|
|
7
|
+
module Sqreen
|
|
8
|
+
module Ecosystem
|
|
9
|
+
module Tracing
|
|
10
|
+
module Signals
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
class Sqreen::Ecosystem::Tracing::Signals::TracingServer < Sqreen::Kit::Signals::Point
|
|
17
|
+
readonly_attrs :payload_schema, :source, :signal_name
|
|
18
|
+
|
|
19
|
+
def initialize(values = {})
|
|
20
|
+
self.payload_schema = Payload::SCHEMA_VERSION
|
|
21
|
+
self.source = Sqreen::Kit::Configuration.default_source
|
|
22
|
+
self.signal_name = 'tracing.server'
|
|
23
|
+
self.time = values[:time] || Time.now
|
|
24
|
+
super
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def payload=(payload)
|
|
28
|
+
unless payload.is_a?(Payload)
|
|
29
|
+
raise ArgumentError, "Payload should be a #{Payload}"
|
|
30
|
+
end
|
|
31
|
+
super
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
class Payload
|
|
35
|
+
include Sqreen::Kit::Signals::DtoHelper
|
|
36
|
+
|
|
37
|
+
add_mandatory_attrs :transport, :client_ip
|
|
38
|
+
|
|
39
|
+
SCHEMA_VERSION = 'tracing/server-2020-04-21'.freeze
|
|
40
|
+
|
|
41
|
+
# @return [Symbol]
|
|
42
|
+
attr_accessor :transport
|
|
43
|
+
|
|
44
|
+
# @return [String]
|
|
45
|
+
attr_accessor :client_ip
|
|
46
|
+
|
|
47
|
+
# @return [Array<String>]
|
|
48
|
+
attr_accessor :previous_hops
|
|
49
|
+
|
|
50
|
+
# @return [String]
|
|
51
|
+
attr_accessor :tracing_identifier
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
require 'sqreen/ecosystem/loggable'
|
|
2
|
+
require 'sqreen/ecosystem/exception_reporting'
|
|
3
|
+
|
|
4
|
+
module Sqreen
|
|
5
|
+
module Ecosystem
|
|
6
|
+
class TracingBroker
|
|
7
|
+
include Loggable
|
|
8
|
+
include ExceptionReporting
|
|
9
|
+
|
|
10
|
+
# Stores a lookup resolution so that lookup (incl. sampling) is done
|
|
11
|
+
# only once, not in the beginning of the producer code (when it asks
|
|
12
|
+
# whether it should proceed) and again once it delivers the data
|
|
13
|
+
ObserverLookup = Struct.new(:modules)
|
|
14
|
+
|
|
15
|
+
# @return [Sqreen::Ecosystem::Tracing::SamplingConfiguration]
|
|
16
|
+
attr_writer :sampling_configuration
|
|
17
|
+
|
|
18
|
+
# @param [Array<Sqreen::Ecosystem::ModuleApi::Tracing>] tracing_modules
|
|
19
|
+
def initialize(tracing_modules)
|
|
20
|
+
@sampling_configuration = nil
|
|
21
|
+
@type_to_subscribers = {}
|
|
22
|
+
tracing_modules.each do |mod|
|
|
23
|
+
consumed_type = mod.consumed_type
|
|
24
|
+
@type_to_subscribers[consumed_type] ||= []
|
|
25
|
+
@type_to_subscribers[consumed_type] << mod
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# @param [Object] data
|
|
30
|
+
# @param [Sqreen::Ecosystem::TracingBroker::ObserverLookup] prev_lookup
|
|
31
|
+
def publish(data, prev_lookup)
|
|
32
|
+
prev_lookup.modules.each do |mod|
|
|
33
|
+
mod_process_data mod, data
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# @param [Module] data_type
|
|
38
|
+
# @param [Hash] _hints reserved for future use, e.g. virtual scopes
|
|
39
|
+
# @return [Sqreen::Ecosystem::TracingBroker::ObserverLookup]
|
|
40
|
+
def interested_consumers(data_type, _hints = {})
|
|
41
|
+
unless @sampling_configuration
|
|
42
|
+
logger.debug do
|
|
43
|
+
"Declaring no one is interested in #{data_type} " \
|
|
44
|
+
"because tracing hasn't been enabled yet"
|
|
45
|
+
end
|
|
46
|
+
return false
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# if we have several modules with the same scope, we
|
|
50
|
+
# should ask whether we should sample only once
|
|
51
|
+
scope_to_should_sample = Hash.new do |hash, scope|
|
|
52
|
+
result = @sampling_configuration.should_sample?(scope)
|
|
53
|
+
if result
|
|
54
|
+
logger.debug { "Will sample scope #{scope}. Sampling line: #{result}" }
|
|
55
|
+
else
|
|
56
|
+
logger.debug { "Will NOT sample scope #{scope}" }
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
hash[scope] = result
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
res = subscribers(data_type).select do |mod|
|
|
63
|
+
scope_to_should_sample[mod.scope]
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
res.empty? ? false : ObserverLookup.new(res)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
private
|
|
70
|
+
|
|
71
|
+
# @param [Sqreen::Ecosystem::ModuleApi::Tracing] mod
|
|
72
|
+
def mod_process_data(mod, data)
|
|
73
|
+
mod.receive(data)
|
|
74
|
+
rescue ::Exception => e # rubocop:disable Lint/RescueException
|
|
75
|
+
report_exception("Error invoking tracing module #{mod}", e)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# @param [Module] data_type
|
|
79
|
+
# @return Array<Sqreen::Ecosystem::ModuleApi::Tracing>
|
|
80
|
+
def subscribers(data_type)
|
|
81
|
+
subscribers = @type_to_subscribers[data_type]
|
|
82
|
+
|
|
83
|
+
# None of the modules subscribes to data_type directly,
|
|
84
|
+
# but maybe they subscribe to one of the ancestors
|
|
85
|
+
# Cache this lookup
|
|
86
|
+
unless subscribers
|
|
87
|
+
subscribers = parents(data_type).inject([]) do |accum, type|
|
|
88
|
+
accum + (@type_to_subscribers[type] || [])
|
|
89
|
+
end
|
|
90
|
+
@type_to_subscribers[data_type] = subscribers
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
subscribers
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def parents(type)
|
|
97
|
+
type.ancestors - Object.ancestors - [type]
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|