airbrake-ruby 3.2.2-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 (82) hide show
  1. checksums.yaml +7 -0
  2. data/lib/airbrake-ruby.rb +554 -0
  3. data/lib/airbrake-ruby/async_sender.rb +119 -0
  4. data/lib/airbrake-ruby/backtrace.rb +194 -0
  5. data/lib/airbrake-ruby/code_hunk.rb +53 -0
  6. data/lib/airbrake-ruby/config.rb +238 -0
  7. data/lib/airbrake-ruby/config/validator.rb +63 -0
  8. data/lib/airbrake-ruby/deploy_notifier.rb +47 -0
  9. data/lib/airbrake-ruby/file_cache.rb +48 -0
  10. data/lib/airbrake-ruby/filter_chain.rb +95 -0
  11. data/lib/airbrake-ruby/filters/context_filter.rb +29 -0
  12. data/lib/airbrake-ruby/filters/dependency_filter.rb +31 -0
  13. data/lib/airbrake-ruby/filters/exception_attributes_filter.rb +45 -0
  14. data/lib/airbrake-ruby/filters/gem_root_filter.rb +33 -0
  15. data/lib/airbrake-ruby/filters/git_last_checkout_filter.rb +90 -0
  16. data/lib/airbrake-ruby/filters/git_repository_filter.rb +42 -0
  17. data/lib/airbrake-ruby/filters/git_revision_filter.rb +66 -0
  18. data/lib/airbrake-ruby/filters/keys_blacklist.rb +50 -0
  19. data/lib/airbrake-ruby/filters/keys_filter.rb +140 -0
  20. data/lib/airbrake-ruby/filters/keys_whitelist.rb +49 -0
  21. data/lib/airbrake-ruby/filters/root_directory_filter.rb +28 -0
  22. data/lib/airbrake-ruby/filters/sql_filter.rb +104 -0
  23. data/lib/airbrake-ruby/filters/system_exit_filter.rb +23 -0
  24. data/lib/airbrake-ruby/filters/thread_filter.rb +92 -0
  25. data/lib/airbrake-ruby/hash_keyable.rb +37 -0
  26. data/lib/airbrake-ruby/ignorable.rb +44 -0
  27. data/lib/airbrake-ruby/nested_exception.rb +39 -0
  28. data/lib/airbrake-ruby/notice.rb +165 -0
  29. data/lib/airbrake-ruby/notice_notifier.rb +228 -0
  30. data/lib/airbrake-ruby/performance_notifier.rb +161 -0
  31. data/lib/airbrake-ruby/promise.rb +99 -0
  32. data/lib/airbrake-ruby/response.rb +71 -0
  33. data/lib/airbrake-ruby/stat.rb +56 -0
  34. data/lib/airbrake-ruby/sync_sender.rb +111 -0
  35. data/lib/airbrake-ruby/tdigest.rb +393 -0
  36. data/lib/airbrake-ruby/time_truncate.rb +17 -0
  37. data/lib/airbrake-ruby/truncator.rb +115 -0
  38. data/lib/airbrake-ruby/version.rb +6 -0
  39. data/spec/airbrake_spec.rb +171 -0
  40. data/spec/async_sender_spec.rb +154 -0
  41. data/spec/backtrace_spec.rb +438 -0
  42. data/spec/code_hunk_spec.rb +118 -0
  43. data/spec/config/validator_spec.rb +189 -0
  44. data/spec/config_spec.rb +281 -0
  45. data/spec/deploy_notifier_spec.rb +41 -0
  46. data/spec/file_cache.rb +36 -0
  47. data/spec/filter_chain_spec.rb +83 -0
  48. data/spec/filters/context_filter_spec.rb +25 -0
  49. data/spec/filters/dependency_filter_spec.rb +14 -0
  50. data/spec/filters/exception_attributes_filter_spec.rb +63 -0
  51. data/spec/filters/gem_root_filter_spec.rb +44 -0
  52. data/spec/filters/git_last_checkout_filter_spec.rb +48 -0
  53. data/spec/filters/git_repository_filter.rb +53 -0
  54. data/spec/filters/git_revision_filter_spec.rb +126 -0
  55. data/spec/filters/keys_blacklist_spec.rb +236 -0
  56. data/spec/filters/keys_whitelist_spec.rb +205 -0
  57. data/spec/filters/root_directory_filter_spec.rb +42 -0
  58. data/spec/filters/sql_filter_spec.rb +219 -0
  59. data/spec/filters/system_exit_filter_spec.rb +14 -0
  60. data/spec/filters/thread_filter_spec.rb +279 -0
  61. data/spec/fixtures/notroot.txt +7 -0
  62. data/spec/fixtures/project_root/code.rb +221 -0
  63. data/spec/fixtures/project_root/empty_file.rb +0 -0
  64. data/spec/fixtures/project_root/long_line.txt +1 -0
  65. data/spec/fixtures/project_root/short_file.rb +3 -0
  66. data/spec/fixtures/project_root/vendor/bundle/ignored_file.rb +5 -0
  67. data/spec/helpers.rb +9 -0
  68. data/spec/ignorable_spec.rb +14 -0
  69. data/spec/nested_exception_spec.rb +75 -0
  70. data/spec/notice_notifier_spec.rb +436 -0
  71. data/spec/notice_notifier_spec/options_spec.rb +266 -0
  72. data/spec/notice_spec.rb +297 -0
  73. data/spec/performance_notifier_spec.rb +287 -0
  74. data/spec/promise_spec.rb +165 -0
  75. data/spec/response_spec.rb +82 -0
  76. data/spec/spec_helper.rb +102 -0
  77. data/spec/stat_spec.rb +35 -0
  78. data/spec/sync_sender_spec.rb +140 -0
  79. data/spec/tdigest_spec.rb +230 -0
  80. data/spec/time_truncate_spec.rb +13 -0
  81. data/spec/truncator_spec.rb +238 -0
  82. metadata +278 -0
