apisonator 2.100.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (173) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +317 -0
  3. data/Gemfile +11 -0
  4. data/Gemfile.base +65 -0
  5. data/Gemfile.lock +319 -0
  6. data/Gemfile.on_prem +1 -0
  7. data/Gemfile.on_prem.lock +297 -0
  8. data/LICENSE +202 -0
  9. data/NOTICE +15 -0
  10. data/README.md +230 -0
  11. data/Rakefile +287 -0
  12. data/apisonator.gemspec +47 -0
  13. data/app/api/api.rb +13 -0
  14. data/app/api/internal/alert_limits.rb +32 -0
  15. data/app/api/internal/application_keys.rb +49 -0
  16. data/app/api/internal/application_referrer_filters.rb +43 -0
  17. data/app/api/internal/applications.rb +77 -0
  18. data/app/api/internal/errors.rb +54 -0
  19. data/app/api/internal/events.rb +42 -0
  20. data/app/api/internal/internal.rb +104 -0
  21. data/app/api/internal/metrics.rb +40 -0
  22. data/app/api/internal/service_tokens.rb +46 -0
  23. data/app/api/internal/services.rb +58 -0
  24. data/app/api/internal/stats.rb +42 -0
  25. data/app/api/internal/usagelimits.rb +62 -0
  26. data/app/api/internal/utilization.rb +23 -0
  27. data/bin/3scale_backend +223 -0
  28. data/bin/3scale_backend_worker +26 -0
  29. data/config.ru +4 -0
  30. data/config/puma.rb +192 -0
  31. data/config/schedule.rb +9 -0
  32. data/ext/mkrf_conf.rb +64 -0
  33. data/lib/3scale/backend.rb +67 -0
  34. data/lib/3scale/backend/alert_limit.rb +56 -0
  35. data/lib/3scale/backend/alerts.rb +137 -0
  36. data/lib/3scale/backend/analytics/kinesis.rb +3 -0
  37. data/lib/3scale/backend/analytics/kinesis/adapter.rb +180 -0
  38. data/lib/3scale/backend/analytics/kinesis/exporter.rb +86 -0
  39. data/lib/3scale/backend/analytics/kinesis/job.rb +135 -0
  40. data/lib/3scale/backend/analytics/redshift.rb +3 -0
  41. data/lib/3scale/backend/analytics/redshift/adapter.rb +367 -0
  42. data/lib/3scale/backend/analytics/redshift/importer.rb +83 -0
  43. data/lib/3scale/backend/analytics/redshift/job.rb +33 -0
  44. data/lib/3scale/backend/application.rb +330 -0
  45. data/lib/3scale/backend/application_events.rb +76 -0
  46. data/lib/3scale/backend/background_job.rb +65 -0
  47. data/lib/3scale/backend/configurable.rb +20 -0
  48. data/lib/3scale/backend/configuration.rb +151 -0
  49. data/lib/3scale/backend/configuration/loader.rb +42 -0
  50. data/lib/3scale/backend/constants.rb +19 -0
  51. data/lib/3scale/backend/cors.rb +84 -0
  52. data/lib/3scale/backend/distributed_lock.rb +67 -0
  53. data/lib/3scale/backend/environment.rb +21 -0
  54. data/lib/3scale/backend/error_storage.rb +52 -0
  55. data/lib/3scale/backend/errors.rb +343 -0
  56. data/lib/3scale/backend/event_storage.rb +120 -0
  57. data/lib/3scale/backend/experiment.rb +84 -0
  58. data/lib/3scale/backend/extensions.rb +5 -0
  59. data/lib/3scale/backend/extensions/array.rb +19 -0
  60. data/lib/3scale/backend/extensions/hash.rb +26 -0
  61. data/lib/3scale/backend/extensions/nil_class.rb +13 -0
  62. data/lib/3scale/backend/extensions/redis.rb +44 -0
  63. data/lib/3scale/backend/extensions/string.rb +13 -0
  64. data/lib/3scale/backend/extensions/time.rb +110 -0
  65. data/lib/3scale/backend/failed_jobs_scheduler.rb +141 -0
  66. data/lib/3scale/backend/job_fetcher.rb +122 -0
  67. data/lib/3scale/backend/listener.rb +728 -0
  68. data/lib/3scale/backend/listener_metrics.rb +99 -0
  69. data/lib/3scale/backend/logging.rb +48 -0
  70. data/lib/3scale/backend/logging/external.rb +44 -0
  71. data/lib/3scale/backend/logging/external/impl.rb +93 -0
  72. data/lib/3scale/backend/logging/external/impl/airbrake.rb +66 -0
  73. data/lib/3scale/backend/logging/external/impl/bugsnag.rb +69 -0
  74. data/lib/3scale/backend/logging/external/impl/default.rb +18 -0
  75. data/lib/3scale/backend/logging/external/resque.rb +57 -0
  76. data/lib/3scale/backend/logging/logger.rb +18 -0
  77. data/lib/3scale/backend/logging/middleware.rb +62 -0
  78. data/lib/3scale/backend/logging/middleware/json_writer.rb +21 -0
  79. data/lib/3scale/backend/logging/middleware/text_writer.rb +60 -0
  80. data/lib/3scale/backend/logging/middleware/writer.rb +143 -0
  81. data/lib/3scale/backend/logging/worker.rb +107 -0
  82. data/lib/3scale/backend/manifest.rb +80 -0
  83. data/lib/3scale/backend/memoizer.rb +277 -0
  84. data/lib/3scale/backend/metric.rb +275 -0
  85. data/lib/3scale/backend/metric/collection.rb +91 -0
  86. data/lib/3scale/backend/oauth.rb +4 -0
  87. data/lib/3scale/backend/oauth/token.rb +26 -0
  88. data/lib/3scale/backend/oauth/token_key.rb +30 -0
  89. data/lib/3scale/backend/oauth/token_storage.rb +313 -0
  90. data/lib/3scale/backend/oauth/token_value.rb +25 -0
  91. data/lib/3scale/backend/period.rb +3 -0
  92. data/lib/3scale/backend/period/boundary.rb +107 -0
  93. data/lib/3scale/backend/period/cache.rb +28 -0
  94. data/lib/3scale/backend/period/period.rb +402 -0
  95. data/lib/3scale/backend/queue_storage.rb +16 -0
  96. data/lib/3scale/backend/rack.rb +49 -0
  97. data/lib/3scale/backend/rack/exception_catcher.rb +136 -0
  98. data/lib/3scale/backend/rack/internal_error_catcher.rb +23 -0
  99. data/lib/3scale/backend/rack/prometheus.rb +19 -0
  100. data/lib/3scale/backend/saas.rb +6 -0
  101. data/lib/3scale/backend/saas_analytics.rb +4 -0
  102. data/lib/3scale/backend/server.rb +30 -0
  103. data/lib/3scale/backend/server/falcon.rb +52 -0
  104. data/lib/3scale/backend/server/puma.rb +71 -0
  105. data/lib/3scale/backend/service.rb +317 -0
  106. data/lib/3scale/backend/service_token.rb +97 -0
  107. data/lib/3scale/backend/stats.rb +8 -0
  108. data/lib/3scale/backend/stats/aggregator.rb +170 -0
  109. data/lib/3scale/backend/stats/aggregators/base.rb +72 -0
  110. data/lib/3scale/backend/stats/aggregators/response_code.rb +58 -0
  111. data/lib/3scale/backend/stats/aggregators/usage.rb +34 -0
  112. data/lib/3scale/backend/stats/bucket_reader.rb +135 -0
  113. data/lib/3scale/backend/stats/bucket_storage.rb +108 -0
  114. data/lib/3scale/backend/stats/cleaner.rb +195 -0
  115. data/lib/3scale/backend/stats/codes_commons.rb +14 -0
  116. data/lib/3scale/backend/stats/delete_job_def.rb +60 -0
  117. data/lib/3scale/backend/stats/key_generator.rb +73 -0
  118. data/lib/3scale/backend/stats/keys.rb +104 -0
  119. data/lib/3scale/backend/stats/partition_eraser_job.rb +58 -0
  120. data/lib/3scale/backend/stats/partition_generator_job.rb +46 -0
  121. data/lib/3scale/backend/stats/period_commons.rb +34 -0
  122. data/lib/3scale/backend/stats/stats_parser.rb +141 -0
  123. data/lib/3scale/backend/stats/storage.rb +113 -0
  124. data/lib/3scale/backend/statsd.rb +14 -0
  125. data/lib/3scale/backend/storable.rb +35 -0
  126. data/lib/3scale/backend/storage.rb +40 -0
  127. data/lib/3scale/backend/storage_async.rb +4 -0
  128. data/lib/3scale/backend/storage_async/async_redis.rb +21 -0
  129. data/lib/3scale/backend/storage_async/client.rb +205 -0
  130. data/lib/3scale/backend/storage_async/pipeline.rb +79 -0
  131. data/lib/3scale/backend/storage_async/resque_extensions.rb +30 -0
  132. data/lib/3scale/backend/storage_helpers.rb +278 -0
  133. data/lib/3scale/backend/storage_key_helpers.rb +9 -0
  134. data/lib/3scale/backend/storage_sync.rb +43 -0
  135. data/lib/3scale/backend/transaction.rb +62 -0
  136. data/lib/3scale/backend/transactor.rb +177 -0
  137. data/lib/3scale/backend/transactor/limit_headers.rb +54 -0
  138. data/lib/3scale/backend/transactor/notify_batcher.rb +139 -0
  139. data/lib/3scale/backend/transactor/notify_job.rb +47 -0
  140. data/lib/3scale/backend/transactor/process_job.rb +33 -0
  141. data/lib/3scale/backend/transactor/report_job.rb +84 -0
  142. data/lib/3scale/backend/transactor/status.rb +236 -0
  143. data/lib/3scale/backend/transactor/usage_report.rb +182 -0
  144. data/lib/3scale/backend/usage.rb +63 -0
  145. data/lib/3scale/backend/usage_limit.rb +115 -0
  146. data/lib/3scale/backend/use_cases/provider_key_change_use_case.rb +60 -0
  147. data/lib/3scale/backend/util.rb +17 -0
  148. data/lib/3scale/backend/validators.rb +26 -0
  149. data/lib/3scale/backend/validators/base.rb +36 -0
  150. data/lib/3scale/backend/validators/key.rb +17 -0
  151. data/lib/3scale/backend/validators/limits.rb +57 -0
  152. data/lib/3scale/backend/validators/oauth_key.rb +15 -0
  153. data/lib/3scale/backend/validators/oauth_setting.rb +15 -0
  154. data/lib/3scale/backend/validators/redirect_uri.rb +33 -0
  155. data/lib/3scale/backend/validators/referrer.rb +60 -0
  156. data/lib/3scale/backend/validators/service_state.rb +15 -0
  157. data/lib/3scale/backend/validators/state.rb +15 -0
  158. data/lib/3scale/backend/version.rb +5 -0
  159. data/lib/3scale/backend/views/oauth_access_tokens.builder +14 -0
  160. data/lib/3scale/backend/views/oauth_app_id_by_token.builder +4 -0
  161. data/lib/3scale/backend/worker.rb +87 -0
  162. data/lib/3scale/backend/worker_async.rb +88 -0
  163. data/lib/3scale/backend/worker_metrics.rb +44 -0
  164. data/lib/3scale/backend/worker_sync.rb +32 -0
  165. data/lib/3scale/bundler_shim.rb +17 -0
  166. data/lib/3scale/prometheus_server.rb +10 -0
  167. data/lib/3scale/tasks/connectivity.rake +41 -0
  168. data/lib/3scale/tasks/helpers.rb +3 -0
  169. data/lib/3scale/tasks/helpers/environment.rb +23 -0
  170. data/lib/3scale/tasks/stats.rake +131 -0
  171. data/lib/3scale/tasks/swagger.rake +46 -0
  172. data/licenses.xml +1215 -0
  173. metadata +227 -0
