sqreen 1.20.4.beta1 → 1.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +13 -0
  3. data/lib/sqreen/condition_evaluator.rb +8 -2
  4. data/lib/sqreen/deliveries/batch.rb +8 -1
  5. data/lib/sqreen/ecosystem.rb +123 -0
  6. data/lib/sqreen/ecosystem/databases/database_connection_data.rb +23 -0
  7. data/lib/sqreen/ecosystem/databases/mongo.rb +39 -0
  8. data/lib/sqreen/ecosystem/databases/mysql.rb +54 -0
  9. data/lib/sqreen/ecosystem/databases/postgres.rb +51 -0
  10. data/lib/sqreen/ecosystem/databases/redis.rb +36 -0
  11. data/lib/sqreen/ecosystem/dispatch_table.rb +43 -0
  12. data/lib/sqreen/ecosystem/exception_reporting.rb +28 -0
  13. data/lib/sqreen/ecosystem/http/net_http.rb +50 -0
  14. data/lib/sqreen/ecosystem/http/rack_request.rb +39 -0
  15. data/lib/sqreen/ecosystem/loggable.rb +13 -0
  16. data/lib/sqreen/ecosystem/messaging/bunny.rb +61 -0
  17. data/lib/sqreen/ecosystem/messaging/kafka.rb +70 -0
  18. data/lib/sqreen/ecosystem/messaging/kinesis.rb +66 -0
  19. data/lib/sqreen/ecosystem/messaging/sqs.rb +68 -0
  20. data/lib/sqreen/ecosystem/module_api.rb +30 -0
  21. data/lib/sqreen/ecosystem/module_api/event_listener.rb +18 -0
  22. data/lib/sqreen/ecosystem/module_api/instrumentation.rb +23 -0
  23. data/lib/sqreen/ecosystem/module_api/message_producer.rb +57 -0
  24. data/lib/sqreen/ecosystem/module_api/signal_producer.rb +24 -0
  25. data/lib/sqreen/ecosystem/module_api/tracing.rb +45 -0
  26. data/lib/sqreen/ecosystem/module_api/tracing/client_data.rb +31 -0
  27. data/lib/sqreen/ecosystem/module_api/tracing/consumer_data.rb +13 -0
  28. data/lib/sqreen/ecosystem/module_api/tracing/messaging_data.rb +35 -0
  29. data/lib/sqreen/ecosystem/module_api/tracing/producer_data.rb +13 -0
  30. data/lib/sqreen/ecosystem/module_api/tracing/server_data.rb +27 -0
  31. data/lib/sqreen/ecosystem/module_api/tracing_id_generation.rb +16 -0
  32. data/lib/sqreen/ecosystem/module_api/transaction_storage.rb +71 -0
  33. data/lib/sqreen/ecosystem/module_registry.rb +48 -0
  34. data/lib/sqreen/ecosystem/tracing/modules/client.rb +35 -0
  35. data/lib/sqreen/ecosystem/tracing/modules/consumer.rb +35 -0
  36. data/lib/sqreen/ecosystem/tracing/modules/determine_ip.rb +28 -0
  37. data/lib/sqreen/ecosystem/tracing/modules/producer.rb +35 -0
  38. data/lib/sqreen/ecosystem/tracing/modules/server.rb +30 -0
  39. data/lib/sqreen/ecosystem/tracing/sampler.rb +160 -0
  40. data/lib/sqreen/ecosystem/tracing/sampling_configuration.rb +150 -0
  41. data/lib/sqreen/ecosystem/tracing/signals/tracing_client.rb +53 -0
  42. data/lib/sqreen/ecosystem/tracing/signals/tracing_consumer.rb +56 -0
  43. data/lib/sqreen/ecosystem/tracing/signals/tracing_producer.rb +56 -0
  44. data/lib/sqreen/ecosystem/tracing/signals/tracing_server.rb +53 -0
  45. data/lib/sqreen/ecosystem/tracing_broker.rb +101 -0
  46. data/lib/sqreen/ecosystem/tracing_id_setup.rb +34 -0
  47. data/lib/sqreen/ecosystem/transaction_storage.rb +64 -0
  48. data/lib/sqreen/ecosystem/util/call_writers_from_init.rb +13 -0
  49. data/lib/sqreen/ecosystem_integration.rb +81 -0
  50. data/lib/sqreen/ecosystem_integration/around_callbacks.rb +89 -0
  51. data/lib/sqreen/ecosystem_integration/instrumentation_service.rb +38 -0
  52. data/lib/sqreen/ecosystem_integration/request_lifecycle_tracking.rb +58 -0
  53. data/lib/sqreen/ecosystem_integration/signal_consumption.rb +35 -0
  54. data/lib/sqreen/events/request_record.rb +0 -1
  55. data/lib/sqreen/frameworks/generic.rb +15 -1
  56. data/lib/sqreen/frameworks/request_recorder.rb +2 -0
  57. data/lib/sqreen/graft/call.rb +9 -0
  58. data/lib/sqreen/graft/hook.rb +5 -3
  59. data/lib/sqreen/graft/hook_point.rb +17 -10
  60. data/lib/sqreen/kit/signals/specialized/sqreen_exception.rb +2 -0
  61. data/lib/sqreen/legacy/old_event_submission_strategy.rb +9 -2
  62. data/lib/sqreen/remote_command.rb +3 -0
  63. data/lib/sqreen/rules.rb +7 -3
  64. data/lib/sqreen/rules/custom_error_cb.rb +3 -3
  65. data/lib/sqreen/rules/waf_cb.rb +3 -3
  66. data/lib/sqreen/runner.rb +19 -5
  67. data/lib/sqreen/session.rb +2 -0
  68. data/lib/sqreen/signals/conversions.rb +6 -1
  69. data/lib/sqreen/version.rb +1 -1
  70. data/lib/sqreen/weave/legacy/instrumentation.rb +38 -19
  71. metadata +57 -11
  72. data/lib/sqreen/encoding_sanitizer.rb +0 -27