@@ -0,0 +1,119 @@
1
+ module Airbrake
2
+ # Responsible for sending notices to Airbrake asynchronously. The class
3
+ # supports an unlimited number of worker threads and an unlimited queue size
4
+ # (both values are configurable).
5
+ #
6
+ # @see SyncSender
7
+ # @api private
8
+ # @since v1.0.0
9
+ class AsyncSender
10
+ # @param [Airbrake::Config] config
11
+ def initialize(config)
12
+ @config = config
13
+ @unsent = SizedQueue.new(config.queue_size)
14
+ @sender = SyncSender.new(config)
15
+ @closed = false
16
+ @workers = ThreadGroup.new
17
+ @mutex = Mutex.new
18
+ @pid = nil
19
+ end
20
+
21
+ # Asynchronously sends a notice to Airbrake.
22
+ #
23
+ # @param [Airbrake::Notice] notice A notice that was generated by the
24
+ # library
25
+ # @return [Airbrake::Promise]
26
+ def send(notice, promise)
27
+ return will_not_deliver(notice) if @unsent.size >= @unsent.max
28
+
29
+ @unsent << [notice, promise]
30
+ promise
31
+ end
32
+
33
+ # Closes the instance making it a no-op (it shut downs all worker
34
+ # threads). Before closing, waits on all unsent notices to be sent.
35
+ #
36
+ # @return [void]
37
+ # @raise [Airbrake::Error] when invoked more than one time
38
+ def close
39
+ threads = @mutex.synchronize do
40
+ raise Airbrake::Error, 'attempted to close already closed sender' if closed?
41
+
42
+ unless @unsent.empty?
43
+ msg = "#{LOG_LABEL} waiting to send #{@unsent.size} unsent notice(s)..."
44
+ @config.logger.debug(msg + ' (Ctrl-C to abort)')
45
+ end
46
+
47
+ @config.workers.times { @unsent << [:stop, Airbrake::Promise.new] }
48
+ @closed = true
49
+ @workers.list.dup
50
+ end
51
+
52
+ threads.each(&:join)
53
+ @config.logger.debug("#{LOG_LABEL} closed")
54
+ end
55
+
56
+ # Checks whether the sender is closed and thus usable.
57
+ # @return [Boolean]
58
+ def closed?
59
+ @closed
60
+ end
61
+
62
+ # Checks if an active sender has any workers. A sender doesn't have any
63
+ # workers only in two cases: when it was closed or when all workers
64
+ # crashed. An *active* sender doesn't have any workers only when something
65
+ # went wrong.
66
+ #
67
+ # Workers are expected to crash when you +fork+ the process the workers are
68
+ # living in. In this case we detect a +fork+ and try to revive them here.
69
+ #
70
+ # Another possible scenario that crashes workers is when you close the
71
+ # instance on +at_exit+, but some other +at_exit+ hook prevents the process
72
+ # from exiting.
73
+ #
74
+ # @return [Boolean] true if an instance wasn't closed, but has no workers
75
+ # @see https://goo.gl/oydz8h Example of at_exit that prevents exit
76
+ def has_workers?
77
+ @mutex.synchronize do
78
+ return false if @closed
79
+
80
+ if @pid != Process.pid && @workers.list.empty?
81
+ @pid = Process.pid
82
+ spawn_workers
83
+ end
84
+
85
+ !@closed && @workers.list.any?
86
+ end
87
+ end
88
+
89
+ private
90
+
91
+ def spawn_workers
92
+ @workers = ThreadGroup.new
93
+ @config.workers.times { @workers.add(spawn_worker) }
94
+ @workers.enclose
95
+ end
96
+
97
+ def spawn_worker
98
+ Thread.new do
99
+ while (message = @unsent.pop)
100
+ break if message.first == :stop
101
+ @sender.send(*message)
102
+ end
103
+ end
104
+ end
105
+
106
+ def will_not_deliver(notice)
107
+ backtrace = notice[:errors][0][:backtrace].map do |line|
108
+ "#{line[:file]}:#{line[:line]} in `#{line[:function]}'"
109
+ end
110
+ @config.logger.error(
111
+ "#{LOG_LABEL} AsyncSender has reached its capacity of " \
112
+ "#{@unsent.max} and the following notice will not be delivered " \
113
+ "Error: #{notice[:errors][0][:type]} - #{notice[:errors][0][:message]}\n" \
114
+ "Backtrace: \n" + backtrace.join("\n")
115
+ )
116
+ nil
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,194 @@
1
+ module Airbrake
2
+ # Represents a cross-Ruby backtrace from exceptions (including JRuby Java
3
+ # exceptions). Provides information about stack frames (such as line number,
4
+ # file and method) in convenient for Airbrake format.
5
+ #
6
+ # @example
7
+ # begin
8
+ # raise 'Oops!'
9
+ # rescue
10
+ # Backtrace.parse($!, Logger.new(STDOUT))
11
+ # end
12
+ #
13
+ # @api private
14
+ # @since v1.0.0
15
+ module Backtrace
16
+ module Patterns
17
+ # @return [Regexp] the pattern that matches standard Ruby stack frames,
18
+ # such as ./spec/notice_spec.rb:43:in `block (3 levels) in <top (required)>'
19
+ RUBY = %r{\A
20
+ (?<file>.+) # Matches './spec/notice_spec.rb'
21
+ :
22
+ (?<line>\d+) # Matches '43'
23
+ :in\s
24
+ `(?<function>.*)' # Matches "`block (3 levels) in <top (required)>'"
25
+ \z}x
26
+
27
+ # @return [Regexp] the pattern that matches JRuby Java stack frames, such
28
+ # as org.jruby.ast.NewlineNode.interpret(NewlineNode.java:105)
29
+ JAVA = %r{\A
30
+ (?<function>.+) # Matches 'org.jruby.ast.NewlineNode.interpret'
31
+ \(
32
+ (?<file>
33
+ (?:uri:classloader:/.+(?=:)) # Matches '/META-INF/jruby.home/protocol.rb'
34
+ |
35
+ (?:uri_3a_classloader_3a_.+(?=:)) # Matches 'uri_3a_classloader_3a_/gems/...'
36
+ |
37
+ [^:]+ # Matches 'NewlineNode.java'
38
+ )
39
+ :?
40
+ (?<line>\d+)? # Matches '105'
41
+ \)
42
+ \z}x
43
+
44
+ # @return [Regexp] the pattern that tries to assume what a generic stack
45
+ # frame might look like, when exception's backtrace is set manually.
46
+ GENERIC = %r{\A
47
+ (?:from\s)?
48
+ (?<file>.+) # Matches '/foo/bar/baz.ext'
49
+ :
50
+ (?<line>\d+)? # Matches '43' or nothing
51
+ (?:
52
+ in\s`(?<function>.+)' # Matches "in `func'"
53
+ |
54
+ :in\s(?<function>.+) # Matches ":in func"
55
+ )? # ... or nothing
56
+ \z}x
57
+
58
+ # @return [Regexp] the pattern that matches exceptions from PL/SQL such as
59
+ # ORA-06512: at "STORE.LI_LICENSES_PACK", line 1945
60
+ # @note This is raised by https://github.com/kubo/ruby-oci8
61
+ OCI = /\A
62
+ (?:
63
+ ORA-\d{5}
64
+ :\sat\s
65
+ (?:"(?<function>.+)",\s)?
66
+ line\s(?<line>\d+)
67
+ |
68
+ #{GENERIC}
69
+ )
70
+ \z/x
71
+
72
+ # @return [Regexp] the pattern that matches CoffeeScript backtraces
73
+ # usually coming from Rails & ExecJS
74
+ EXECJS = /\A
75
+ (?:
76
+ # Matches 'compile ((execjs):6692:19)'
77
+ (?<function>.+)\s\((?<file>.+):(?<line>\d+):\d+\)
78
+ |
79
+ # Matches 'bootstrap_node.js:467:3'
80
+ (?<file>.+):(?<line>\d+):\d+(?<function>)
81
+ |
82
+ # Matches the Ruby part of the backtrace
83
+ #{RUBY}
84
+ )
85
+ \z/x
86
+ end
87
+
88
+ # @return [Integer] how many first frames should include code hunks
89
+ CODE_FRAME_LIMIT = 10
90
+
91
+ # Parses an exception's backtrace.
92
+ #
93
+ # @param [Exception] exception The exception, which contains a backtrace to
94
+ # parse
95
+ # @return [Array<Hash{Symbol=>String,Integer}>] the parsed backtrace
96
+ def self.parse(config, exception)
97
+ return [] if exception.backtrace.nil? || exception.backtrace.none?
98
+ parse_backtrace(config, exception)
99
+ end
100
+
101
+ # Checks whether the given exception was generated by JRuby's VM.
102
+ #
103
+ # @param [Exception] exception
104
+ # @return [Boolean]
105
+ def self.java_exception?(exception)
106
+ if defined?(Java::JavaLang::Throwable) &&
107
+ exception.is_a?(Java::JavaLang::Throwable)
108
+ return true
109
+ end
110
+
111
+ return false unless exception.respond_to?(:backtrace)
112
+
113
+ (Patterns::JAVA =~ exception.backtrace.first) != nil
114
+ end
115
+
116
+ class << self
117
+ private
118
+
119
+ def best_regexp_for(exception)
120
+ if java_exception?(exception)
121
+ Patterns::JAVA
122
+ elsif oci_exception?(exception)
123
+ Patterns::OCI
124
+ elsif execjs_exception?(exception)
125
+ Patterns::EXECJS
126
+ else
127
+ Patterns::RUBY
128
+ end
129
+ end
130
+
131
+ def oci_exception?(exception)
132
+ defined?(OCIError) && exception.is_a?(OCIError)
133
+ end
134
+
135
+ def execjs_exception?(exception)
136
+ return false unless defined?(ExecJS::RuntimeError)
137
+ return true if exception.is_a?(ExecJS::RuntimeError)
138
+ return true if exception.cause && exception.cause.is_a?(ExecJS::RuntimeError)
139
+
140
+ false
141
+ end
142
+
143
+ def stack_frame(config, regexp, stackframe)
144
+ if (match = match_frame(regexp, stackframe))
145
+ return {
146
+ file: match[:file],
147
+ line: (Integer(match[:line]) if match[:line]),
148
+ function: match[:function]
149
+ }
150
+ end
151
+
152
+ config.logger.error(
153
+ "can't parse '#{stackframe}' (please file an issue so we can fix " \
154
+ "it: https://github.com/airbrake/airbrake-ruby/issues/new)"
155
+ )
156
+ { file: nil, line: nil, function: stackframe }
157
+ end
158
+
159
+ def match_frame(regexp, stackframe)
160
+ match = regexp.match(stackframe)
161
+ return match if match
162
+
163
+ Patterns::GENERIC.match(stackframe)
164
+ end
165
+
166
+ def parse_backtrace(config, exception)
167
+ regexp = best_regexp_for(exception)
168
+ root_directory = config.root_directory.to_s
169
+
170
+ exception.backtrace.map.with_index do |stackframe, i|
171
+ frame = stack_frame(config, regexp, stackframe)
172
+ next(frame) if !config.code_hunks || frame[:file].nil?
173
+
174
+ if !root_directory.empty?
175
+ populate_code(config, frame) if frame_in_root?(frame, root_directory)
176
+ elsif i < CODE_FRAME_LIMIT
177
+ populate_code(config, frame)
178
+ end
179
+
180
+ frame
181
+ end
182
+ end
183
+
184
+ def populate_code(config, frame)
185
+ code = Airbrake::CodeHunk.new(config).get(frame[:file], frame[:line])
186
+ frame[:code] = code if code
187
+ end
188
+
189
+ def frame_in_root?(frame, root_directory)
190
+ frame[:file].start_with?(root_directory) && frame[:file] !~ %r{vendor/bundle}
191
+ end
192
+ end
193
+ end
194
+ end
@@ -0,0 +1,53 @@
1
+ module Airbrake
2
+ # Represents a small hunk of code consisting of a base line and a couple lines
3
+ # around it
4
+ # @api private
5
+ class CodeHunk
6
+ # @return [Integer] the maximum length of a line
7
+ MAX_LINE_LEN = 200
8
+
9
+ # @return [Integer] how many lines should be read around the base line
10
+ NLINES = 2
11
+
12
+ def initialize(config)
13
+ @config = config
14
+ end
15
+
16
+ # @param [String] file The file to read
17
+ # @param [Integer] line The base line in the file
18
+ # @return [Hash{Integer=>String}, nil] lines of code around the base line
19
+ def get(file, line)
20
+ return unless File.exist?(file)
21
+ return unless line
22
+
23
+ lines = get_lines(file, [line - NLINES, 1].max, line + NLINES) || {}
24
+ return { 1 => '' } if lines.empty?
25
+
26
+ lines
27
+ end
28
+
29
+ private
30
+
31
+ def get_from_cache(file)
32
+ Airbrake::FileCache[file] ||= File.foreach(file)
33
+ rescue StandardError => ex
34
+ @config.logger.error(
35
+ "#{self.class.name}: can't read code hunk for #{file}: #{ex}"
36
+ )
37
+ nil
38
+ end
39
+
40
+ def get_lines(file, start_line, end_line)
41
+ return unless (cached_file = get_from_cache(file))
42
+
43
+ lines = {}
44
+ cached_file.with_index(1) do |l, i|
45
+ next if i < start_line
46
+ break if i > end_line
47
+
48
+ lines[i] = l[0...MAX_LINE_LEN].rstrip
49
+ end
50
+ lines
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,238 @@
1
+ module Airbrake
2
+ # Represents the Airbrake config. A config contains all the options that you
3
+ # can use to configure an Airbrake instance.
4
+ #
5
+ # @api public
6
+ # @since v1.0.0
7
+ class Config
8
+ # @return [Integer] the project identificator. This value *must* be set.
9
+ # @api public
10
+ attr_accessor :project_id
11
+
12
+ # @return [String] the project key. This value *must* be set.
13
+ # @api public
14
+ attr_accessor :project_key
15
+
16
+ # @return [Hash] the proxy parameters such as (:host, :port, :user and
17
+ # :password)
18
+ # @api public
19
+ attr_accessor :proxy
20
+
21
+ # @return [Logger] the default logger used for debug output
22
+ # @api public
23
+ attr_reader :logger
24
+
25
+ # @return [String] the version of the user's application
26
+ # @api public
27
+ attr_accessor :app_version
28
+
29
+ # @return [Hash{String=>String}] arbitrary versions that your app wants to
30
+ # track
31
+ # @api public
32
+ # @since v2.10.0
33
+ attr_accessor :versions
34
+
35
+ # @return [Integer] the max number of notices that can be queued up
36
+ # @api public
37
+ attr_accessor :queue_size
38
+
39
+ # @return [Integer] the number of worker threads that process the notice
40
+ # queue
41
+ # @api public
42
+ attr_accessor :workers
43
+
44
+ # @return [String] the host, which provides the API endpoint to which
45
+ # exceptions should be sent
46
+ # @api public
47
+ attr_accessor :host
48
+
49
+ # @return [String, Pathname] the working directory of your project
50
+ # @api public
51
+ attr_accessor :root_directory
52
+
53
+ # @return [String, Symbol] the environment the application is running in
54
+ # @api public
55
+ attr_accessor :environment
56
+
57
+ # @return [Array<String,Symbol,Regexp>] the array of environments that
58
+ # forbids sending exceptions when the application is running in them.
59
+ # Other possible environments not listed in the array will allow sending
60
+ # occurring exceptions.
61
+ # @api public
62
+ attr_accessor :ignore_environments
63
+
64
+ # @return [Integer] The HTTP timeout in seconds.
65
+ # @api public
66
+ attr_accessor :timeout
67
+
68
+ # @return [Array<String, Symbol, Regexp>] the keys, which should be
69
+ # filtered
70
+ # @api public
71
+ # @since v1.2.0
72
+ attr_accessor :blacklist_keys
73
+
74
+ # @return [Array<String, Symbol, Regexp>] the keys, which shouldn't be
75
+ # filtered
76
+ # @api public
77
+ # @since v1.2.0
78
+ attr_accessor :whitelist_keys
79
+
80
+ # @return [Boolean] true if the library should attach code hunks to each
81
+ # frame in a backtrace, false otherwise
82
+ # @api public
83
+ # @since v2.5.0
84
+ attr_accessor :code_hunks
85
+
86
+ # @return [Boolean] true if the library should send performance stats
87
+ # information to Airbrake (routes, SQL queries), false otherwise
88
+ # @api public
89
+ # @since v3.2.0
90
+ attr_accessor :performance_stats
91
+
92
+ # @return [Integer] how many seconds to wait before sending collected route
93
+ # stats
94
+ # @api public
95
+ # @since v3.2.0
96
+ attr_accessor :performance_stats_flush_period
97
+
98
+ # @param [Hash{Symbol=>Object}] user_config the hash to be used to build the
99
+ # config
100
+ # rubocop:disable Metrics/AbcSize
101
+ def initialize(user_config = {})
102
+ @validator = Config::Validator.new(self)
103
+
104
+ self.proxy = {}
105
+ self.queue_size = 100
106
+ self.workers = 1
107
+ self.code_hunks = true
108
+
109
+ self.logger = Logger.new(STDOUT)
110
+ logger.level = Logger::WARN
111
+
112
+ self.project_id = user_config[:project_id]
113
+ self.project_key = user_config[:project_key]
114
+ self.host = 'https://api.airbrake.io'
115
+
116
+ self.ignore_environments = []
117
+
118
+ self.timeout = user_config[:timeout]
119
+
120
+ self.blacklist_keys = []
121
+ self.whitelist_keys = []
122
+
123
+ self.root_directory = File.realpath(
124
+ (defined?(Bundler) && Bundler.root) ||
125
+ Dir.pwd
126
+ )
127
+
128
+ self.versions = {}
129
+ self.performance_stats = false
130
+ self.performance_stats_flush_period = 15
131
+
132
+ merge(user_config)
133
+ end
134
+ # rubocop:enable Metrics/AbcSize
135
+
136
+ # The full URL to the Airbrake Notice API. Based on the +:host+ option.
137
+ # @return [URI] the endpoint address
138
+ def endpoint
139
+ @endpoint ||=
140
+ begin
141
+ self.host = ('https://' << host) if host !~ %r{\Ahttps?://}
142
+ api = "api/v3/projects/#{project_id}/notices"
143
+ URI.join(host, api)
144
+ end
145
+ end
146
+
147
+ # Sets the logger. Never allows to assign `nil` as the logger.
148
+ # @return [Logger] the logger
149
+ def logger=(logger)
150
+ @logger = logger || @logger
151
+ end
152
+
153
+ # Merges the given +config_hash+ with itself.
154
+ #
155
+ # @example
156
+ # config.merge(host: 'localhost:8080')
157
+ #
158
+ # @return [self] the merged config
159
+ def merge(config_hash)
160
+ config_hash.each_pair { |option, value| set_option(option, value) }
161
+ self
162
+ end
163
+
164
+ # @return [Boolean] true if the config meets the requirements, false
165
+ # otherwise
166
+ def valid?
167
+ return true if ignored_environment?
168
+
169
+ return false unless @validator.valid_project_id?
170
+ return false unless @validator.valid_project_key?
171
+ return false unless @validator.valid_environment?
172
+
173
+ true
174
+ end
175
+
176
+ def validation_error_message
177
+ @validator.error_message
178
+ end
179
+
180
+ # @return [Boolean] true if the config ignores current environment, false
181
+ # otherwise
182
+ def ignored_environment?
183
+ if ignore_environments.any? && environment.nil?
184
+ logger.warn("#{LOG_LABEL} the 'environment' option is not set, " \
185
+ "'ignore_environments' has no effect")
186
+ end
187
+
188
+ env = environment.to_s
189
+ ignore_environments.any? do |pattern|
190
+ if pattern.is_a?(Regexp)
191
+ env.match(pattern)
192
+ else
193
+ env == pattern.to_s
194
+ end
195
+ end
196
+ end
197
+
198
+ def route_stats
199
+ logger.warn(
200
+ "#{LOG_LABEL} the 'route_stats' option is deprecated. " \
201
+ "Use 'performance_stats' instead"
202
+ )
203
+ @performance_stats
204
+ end
205
+
206
+ def route_stats=(value)
207
+ logger.warn(
208
+ "#{LOG_LABEL} the 'route_stats' option is deprecated. " \
209
+ "Use 'performance_stats_flush_period' instead"
210
+ )
211
+ @performance_stats = value
212
+ end
213
+
214
+ def route_stats_flush_period
215
+ logger.warn(
216
+ "#{LOG_LABEL} the 'route_stats_flush_period' option is deprecated. " \
217
+ "Use 'performance_stats_flush_period' instead"
218
+ )
219
+ @performance_stats_flush_period
220
+ end
221
+
222
+ def route_stats_flush_period=(value)
223
+ logger.warn(
224
+ "#{LOG_LABEL} the 'route_stats_flush_period' option is deprecated. " \
225
+ "Use 'performance_stats' instead"
226
+ )
227
+ @performance_stats_flush_period = value
228
+ end
229
+
230
+ private
231
+
232
+ def set_option(option, value)
233
+ __send__("#{option}=", value)
234
+ rescue NoMethodError
235
+ raise Airbrake::Error, "unknown option '#{option}'"
236
+ end
237
+ end
238
+ end