@@ -0,0 +1,99 @@
1
+ require 'yabeda/prometheus'
2
+ require 'rack'
3
+
4
+ module ThreeScale
5
+ module Backend
6
+ class ListenerMetrics
7
+ REQUEST_TYPES = {
8
+ '/transactions/authorize.xml' => 'authorize',
9
+ '/transactions/oauth_authorize.xml' => 'authorize_oauth',
10
+ '/transactions/authrep.xml' => 'authrep',
11
+ '/transactions/oauth_authrep.xml' => 'authrep_oauth',
12
+ '/transactions.xml' => 'report'
13
+ }
14
+ private_constant :REQUEST_TYPES
15
+
16
+ class << self
17
+ ERRORS_4XX_TO_TRACK = Set[403, 404, 409].freeze
18
+ private_constant :ERRORS_4XX_TO_TRACK
19
+
20
+ def start_metrics_server(port = nil)
21
+ configure_data_store
22
+ define_metrics
23
+
24
+ # Yabeda does not accept the port as a param
25
+ ENV['PROMETHEUS_EXPORTER_PORT'] = port.to_s if port
26
+ Yabeda::Prometheus::Exporter.start_metrics_server!
27
+ end
28
+
29
+ def report_resp_code(path, resp_code)
30
+ Yabeda.apisonator_listener.response_codes.increment(
31
+ {
32
+ request_type: REQUEST_TYPES[path],
33
+ resp_code: code_group(resp_code)
34
+ },
35
+ by: 1
36
+ )
37
+ end
38
+
39
+ def report_response_time(path, request_time)
40
+ Yabeda.apisonator_listener.response_times.measure(
41
+ { request_type: REQUEST_TYPES[path] },
42
+ request_time
43
+ )
44
+ end
45
+
46
+ private
47
+
48
+ def configure_data_store
49
+ # Needed to aggregate metrics across processes.
50
+ # Ref: https://github.com/yabeda-rb/yabeda-prometheus#multi-process-server-support
51
+ Dir['/tmp/prometheus/*.bin'].each do |file_path|
52
+ File.unlink(file_path)
53
+ end
54
+
55
+ Prometheus::Client.config.data_store = Prometheus::Client::DataStores::DirectFileStore.new(
56
+ dir: '/tmp/prometheus'
57
+ )
58
+ end
59
+
60
+ def define_metrics
61
+ Yabeda.configure do
62
+ group :apisonator_listener do
63
+ counter :response_codes do
64
+ comment 'Response codes'
65
+ tags %i[request_type resp_code]
66
+ end
67
+
68
+ histogram :response_times do
69
+ comment 'Response times'
70
+ unit :seconds
71
+ tags %i[request_type]
72
+ # Most requests will be under 100ms, so use a higher granularity from there
73
+ buckets [0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09, 0.1, 0.25, 0.5, 0.75, 1]
74
+ end
75
+ end
76
+ end
77
+
78
+ # Note that this method raises if called more than once. Both
79
+ # listeners and workers define their metrics, but that's fine because
80
+ # a process cannot act as both.
81
+ Yabeda.configure!
82
+ end
83
+
84
+ def code_group(resp_code)
85
+ case resp_code
86
+ when (200...300)
87
+ '2xx'.freeze
88
+ when (400...500)
89
+ ERRORS_4XX_TO_TRACK.include?(resp_code) ? resp_code : '4xx'.freeze
90
+ when (500...600)
91
+ '5xx'.freeze
92
+ else
93
+ 'unknown'.freeze
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,48 @@
1
+ require '3scale/backend/environment'
2
+ require '3scale/backend/configuration'
3
+ require '3scale/backend/logging/logger'
4
+ require '3scale/backend/logging/external'
5
+
6
+ module ThreeScale
7
+ module Backend
8
+ # include this module to have a handy access to the default logger
9
+ module Logging
10
+ def self.included(base)
11
+ enable! on: base
12
+ end
13
+
14
+ def self.enable!(on:, with: [], as: :logger)
15
+ logger = if with.empty?
16
+ Backend.logger
17
+ else
18
+ Backend::Logging::Logger.new(*with)
19
+ end
20
+
21
+ # define the method before yielding
22
+ on.send :define_method, as do
23
+ logger
24
+ end
25
+
26
+ yield logger if block_given?
27
+ end
28
+ end
29
+
30
+ class << self
31
+
32
+ private
33
+
34
+ def enable_logging
35
+ Logging.enable! on: self.singleton_class,
36
+ with: [configuration.log_file, 10] do |logger|
37
+ logger.define_singleton_method(:notify, logger_notify_proc(logger))
38
+ end
39
+ end
40
+
41
+ def logger_notify_proc(logger)
42
+ Logging::External.notify_proc || logger.method(:error).to_proc
43
+ end
44
+ end
45
+
46
+ enable_logging
47
+ end
48
+ end
@@ -0,0 +1,44 @@
1
+ require '3scale/backend/configuration'
2
+ require '3scale/backend/logging/external/impl'
3
+
4
+ module ThreeScale
5
+ module Backend
6
+ module Logging
7
+ module External
8
+ class << self
9
+ private
10
+
11
+ attr_accessor :impl, :enabled
12
+ alias_method :enabled?, :enabled
13
+ public :enabled?
14
+
15
+ public
16
+
17
+ def setup
18
+ config = Backend.configuration.hoptoad
19
+
20
+ service = if config.service && !config.service.empty?
21
+ config.service.to_sym
22
+ else
23
+ :default
24
+ end
25
+ self.impl = Impl.load service
26
+ self.enabled = impl.setup(config.api_key)
27
+ end
28
+
29
+ def reset
30
+ self.enabled = false
31
+ end
32
+
33
+ # delegate methods not overriden to the impl
34
+ (Impl::METHODS - public_instance_methods(false)).each do |m|
35
+ define_method(m) do |*args|
36
+ setup unless enabled?
37
+ impl.public_send m, *args
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,93 @@
1
+ module ThreeScale
2
+ module Backend
3
+ module Logging
4
+ module External
5
+ # This is the module that each implementation has to populate with its
6
+ # own class. The implementation file must be named after the class and
7
+ # live in a specific subdirectory relative to this file matching this
8
+ # file's name.
9
+ #
10
+ # To load the class one must specify a symbol with the base name without
11
+ # extension as the file that implements it. The class name is expected
12
+ # to be the capitalized symbol.
13
+ module Impl
14
+ # methods to be implemented by each external logging service
15
+ #
16
+ # setup - Meant to configure the service for a general use. Each other
17
+ # method in the list calls setup if it has not been called
18
+ # before.
19
+ # setup_rake - Perform additional configuration for Rake
20
+ # setup_rack - Receives the Rack object, meant to add a middleware.
21
+ # setup_worker - Additional configuration for job worker usage.
22
+ # notify_proc - The global logger's notify method will call the proc
23
+ # returned by this. If nil is returned a fallback will
24
+ # be chosen for that method (typically local logging).
25
+ #
26
+ METHODS = [:setup, :setup_rake, :setup_rack,
27
+ :setup_worker, :notify_proc].freeze
28
+
29
+ class Error < StandardError
30
+ class FileNotFound < self
31
+ def initialize(impl)
32
+ super "external logging implementation not found for #{impl.inspect}"
33
+ end
34
+ end
35
+
36
+ class ClassNotFound < self
37
+ def initialize(impl)
38
+ super "external logging implementation does not provide a " \
39
+ "similarly named class: #{impl.inspect}"
40
+ end
41
+ end
42
+ end
43
+
44
+ class << self
45
+ # returns the class implementing the logging service
46
+ def load(impl)
47
+ require(find_file impl)
48
+
49
+ fetch_impl_klass impl
50
+ end
51
+
52
+ private
53
+
54
+ def find_file(impl)
55
+ re = build_regexp impl
56
+
57
+ impl_file = Dir[glob].find do |path|
58
+ re.match(File.basename path)
59
+ end
60
+
61
+ impl_file || raise(Error::FileNotFound.new(impl))
62
+ end
63
+
64
+ def fetch_impl_klass(impl)
65
+ const_get(impl.capitalize)
66
+ rescue NameError
67
+ raise Error::ClassNotFound.new(impl)
68
+ end
69
+
70
+ def build_regexp(impl)
71
+ Regexp.new("\\A#{Regexp.escape(impl.to_s + extname)}\\z")
72
+ end
73
+
74
+ # these are almost constants, but since this is meant to be init
75
+ # code with throw-away strings they are left here as helper methods
76
+ def glob
77
+ directory << File::SEPARATOR << '*' << File.extname(__FILE__)
78
+ end
79
+
80
+ def directory
81
+ __FILE__.chomp(extname) + File::SEPARATOR
82
+ end
83
+
84
+ def extname
85
+ # assume implementations will be coded in our own language
86
+ File.extname __FILE__
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,66 @@
1
+ require '3scale/backend/environment'
2
+ require '3scale/backend/configuration'
3
+
4
+ module ThreeScale
5
+ module Backend
6
+ module Logging
7
+ module External
8
+ module Impl
9
+ module Airbrake
10
+ class << self
11
+ def setup(api_key)
12
+ do_require
13
+
14
+ configure api_key
15
+ end
16
+
17
+ def setup_rack(rack)
18
+ rack.use middleware
19
+ end
20
+
21
+ def setup_rake
22
+ require 'airbrake/tasks'
23
+ require 'airbrake/rake_handler'
24
+
25
+ ::Airbrake.configure do |config|
26
+ config.rescue_rake_exceptions = true
27
+ end
28
+ end
29
+
30
+ def setup_worker
31
+ require '3scale/backend/logging/external/resque'
32
+
33
+ External::Resque.setup klass
34
+ end
35
+
36
+ def notify_proc
37
+ klass.method(:notify).to_proc
38
+ end
39
+
40
+ private
41
+
42
+ def do_require
43
+ require 'airbrake'
44
+ end
45
+
46
+ def klass
47
+ ::Airbrake
48
+ end
49
+
50
+ def middleware
51
+ ::Airbrake::Sinatra
52
+ end
53
+
54
+ def configure(api_key)
55
+ ::Airbrake.configure do |config|
56
+ config.api_key = api_key
57
+ config.environment_name = Backend.environment
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,69 @@
1
+ require '3scale/backend/version'
2
+ require '3scale/backend/environment'
3
+ require '3scale/backend/util'
4
+ require '3scale/backend/logging'
5
+
6
+ module ThreeScale
7
+ module Backend
8
+ module Logging
9
+ module External
10
+ module Impl
11
+ module Bugsnag
12
+ class << self
13
+ def setup(api_key)
14
+ do_require
15
+
16
+ configure api_key
17
+ end
18
+
19
+ def setup_rack(rack)
20
+ rack.use middleware
21
+ end
22
+
23
+ def setup_rake
24
+ # no-op
25
+ end
26
+
27
+ def setup_worker
28
+ require '3scale/backend/logging/external/resque'
29
+
30
+ External::Resque.setup klass
31
+ end
32
+
33
+ def notify_proc
34
+ klass.method(:notify).to_proc
35
+ end
36
+
37
+ private
38
+
39
+ def do_require
40
+ require 'bugsnag'
41
+ end
42
+
43
+ def klass
44
+ ::Bugsnag
45
+ end
46
+
47
+ def middleware
48
+ ::Bugsnag::Rack
49
+ end
50
+
51
+ def configure(api_key)
52
+ ::Bugsnag.configure do |config|
53
+ config.api_key = api_key
54
+ config.release_stage = Backend.environment
55
+ config.app_version = Backend::VERSION
56
+ config.timeout = 3
57
+ config.logger = Backend.logger
58
+ config.meta_data_filters = []
59
+ config.notify_release_stages = ['production', 'preview']
60
+ config.project_root = Backend::Util.root_dir
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,18 @@
1
+ module ThreeScale
2
+ module Backend
3
+ module Logging
4
+ module External
5
+ module Impl
6
+ # the default implementation does nothing
7
+ class Default
8
+ class << self
9
+ (Impl::METHODS - public_instance_methods(false)).each do |m|
10
+ define_method(m) { |*| }
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,57 @@
1
+ # This is a module to configure an external error logging service for Resque.
2
+ #
3
+ # The requirement is that an object be passed in that implements the same
4
+ # interface as Airbrake.
5
+ #
6
+ # This requires a Resque version with https://github.com/resque/resque/pull/1602
7
+ #
8
+ module ThreeScale
9
+ module Backend
10
+ module Logging
11
+ module External
12
+ module Resque
13
+ class << self
14
+ def setup(klass)
15
+ load_resque_failure_for klass
16
+
17
+ ::Resque::Failure::Multiple.classes = [
18
+ ::Resque::Failure::Redis,
19
+ Class.new(::Resque::Failure::Airbrake) do
20
+ def self.configure(&block)
21
+ # calling this hook is an error
22
+ raise "error: tried to configure #{self.inspect} from Resque"
23
+ end
24
+ end,
25
+ ]
26
+ ::Resque::Failure.backend = ::Resque::Failure::Multiple
27
+ end
28
+
29
+ private
30
+
31
+ # set the argument as ::Airbrake and load Resque::Failure
32
+ def load_resque_failure_for(klass)
33
+ require 'resque/failure/base'
34
+ require 'resque/failure/multiple'
35
+ require 'resque/failure/redis'
36
+
37
+ # ensure we have a matching ::Airbrake top-level constant or
38
+ # define it if missing
39
+ begin
40
+ airbrake = ::Kernel.const_get(:Airbrake)
41
+ rescue NameError
42
+ # not defined, so set our own
43
+ ::Kernel.const_set(:Airbrake, klass)
44
+ else
45
+ # defined, expect it's our own object
46
+ raise "Airbrake constant pre-defined as #{airbrake.inspect}, " \
47
+ " required to be #{klass.inspect}!" if airbrake != klass
48
+ end
49
+
50
+ require 'resque/failure/airbrake'
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end