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,35 @@
|
|
|
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::TracingConsumer::Payload+ and
|
|
9
|
+
# +Sqreen::Ecosystem::Tracing::Signals::TracingProducer::Payload+.
|
|
10
|
+
#
|
|
11
|
+
# Signals are not produced by the data producers (transport)
|
|
12
|
+
# because of superior orders, as the only current use of this
|
|
13
|
+
# data is to generate signals.
|
|
14
|
+
module MessagingData
|
|
15
|
+
include Util::CallWritersFromInit
|
|
16
|
+
|
|
17
|
+
# @return [Symbol]
|
|
18
|
+
attr_accessor :message_type
|
|
19
|
+
|
|
20
|
+
# @return [String]
|
|
21
|
+
attr_accessor :host
|
|
22
|
+
|
|
23
|
+
# @return [String]
|
|
24
|
+
attr_accessor :ip
|
|
25
|
+
|
|
26
|
+
# @return [String]
|
|
27
|
+
attr_accessor :topic
|
|
28
|
+
|
|
29
|
+
# @return [String]
|
|
30
|
+
attr_accessor :tracing_identifier
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
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,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,48 @@
|
|
|
1
|
+
require 'sqreen/ecosystem/loggable'
|
|
2
|
+
|
|
3
|
+
module Sqreen
|
|
4
|
+
module Ecosystem
|
|
5
|
+
class ModuleRegistry
|
|
6
|
+
include Sqreen::Ecosystem::Loggable
|
|
7
|
+
|
|
8
|
+
def initialize
|
|
9
|
+
@mods = []
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def register(mod)
|
|
13
|
+
@mods << mod
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def init_all
|
|
17
|
+
logger.info { "Initializing #{@mods.size} ecosystem modules" }
|
|
18
|
+
each_module do |mod|
|
|
19
|
+
unless mod.respond_to? :setup
|
|
20
|
+
logger.debug { "Module with type #{mod.class} requires no initialization" }
|
|
21
|
+
next
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
logger.debug { "Initializing module with type #{mod.class}" }
|
|
25
|
+
mod.setup
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def destroy_all
|
|
30
|
+
# not implemented
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# @param [Class] type
|
|
34
|
+
def each_module(type = nil, &block)
|
|
35
|
+
selected_mods = type ? (@mods.select { |mod| mod.is_a?(type) }) : @mods
|
|
36
|
+
if block_given?
|
|
37
|
+
selected_mods.each(&block)
|
|
38
|
+
else
|
|
39
|
+
selected_mods.each
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def module_subset(type)
|
|
44
|
+
each_module(type).to_a
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
require 'sqreen/ecosystem/tracing/modules/determine_ip'
|
|
2
|
+
require 'sqreen/ecosystem/tracing/signals/tracing_client'
|
|
3
|
+
require 'sqreen/ecosystem/loggable'
|
|
4
|
+
require 'sqreen/ecosystem/module_api'
|
|
5
|
+
require 'sqreen/ecosystem/module_api/tracing'
|
|
6
|
+
require 'sqreen/ecosystem/module_api/tracing/client_data'
|
|
7
|
+
|
|
8
|
+
module Sqreen
|
|
9
|
+
module Ecosystem
|
|
10
|
+
module Tracing
|
|
11
|
+
module Modules
|
|
12
|
+
class Client
|
|
13
|
+
include ModuleApi::Tracing
|
|
14
|
+
include ModuleApi::TracingIdGeneration
|
|
15
|
+
include ModuleApi::Loggable
|
|
16
|
+
|
|
17
|
+
consumes ModuleApi::Tracing::ClientData
|
|
18
|
+
fixed_scope 'client'
|
|
19
|
+
|
|
20
|
+
def receive(data)
|
|
21
|
+
signal = Tracing::Signals::TracingClient.new
|
|
22
|
+
signal.payload = Tracing::Signals::TracingClient::Payload.new(
|
|
23
|
+
transport: data.transport,
|
|
24
|
+
host: data.host || '',
|
|
25
|
+
ip: data.ip,
|
|
26
|
+
tracing_identifier: data.tracing_identifier || create_tracing_id
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
submit_signal signal
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
require 'sqreen/ecosystem/tracing/modules/determine_ip'
|
|
2
|
+
require 'sqreen/ecosystem/tracing/signals/tracing_consumer'
|
|
3
|
+
require 'sqreen/ecosystem/module_api'
|
|
4
|
+
require 'sqreen/ecosystem/module_api/tracing/consumer_data'
|
|
5
|
+
|
|
6
|
+
module Sqreen
|
|
7
|
+
module Ecosystem
|
|
8
|
+
module Tracing
|
|
9
|
+
module Modules
|
|
10
|
+
class Consumer
|
|
11
|
+
include ModuleApi::Tracing
|
|
12
|
+
include ModuleApi::TracingIdGeneration
|
|
13
|
+
include ModuleApi::Loggable
|
|
14
|
+
|
|
15
|
+
consumes ModuleApi::Tracing::ConsumerData
|
|
16
|
+
fixed_scope 'consumer'
|
|
17
|
+
|
|
18
|
+
# @param [ModuleApi::Tracing::ConsumerData] data
|
|
19
|
+
def receive(data)
|
|
20
|
+
signal = Tracing::Signals::TracingConsumer.new
|
|
21
|
+
signal.payload = Tracing::Signals::TracingConsumer::Payload.new(
|
|
22
|
+
message_type: data.message_type,
|
|
23
|
+
host: data.host || '',
|
|
24
|
+
ip: data.ip,
|
|
25
|
+
topic: data.topic,
|
|
26
|
+
tracing_identifier: data.tracing_identifier || create_tracing_id
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
submit_signal signal
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
require 'sqreen/ecosystem/module_api'
|
|
2
|
+
|
|
3
|
+
module Sqreen
|
|
4
|
+
module Ecosystem
|
|
5
|
+
module Tracing
|
|
6
|
+
module Modules
|
|
7
|
+
module DetermineIp
|
|
8
|
+
class << self
|
|
9
|
+
include ModuleApi::Loggable
|
|
10
|
+
|
|
11
|
+
def [](data)
|
|
12
|
+
return data.ip if data.ip
|
|
13
|
+
|
|
14
|
+
return nil unless data.host && !data.host.empty?
|
|
15
|
+
|
|
16
|
+
begin
|
|
17
|
+
IPSocket.getaddress data.host
|
|
18
|
+
rescue SocketError => e
|
|
19
|
+
logger.info { "Error resolving #{data.host}: #{e.message}" }
|
|
20
|
+
nil
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
require 'sqreen/ecosystem/tracing/modules/determine_ip'
|
|
2
|
+
require 'sqreen/ecosystem/tracing/signals/tracing_producer'
|
|
3
|
+
require 'sqreen/ecosystem/module_api'
|
|
4
|
+
require 'sqreen/ecosystem/module_api/tracing/producer_data'
|
|
5
|
+
|
|
6
|
+
module Sqreen
|
|
7
|
+
module Ecosystem
|
|
8
|
+
module Tracing
|
|
9
|
+
module Modules
|
|
10
|
+
class Producer
|
|
11
|
+
include ModuleApi::Tracing
|
|
12
|
+
include ModuleApi::TracingIdGeneration
|
|
13
|
+
include ModuleApi::Loggable
|
|
14
|
+
|
|
15
|
+
consumes ModuleApi::Tracing::ProducerData
|
|
16
|
+
fixed_scope 'producer'
|
|
17
|
+
|
|
18
|
+
# @param [ModuleApi::Tracing::ProducerData] data
|
|
19
|
+
def receive(data)
|
|
20
|
+
signal = Tracing::Signals::TracingProducer.new
|
|
21
|
+
signal.payload = Tracing::Signals::TracingProducer::Payload.new(
|
|
22
|
+
message_type: data.message_type,
|
|
23
|
+
host: data.host || '',
|
|
24
|
+
ip: data.ip,
|
|
25
|
+
topic: data.topic,
|
|
26
|
+
tracing_identifier: data.tracing_identifier || create_tracing_id
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
submit_signal signal
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
require 'sqreen/ecosystem/tracing/signals/tracing_server'
|
|
2
|
+
require 'sqreen/ecosystem/module_api/tracing'
|
|
3
|
+
require 'sqreen/ecosystem/module_api/tracing/server_data'
|
|
4
|
+
|
|
5
|
+
module Sqreen
|
|
6
|
+
module Ecosystem
|
|
7
|
+
module Tracing
|
|
8
|
+
module Modules
|
|
9
|
+
class Server
|
|
10
|
+
include ModuleApi::Tracing
|
|
11
|
+
|
|
12
|
+
consumes ModuleApi::Tracing::ServerData
|
|
13
|
+
fixed_scope 'server'
|
|
14
|
+
|
|
15
|
+
# @param [Sqreen::Ecosystem::ModuleApi::Tracing::ServerData] data
|
|
16
|
+
def receive(data)
|
|
17
|
+
signal = Tracing::Signals::TracingServer.new
|
|
18
|
+
signal.payload = Tracing::Signals::TracingServer::Payload.new(
|
|
19
|
+
transport: data.transport,
|
|
20
|
+
client_ip: data.client_ip,
|
|
21
|
+
tracing_identifier: data.tracing_identifier
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
submit_signal signal
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
require 'thread' # for Mutex
|
|
2
|
+
require 'singleton'
|
|
3
|
+
require 'sqreen/ecosystem/loggable'
|
|
4
|
+
|
|
5
|
+
# see https://github.com/sqreen/TechDoc/blob/master/content/specs/spec000024-sampling.md
|
|
6
|
+
|
|
7
|
+
module Sqreen
|
|
8
|
+
module Ecosystem
|
|
9
|
+
module Tracing
|
|
10
|
+
class Sampler
|
|
11
|
+
# @param [Array<Hash{String=>Object}>] definition
|
|
12
|
+
def initialize(definition)
|
|
13
|
+
@lines = definition.map { |h| Line.new(h) }
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def should_sample?
|
|
17
|
+
line = @lines.find(&:triggers?)
|
|
18
|
+
line ? line.saved_definition : false
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
class Line
|
|
22
|
+
include Loggable
|
|
23
|
+
|
|
24
|
+
attr_reader :saved_definition
|
|
25
|
+
|
|
26
|
+
# @param [Hash{String=>Object}] definition
|
|
27
|
+
def initialize(definition)
|
|
28
|
+
@saved_definition = definition
|
|
29
|
+
@primitives = []
|
|
30
|
+
|
|
31
|
+
unknown = definition.keys - PRIMITIVES_MAP.keys
|
|
32
|
+
unless unknown.empty?
|
|
33
|
+
logger.warn "Unknown primitives: #{unknown}"
|
|
34
|
+
@primitives << AlwaysFalsePrimitive.instance
|
|
35
|
+
return
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
PRIMITIVES_MAP.each do |key, prim_class|
|
|
39
|
+
next unless definition[key]
|
|
40
|
+
@primitives << prim_class.new(definition[key])
|
|
41
|
+
end
|
|
42
|
+
# if @primitives is empty the line will always
|
|
43
|
+
# return true: [].all?(&:triggers?) is true
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def triggers?
|
|
47
|
+
@primitives.all?(&:triggers?)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
class AlwaysFalsePrimitive
|
|
52
|
+
include Singleton
|
|
53
|
+
|
|
54
|
+
def triggers?
|
|
55
|
+
false
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
class CallsPrimitive
|
|
60
|
+
def initialize(calls_period)
|
|
61
|
+
@calls_period = calls_period
|
|
62
|
+
@count = 0
|
|
63
|
+
@mutex = Mutex.new
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def triggers?
|
|
67
|
+
prev_count = nil
|
|
68
|
+
@mutex.synchronize do
|
|
69
|
+
prev_count = @count
|
|
70
|
+
@count += 1
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
(prev_count % @calls_period).zero?
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
class RandomPrimitive
|
|
78
|
+
def initialize(probability)
|
|
79
|
+
@probability = probability
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def triggers?
|
|
83
|
+
@probability >= rand
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
class MaxDurationMinutesPrimitive
|
|
88
|
+
def initialize(time_in_minutes)
|
|
89
|
+
@deadline = Sqreen.time + time_in_minutes * 60
|
|
90
|
+
@passed = false # no locking needed
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def triggers?
|
|
94
|
+
return false if @passed
|
|
95
|
+
if Sqreen.time > @deadline
|
|
96
|
+
@passed = true
|
|
97
|
+
return false
|
|
98
|
+
end
|
|
99
|
+
true
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
class TargetPerMinutePrimitive
|
|
104
|
+
def initialize(max_calls)
|
|
105
|
+
@max_calls = max_calls
|
|
106
|
+
@minute_last_call = cur_minute
|
|
107
|
+
@calls_accumulated = 0
|
|
108
|
+
@mutex = Mutex.new
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def triggers?
|
|
112
|
+
this_minute = cur_minute
|
|
113
|
+
calls_cur_minute = @mutex.synchronize do
|
|
114
|
+
if @minute_last_call == this_minute
|
|
115
|
+
@calls_accumulated += 1
|
|
116
|
+
else
|
|
117
|
+
@minute_last_call = this_minute
|
|
118
|
+
@calls_accumulated = 1
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
calls_cur_minute <= @max_calls
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
private
|
|
126
|
+
|
|
127
|
+
def cur_minute
|
|
128
|
+
(Sqreen.time / 60).floor
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
class MaxCallsPrimitive
|
|
133
|
+
def initialize(max_calls)
|
|
134
|
+
@max_calls = max_calls
|
|
135
|
+
@disabled = false # to avoid lock
|
|
136
|
+
@mutex = Mutex.new
|
|
137
|
+
@num_calls = 0
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def triggers?
|
|
141
|
+
return false if @disabled
|
|
142
|
+
num_calls = @mutex.synchronize do
|
|
143
|
+
@num_calls += 1
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
num_calls <= @max_calls
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
PRIMITIVES_MAP = {
|
|
151
|
+
"calls" => CallsPrimitive,
|
|
152
|
+
"random" => RandomPrimitive,
|
|
153
|
+
"max_duration_minutes" => MaxDurationMinutesPrimitive,
|
|
154
|
+
"target_per_minute" => TargetPerMinutePrimitive,
|
|
155
|
+
"max_calls" => MaxCallsPrimitive,
|
|
156
|
+
}.freeze
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
end
|