@@ -0,0 +1,28 @@
1
+ require 'sqreen/ecosystem/dispatch_table'
2
+ require 'sqreen/ecosystem/loggable'
3
+ require 'sqreen/kit/configuration'
4
+ require 'sqreen/kit/signals/specialized/sqreen_exception'
5
+
6
+ module Sqreen
7
+ module Ecosystem
8
+ module ExceptionReporting
9
+ include Loggable
10
+
11
+ private
12
+
13
+ # @param [String] message
14
+ # @param [Exception] e
15
+ def report_exception(message, e)
16
+ logger.warn { "#{message}: #{e.message}" }
17
+ logger.debug { e.backtrace.map { |x| " #{x}" }.join("\n") }
18
+
19
+ signal = Sqreen::Kit::Signals::Specialized::SqreenException.new(
20
+ ruby_exception: e,
21
+ source: Sqreen::Kit::Configuration.default_source
22
+ )
23
+
24
+ DispatchTable.consume_signal[signal]
25
+ end
26
+ end
27
+ end
28
+ 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,61 @@
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/consumer_data'
5
+ require 'sqreen/ecosystem/module_api/tracing/producer_data'
6
+
7
+ module Sqreen
8
+ module Ecosystem
9
+ module Messaging
10
+ class Bunny
11
+ include ModuleApi::Loggable
12
+ include ModuleApi::Instrumentation
13
+ include ModuleApi::MessageProducer
14
+
15
+ def setup
16
+ advice_send = wrap_for_interest(ModuleApi::Tracing::ProducerData, &method(:after_send_advice))
17
+ advice_receive = wrap_for_interest(ModuleApi::Tracing::ConsumerData, &method(:after_receive_advice))
18
+ advice_receive_consumer = wrap_for_interest(ModuleApi::Tracing::ConsumerData, &method(:after_receive_advice_consumer))
19
+ instrument 'Bunny::Queue#publish', after: advice_send
20
+ instrument 'Bunny::Queue#pop', after: advice_receive
21
+ instrument 'Bunny::Consumer#call', after: advice_receive_consumer
22
+ end
23
+
24
+ private
25
+
26
+ # @param [Sqreen::Graft::CallbackCall] call
27
+ def after_send_advice(call, _ball)
28
+ return if call.raised
29
+
30
+ create_signal(call.instance, ModuleApi::Tracing::ProducerData)
31
+ end
32
+
33
+ # @param [Sqreen::Graft::CallbackCall] call
34
+ def after_receive_advice(call, _ball)
35
+ return if call.raised
36
+
37
+ create_signal(call.instance, ModuleApi::Tracing::ConsumerData)
38
+ end
39
+
40
+ # @param [Sqreen::Graft::CallbackCall] call
41
+ def after_receive_advice_consumer(call, _ball)
42
+ return if call.raised
43
+
44
+ queue = call.instance.queue
45
+ create_signal(queue, ModuleApi::Tracing::ConsumerData)
46
+ end
47
+
48
+ # @param [Bunny::Queue] q
49
+ def create_signal(q, clazz)
50
+ conn = q.channel.connection
51
+
52
+ clazz.new(
53
+ message_type: :amqp,
54
+ host: conn.host,
55
+ topic: q.name,
56
+ )
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,70 @@
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/consumer_data'
5
+ require 'sqreen/ecosystem/module_api/tracing/producer_data'
6
+
7
+ module Sqreen
8
+ module Ecosystem
9
+ module Messaging
10
+ class Kafka
11
+ include ModuleApi::Loggable
12
+ include ModuleApi::Instrumentation
13
+ include ModuleApi::MessageProducer
14
+
15
+ def setup
16
+ advice_send = wrap_for_interest(ModuleApi::Tracing::ProducerData, &method(:after_send))
17
+ advice_receive = wrap_for_interest(ModuleApi::Tracing::ConsumerData, &method(:after_receive))
18
+ instrument 'Kafka::Broker#produce', after: advice_send
19
+ instrument 'Kafka::Broker#fetch_messages', after: advice_receive
20
+ end
21
+
22
+ private
23
+
24
+ # @param [Sqreen::Graft::CallbackCall] call
25
+ def after_send(call, _ball)
26
+ return if call.raised
27
+ if call.args.length != 1
28
+ logger.info "Expected 1 arguments to Kafka::Broker#produce"
29
+ return
30
+ end
31
+ options = call.args.first
32
+ topics = options[:messages_for_topics].keys
33
+
34
+ create_signal_data(ModuleApi::Tracing::ProducerData,
35
+ call.instance,
36
+ topics)
37
+ end
38
+
39
+ # @param [Sqreen::Graft::CallbackCall] call
40
+ def after_receive(call, _ball)
41
+ return if call.raised
42
+ if call.args.length != 1
43
+ logger.info "Expected 1 arguments to Kafka::Broker#fetch_messages"
44
+ return
45
+ end
46
+ options = call.args.first
47
+ topics = options[:topics].keys
48
+
49
+ create_signal_data(ModuleApi::Tracing::ConsumerData,
50
+ call.instance,
51
+ topics)
52
+ end
53
+
54
+ # @param [Class] clazz
55
+ # @param [Kafka::Broker] broker
56
+ # @param [Array<String>] topics
57
+ def create_signal_data(clazz, broker, topics)
58
+ host = broker.instance_variable_get :@host
59
+ topics.map do |top|
60
+ clazz.new(
61
+ message_type: :kafka,
62
+ host: host,
63
+ topic: top,
64
+ )
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,66 @@
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/consumer_data'
5
+ require 'sqreen/ecosystem/module_api/tracing/producer_data'
6
+
7
+ # see https://aws.amazon.com/blogs/developer/announcing-amazon-kinesis-subscribetoshard-api-support-in-the-aws-sdk-for-ruby/
8
+ module Sqreen
9
+ module Ecosystem
10
+ module Messaging
11
+ class Kinesis
12
+ include ModuleApi::Loggable
13
+ include ModuleApi::Instrumentation
14
+ include ModuleApi::MessageProducer
15
+
16
+ def setup
17
+ advice_send = wrap_for_interest(ModuleApi::Tracing::ProducerData, &method(:after_send_advice))
18
+ advice_receive = wrap_for_interest(ModuleApi::Tracing::ConsumerData, &method(:after_receive_advice))
19
+ instrument 'Aws::Kinesis::Client#put_record', after: advice_send
20
+ instrument 'Aws::Kinesis::Client#put_records', after: advice_send
21
+ # more sophisticated usages (register_stream_consumer, possibly with AsyncClient)
22
+ # are not supported. They are more difficult to test, as kinesalite doesn't support them
23
+ instrument 'Aws::Kinesis::Client#get_shard_iterator', after: advice_receive
24
+ end
25
+
26
+ private
27
+
28
+ # @param [Sqreen::Graft::CallbackCall] call
29
+ def after_send_advice(call, _ball)
30
+ return if call.raised
31
+ unless call.args.length > 0 && call.args[0].is_a?(Hash)
32
+ logger.info "Unexpected arguments to put_record(s)"
33
+ return
34
+ end
35
+
36
+ create_signal(call.instance, call.args, ModuleApi::Tracing::ProducerData)
37
+ end
38
+
39
+ # @param [Sqreen::Graft::CallbackCall] call
40
+ def after_receive_advice(call, _ball)
41
+ return if call.raised
42
+ unless call.args.length > 0 && call.args[0].is_a?(Hash)
43
+ logger.info "Unexpected arguments to get_shared_iterator"
44
+ return
45
+ end
46
+
47
+ create_signal(call.instance, call.args, ModuleApi::Tracing::ConsumerData)
48
+ end
49
+
50
+ def create_signal(client, args, clazz)
51
+ hash = args[0]
52
+ stream_name = hash[:stream_name] || hash['stream_name']
53
+ return unless stream_name
54
+
55
+ endpoint = client.instance_variable_get(:@config).endpoint
56
+
57
+ clazz.new(
58
+ message_type: :'aws-kinesis',
59
+ host: endpoint.host,
60
+ topic: stream_name,
61
+ )
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,68 @@
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/consumer_data'
5
+ require 'sqreen/ecosystem/module_api/tracing/producer_data'
6
+
7
+ module Sqreen
8
+ module Ecosystem
9
+ module Messaging
10
+ class Sqs
11
+ include ModuleApi::Loggable
12
+ include ModuleApi::Instrumentation
13
+ include ModuleApi::MessageProducer
14
+
15
+ def setup
16
+ advice_send = wrap_for_interest(ModuleApi::Tracing::ProducerData, &method(:after_send_advice))
17
+ advice_receive = wrap_for_interest(ModuleApi::Tracing::ConsumerData, &method(:after_receive_advice))
18
+ instrument 'Aws::SQS::Client#send_message', after: advice_send
19
+ instrument 'Aws::SQS::Client#send_message_batch', after: advice_send
20
+ instrument 'Aws::SQS::Client#receive_message', after: advice_receive
21
+ end
22
+
23
+ private
24
+
25
+ # @param [Sqreen::Graft::CallbackCall] call
26
+ def after_send_advice(call, _ball)
27
+ return if call.raised
28
+ unless call.args.length > 0 && call.args[0].is_a?(Hash)
29
+ logger.info "Unexpected arguments to send_message(_batch)"
30
+ return
31
+ end
32
+
33
+ create_signal(call.args, ModuleApi::Tracing::ProducerData)
34
+ end
35
+
36
+ # @param [Sqreen::Graft::CallbackCall] call
37
+ def after_receive_advice(call, _ball)
38
+ return if call.raised
39
+ unless call.args.length > 0 && call.args[0].is_a?(Hash)
40
+ logger.info "Unexpected arguments to receive_message"
41
+ return
42
+ end
43
+
44
+ create_signal(call.args, ModuleApi::Tracing::ConsumerData)
45
+ end
46
+
47
+ def create_signal(args, clazz)
48
+ hash = args[0]
49
+ queue_url = hash[:queue_url] || hash['queue_url']
50
+ return unless queue_url
51
+
52
+ begin
53
+ uri = URI.parse(queue_url)
54
+ rescue URI::InvalidURIError
55
+ logger.info { "Invalid URI: #{uri}" }
56
+ return
57
+ end
58
+
59
+ clazz.new(
60
+ message_type: :'aws-sqs',
61
+ host: uri.host,
62
+ topic: ($1 if uri.path =~ /\A\/queue\/(?:[^\/]+\/)?([^\/]+)\z/),
63
+ )
64
+ end
65
+ end
66
+ end
67
+ end
68
+ 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
@@ -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