sentry-raven 3.0.1 → 3.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.craft.yml +2 -1
- data/.github/ISSUE_TEMPLATE/bug_report.md +32 -0
- data/.github/pull_request_template.md +16 -0
- data/.github/workflows/test.yml +41 -26
- data/.github/workflows/zeus_upload.yml +32 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +6 -3
- data/{changelog.md → CHANGELOG.md} +157 -7
- data/CONTRIBUTING.md +71 -0
- data/Gemfile +5 -2
- data/README.md +29 -14
- data/lib/raven/backtrace.rb +2 -0
- data/lib/raven/base.rb +2 -0
- data/lib/raven/breadcrumbs/active_support_logger.rb +25 -0
- data/lib/raven/breadcrumbs/logger.rb +2 -92
- data/lib/raven/breadcrumbs/sentry_logger.rb +73 -0
- data/lib/raven/cli.rb +8 -19
- data/lib/raven/client.rb +1 -1
- data/lib/raven/configuration.rb +81 -5
- data/lib/raven/context.rb +13 -8
- data/lib/raven/core_ext/object/deep_dup.rb +57 -0
- data/lib/raven/core_ext/object/duplicable.rb +153 -0
- data/lib/raven/event.rb +23 -13
- data/lib/raven/helpers/deprecation_helper.rb +17 -0
- data/lib/raven/instance.rb +10 -1
- data/lib/raven/integrations/delayed_job.rb +2 -1
- data/lib/raven/integrations/rack-timeout.rb +5 -1
- data/lib/raven/integrations/rack.rb +15 -2
- data/lib/raven/integrations/rails.rb +12 -3
- data/lib/raven/integrations/rails/active_job.rb +2 -1
- data/lib/raven/integrations/rails/backtrace_cleaner.rb +29 -0
- data/lib/raven/integrations/sidekiq.rb +4 -78
- data/lib/raven/integrations/sidekiq/cleanup_middleware.rb +13 -0
- data/lib/raven/integrations/sidekiq/error_handler.rb +38 -0
- data/lib/raven/processor/cookies.rb +1 -1
- data/lib/raven/processor/removecircularreferences.rb +2 -1
- data/lib/raven/transports/http.rb +0 -2
- data/lib/raven/utils/context_filter.rb +42 -0
- data/lib/raven/version.rb +1 -1
- data/lib/sentry-raven-without-integrations.rb +6 -1
- data/lib/sentry_raven_without_integrations.rb +1 -0
- data/sentry-ruby/.gitignore +11 -0
- data/sentry-ruby/.rspec +3 -0
- data/sentry-ruby/.travis.yml +6 -0
- data/sentry-ruby/CODE_OF_CONDUCT.md +74 -0
- data/sentry-ruby/Gemfile +9 -0
- data/sentry-ruby/LICENSE.txt +21 -0
- data/sentry-ruby/README.md +44 -0
- data/sentry-ruby/Rakefile +6 -0
- data/sentry-ruby/bin/console +14 -0
- data/sentry-ruby/bin/setup +8 -0
- data/sentry-ruby/examples/rails-6.0/.browserslistrc +1 -0
- data/sentry-ruby/examples/rails-6.0/.gitignore +35 -0
- data/sentry-ruby/examples/rails-6.0/Gemfile +58 -0
- data/sentry-ruby/examples/rails-6.0/README.md +23 -0
- data/sentry-ruby/examples/rails-6.0/Rakefile +6 -0
- data/sentry-ruby/examples/rails-6.0/app/assets/config/manifest.js +2 -0
- data/sentry-ruby/examples/rails-6.0/app/assets/images/.keep +0 -0
- data/sentry-ruby/examples/rails-6.0/app/assets/stylesheets/application.css +15 -0
- data/sentry-ruby/examples/rails-6.0/app/channels/application_cable/channel.rb +4 -0
- data/sentry-ruby/examples/rails-6.0/app/channels/application_cable/connection.rb +4 -0
- data/sentry-ruby/examples/rails-6.0/app/controllers/application_controller.rb +2 -0
- data/sentry-ruby/examples/rails-6.0/app/controllers/concerns/.keep +0 -0
- data/sentry-ruby/examples/rails-6.0/app/controllers/welcome_controller.rb +23 -0
- data/sentry-ruby/examples/rails-6.0/app/helpers/application_helper.rb +2 -0
- data/sentry-ruby/examples/rails-6.0/app/javascript/channels/consumer.js +6 -0
- data/sentry-ruby/examples/rails-6.0/app/javascript/channels/index.js +5 -0
- data/sentry-ruby/examples/rails-6.0/app/javascript/packs/application.js +17 -0
- data/sentry-ruby/examples/rails-6.0/app/jobs/application_job.rb +7 -0
- data/sentry-ruby/examples/rails-6.0/app/mailers/application_mailer.rb +4 -0
- data/sentry-ruby/examples/rails-6.0/app/models/application_record.rb +3 -0
- data/sentry-ruby/examples/rails-6.0/app/models/concerns/.keep +0 -0
- data/sentry-ruby/examples/rails-6.0/app/views/layouts/application.html.erb +15 -0
- data/sentry-ruby/examples/rails-6.0/app/views/layouts/mailer.html.erb +13 -0
- data/sentry-ruby/examples/rails-6.0/app/views/layouts/mailer.text.erb +1 -0
- data/sentry-ruby/examples/rails-6.0/app/views/welcome/report_demo.html.erb +22 -0
- data/sentry-ruby/examples/rails-6.0/app/views/welcome/view_error.html.erb +1 -0
- data/sentry-ruby/examples/rails-6.0/app/workers/error_worker.rb +7 -0
- data/sentry-ruby/examples/rails-6.0/babel.config.js +72 -0
- data/sentry-ruby/examples/rails-6.0/bin/bundle +114 -0
- data/sentry-ruby/examples/rails-6.0/bin/rails +9 -0
- data/sentry-ruby/examples/rails-6.0/bin/rake +9 -0
- data/sentry-ruby/examples/rails-6.0/bin/setup +36 -0
- data/sentry-ruby/examples/rails-6.0/bin/spring +17 -0
- data/sentry-ruby/examples/rails-6.0/bin/webpack +18 -0
- data/sentry-ruby/examples/rails-6.0/bin/webpack-dev-server +18 -0
- data/sentry-ruby/examples/rails-6.0/bin/yarn +11 -0
- data/sentry-ruby/examples/rails-6.0/config.ru +5 -0
- data/sentry-ruby/examples/rails-6.0/config/application.rb +28 -0
- data/sentry-ruby/examples/rails-6.0/config/boot.rb +4 -0
- data/sentry-ruby/examples/rails-6.0/config/cable.yml +10 -0
- data/sentry-ruby/examples/rails-6.0/config/credentials.yml.enc +1 -0
- data/sentry-ruby/examples/rails-6.0/config/database.yml +25 -0
- data/sentry-ruby/examples/rails-6.0/config/environment.rb +5 -0
- data/sentry-ruby/examples/rails-6.0/config/environments/development.rb +62 -0
- data/sentry-ruby/examples/rails-6.0/config/environments/production.rb +112 -0
- data/sentry-ruby/examples/rails-6.0/config/environments/test.rb +48 -0
- data/sentry-ruby/examples/rails-6.0/config/initializers/application_controller_renderer.rb +8 -0
- data/sentry-ruby/examples/rails-6.0/config/initializers/assets.rb +14 -0
- data/sentry-ruby/examples/rails-6.0/config/initializers/backtrace_silencers.rb +7 -0
- data/sentry-ruby/examples/rails-6.0/config/initializers/content_security_policy.rb +30 -0
- data/sentry-ruby/examples/rails-6.0/config/initializers/cookies_serializer.rb +5 -0
- data/sentry-ruby/examples/rails-6.0/config/initializers/filter_parameter_logging.rb +4 -0
- data/sentry-ruby/examples/rails-6.0/config/initializers/inflections.rb +16 -0
- data/sentry-ruby/examples/rails-6.0/config/initializers/mime_types.rb +4 -0
- data/sentry-ruby/examples/rails-6.0/config/initializers/wrap_parameters.rb +14 -0
- data/sentry-ruby/examples/rails-6.0/config/locales/en.yml +33 -0
- data/sentry-ruby/examples/rails-6.0/config/puma.rb +38 -0
- data/sentry-ruby/examples/rails-6.0/config/routes.rb +10 -0
- data/sentry-ruby/examples/rails-6.0/config/spring.rb +6 -0
- data/sentry-ruby/examples/rails-6.0/config/storage.yml +34 -0
- data/sentry-ruby/examples/rails-6.0/config/webpack/development.js +5 -0
- data/sentry-ruby/examples/rails-6.0/config/webpack/environment.js +3 -0
- data/sentry-ruby/examples/rails-6.0/config/webpack/production.js +5 -0
- data/sentry-ruby/examples/rails-6.0/config/webpack/test.js +5 -0
- data/sentry-ruby/examples/rails-6.0/config/webpacker.yml +96 -0
- data/sentry-ruby/examples/rails-6.0/db/seeds.rb +7 -0
- data/sentry-ruby/examples/rails-6.0/lib/assets/.keep +0 -0
- data/sentry-ruby/examples/rails-6.0/lib/tasks/.keep +0 -0
- data/sentry-ruby/examples/rails-6.0/package.json +15 -0
- data/sentry-ruby/examples/rails-6.0/postcss.config.js +12 -0
- data/sentry-ruby/examples/rails-6.0/public/404.html +67 -0
- data/sentry-ruby/examples/rails-6.0/public/422.html +67 -0
- data/sentry-ruby/examples/rails-6.0/public/500.html +66 -0
- data/sentry-ruby/examples/rails-6.0/public/apple-touch-icon-precomposed.png +0 -0
- data/sentry-ruby/examples/rails-6.0/public/apple-touch-icon.png +0 -0
- data/sentry-ruby/examples/rails-6.0/public/favicon.ico +0 -0
- data/sentry-ruby/examples/rails-6.0/public/robots.txt +1 -0
- data/sentry-ruby/examples/rails-6.0/storage/.keep +0 -0
- data/sentry-ruby/examples/rails-6.0/test/application_system_test_case.rb +5 -0
- data/sentry-ruby/examples/rails-6.0/test/channels/application_cable/connection_test.rb +11 -0
- data/sentry-ruby/examples/rails-6.0/test/controllers/.keep +0 -0
- data/sentry-ruby/examples/rails-6.0/test/fixtures/.keep +0 -0
- data/sentry-ruby/examples/rails-6.0/test/fixtures/files/.keep +0 -0
- data/sentry-ruby/examples/rails-6.0/test/helpers/.keep +0 -0
- data/sentry-ruby/examples/rails-6.0/test/integration/.keep +0 -0
- data/sentry-ruby/examples/rails-6.0/test/mailers/.keep +0 -0
- data/sentry-ruby/examples/rails-6.0/test/models/.keep +0 -0
- data/sentry-ruby/examples/rails-6.0/test/system/.keep +0 -0
- data/sentry-ruby/examples/rails-6.0/test/test_helper.rb +13 -0
- data/sentry-ruby/examples/rails-6.0/vendor/.keep +0 -0
- data/sentry-ruby/examples/rails-6.0/yarn.lock +7508 -0
- data/sentry-ruby/lib/sentry.rb +16 -0
- data/sentry-ruby/lib/sentry/backtrace.rb +128 -0
- data/sentry-ruby/lib/sentry/client.rb +162 -0
- data/sentry-ruby/lib/sentry/client/state.rb +40 -0
- data/sentry-ruby/lib/sentry/configuration.rb +533 -0
- data/sentry-ruby/lib/sentry/event.rb +209 -0
- data/sentry-ruby/lib/sentry/interface.rb +31 -0
- data/sentry-ruby/lib/sentry/interfaces/exception.rb +15 -0
- data/sentry-ruby/lib/sentry/interfaces/http.rb +16 -0
- data/sentry-ruby/lib/sentry/interfaces/message.rb +18 -0
- data/sentry-ruby/lib/sentry/interfaces/single_exception.rb +14 -0
- data/sentry-ruby/lib/sentry/interfaces/stack_trace.rb +69 -0
- data/sentry-ruby/lib/sentry/linecache.rb +44 -0
- data/sentry-ruby/lib/sentry/logger.rb +20 -0
- data/sentry-ruby/lib/sentry/transports.rb +19 -0
- data/sentry-ruby/lib/sentry/transports/dummy.rb +16 -0
- data/sentry-ruby/lib/sentry/transports/http.rb +66 -0
- data/sentry-ruby/lib/sentry/transports/stdout.rb +20 -0
- data/sentry-ruby/lib/sentry/utils/deep_merge.rb +22 -0
- data/sentry-ruby/lib/sentry/utils/exception_cause_chain.rb +20 -0
- data/sentry-ruby/lib/sentry/version.rb +3 -0
- data/sentry-ruby/sentry-ruby.gemspec +26 -0
- data/sentry-ruby/spec/sentry/backtrace_spec.rb +38 -0
- data/sentry-ruby/spec/sentry/client_spec.rb +443 -0
- data/sentry-ruby/spec/sentry/configuration_spec.rb +400 -0
- data/sentry-ruby/spec/sentry/event_spec.rb +238 -0
- data/sentry-ruby/spec/sentry/interface_spec.rb +38 -0
- data/sentry-ruby/spec/sentry/interfaces/stack_trace_spec.rb +11 -0
- data/sentry-ruby/spec/sentry/linecache_spec.rb +40 -0
- data/sentry-ruby/spec/sentry/transports/http_spec.rb +57 -0
- data/sentry-ruby/spec/sentry/transports/stdout_spec.rb +11 -0
- data/sentry-ruby/spec/sentry_spec.rb +9 -0
- data/sentry-ruby/spec/spec_helper.rb +49 -0
- data/sentry-ruby/spec/support/linecache.txt +6 -0
- metadata +152 -4
- data/lib/raven/breadcrumbs/activesupport.rb +0 -19
@@ -0,0 +1,209 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'socket'
|
4
|
+
require 'securerandom'
|
5
|
+
require 'sentry/interface'
|
6
|
+
require 'sentry/backtrace'
|
7
|
+
require 'sentry/utils/deep_merge'
|
8
|
+
|
9
|
+
module Sentry
|
10
|
+
class Event
|
11
|
+
# See Sentry server default limits at
|
12
|
+
# https://github.com/getsentry/sentry/blob/master/src/sentry/conf/server.py
|
13
|
+
MAX_MESSAGE_SIZE_IN_BYTES = 1024 * 8
|
14
|
+
REQUIRED_OPTION_KEYS = [:configuration].freeze
|
15
|
+
|
16
|
+
SDK = { "name" => "sentry-ruby", "version" => Sentry::VERSION }.freeze
|
17
|
+
|
18
|
+
attr_accessor :id, :logger, :transaction, :server_name, :release, :modules,
|
19
|
+
:extra, :tags, :context, :configuration, :checksum,
|
20
|
+
:fingerprint, :environment, :server_os, :runtime,
|
21
|
+
:breadcrumbs, :user, :backtrace, :platform, :sdk
|
22
|
+
alias event_id id
|
23
|
+
|
24
|
+
attr_reader :level, :timestamp, :time_spent
|
25
|
+
|
26
|
+
def initialize(
|
27
|
+
configuration:,
|
28
|
+
message: nil,
|
29
|
+
user: {}, extra: {}, tags: {},
|
30
|
+
backtrace: [], level: :error, checksum: nil, fingerprint: [],
|
31
|
+
server_name: nil, release: nil, environment: nil
|
32
|
+
)
|
33
|
+
# this needs to go first because some setters rely on configuration
|
34
|
+
self.configuration = configuration
|
35
|
+
|
36
|
+
# Set some simple default values
|
37
|
+
self.id = SecureRandom.uuid.delete("-")
|
38
|
+
self.timestamp = Time.now.utc
|
39
|
+
self.level = level
|
40
|
+
self.platform = :ruby
|
41
|
+
self.sdk = SDK
|
42
|
+
|
43
|
+
# Set some attributes with empty hashes to allow merging
|
44
|
+
@interfaces = {}
|
45
|
+
|
46
|
+
self.user = user || {}
|
47
|
+
self.extra = extra || {}
|
48
|
+
self.tags = configuration.tags.merge(tags || {})
|
49
|
+
|
50
|
+
self.message = message
|
51
|
+
self.server_os = {} # TODO: contexts
|
52
|
+
self.runtime = {} # TODO: contexts
|
53
|
+
|
54
|
+
self.checksum = checksum
|
55
|
+
self.fingerprint = fingerprint
|
56
|
+
|
57
|
+
self.server_name = server_name
|
58
|
+
self.environment = environment
|
59
|
+
self.release = release
|
60
|
+
|
61
|
+
# Allow attributes to be set on the event at initialization
|
62
|
+
yield self if block_given?
|
63
|
+
# options.each_pair { |key, val| public_send("#{key}=", val) unless val.nil? }
|
64
|
+
|
65
|
+
if !backtrace.empty?
|
66
|
+
interface(:stacktrace) do |int|
|
67
|
+
int.frames = stacktrace_interface_from(backtrace)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
set_core_attributes_from_configuration
|
72
|
+
end
|
73
|
+
|
74
|
+
def message
|
75
|
+
@interfaces[:logentry]&.unformatted_message
|
76
|
+
end
|
77
|
+
|
78
|
+
def message=(message)
|
79
|
+
unless message.is_a?(String)
|
80
|
+
configuration.logger.debug("You're passing a non-string message")
|
81
|
+
message = message.to_s
|
82
|
+
end
|
83
|
+
|
84
|
+
interface(:message) do |int|
|
85
|
+
int.message = message.byteslice(0...MAX_MESSAGE_SIZE_IN_BYTES) # Messages limited to 10kb
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def timestamp=(time)
|
90
|
+
@timestamp = time.is_a?(Time) ? time.strftime('%Y-%m-%dT%H:%M:%S') : time
|
91
|
+
end
|
92
|
+
|
93
|
+
def time_spent=(time)
|
94
|
+
@time_spent = time.is_a?(Float) ? (time * 1000).to_i : time
|
95
|
+
end
|
96
|
+
|
97
|
+
def level=(new_level) # needed to meet the Sentry spec
|
98
|
+
@level = new_level.to_s == "warn" ? :warning : new_level
|
99
|
+
end
|
100
|
+
|
101
|
+
def interface(name, value = nil, &block)
|
102
|
+
int = Interface.registered[name]
|
103
|
+
raise(Error, "Unknown interface: #{name}") unless int
|
104
|
+
|
105
|
+
@interfaces[int.sentry_alias] = int.new(value, &block) if value || block
|
106
|
+
@interfaces[int.sentry_alias]
|
107
|
+
end
|
108
|
+
|
109
|
+
def [](key)
|
110
|
+
interface(key)
|
111
|
+
end
|
112
|
+
|
113
|
+
def []=(key, value)
|
114
|
+
interface(key, value)
|
115
|
+
end
|
116
|
+
|
117
|
+
def to_hash
|
118
|
+
data = [:checksum, :environment, :event_id, :extra, :fingerprint, :level,
|
119
|
+
:logger, :message, :modules, :platform, :release, :sdk, :server_name,
|
120
|
+
:tags, :time_spent, :timestamp, :transaction, :user].each_with_object({}) do |att, memo|
|
121
|
+
memo[att] = public_send(att) if public_send(att)
|
122
|
+
end
|
123
|
+
|
124
|
+
# TODO-v4: Fix this
|
125
|
+
# data[:breadcrumbs] = @breadcrumbs.to_hash unless @breadcrumbs.empty?
|
126
|
+
|
127
|
+
@interfaces.each_pair do |name, int_data|
|
128
|
+
data[name.to_sym] = int_data.to_hash
|
129
|
+
end
|
130
|
+
data
|
131
|
+
end
|
132
|
+
|
133
|
+
def to_json_compatible
|
134
|
+
JSON.parse(JSON.generate(to_hash))
|
135
|
+
end
|
136
|
+
|
137
|
+
def add_exception_interface(exc)
|
138
|
+
interface(:exception) do |exc_int|
|
139
|
+
exceptions = Sentry::Utils::ExceptionCauseChain.exception_to_array(exc).reverse
|
140
|
+
backtraces = Set.new
|
141
|
+
exc_int.values = exceptions.map do |e|
|
142
|
+
SingleExceptionInterface.new do |int|
|
143
|
+
int.type = e.class.to_s
|
144
|
+
int.value = e.to_s
|
145
|
+
int.module = e.class.to_s.split('::')[0...-1].join('::')
|
146
|
+
|
147
|
+
int.stacktrace =
|
148
|
+
if e.backtrace && !backtraces.include?(e.backtrace.object_id)
|
149
|
+
backtraces << e.backtrace.object_id
|
150
|
+
StacktraceInterface.new do |stacktrace|
|
151
|
+
stacktrace.frames = stacktrace_interface_from(e.backtrace)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def stacktrace_interface_from(backtrace)
|
160
|
+
Backtrace.parse(backtrace, configuration: configuration).lines.reverse.each_with_object([]) do |line, memo|
|
161
|
+
frame = StacktraceInterface::Frame.new(configuration: configuration)
|
162
|
+
frame.abs_path = line.file if line.file
|
163
|
+
frame.function = line.method if line.method
|
164
|
+
frame.lineno = line.number
|
165
|
+
frame.in_app = line.in_app
|
166
|
+
frame.module = line.module_name if line.module_name
|
167
|
+
|
168
|
+
if configuration[:context_lines] && frame.abs_path
|
169
|
+
frame.pre_context, frame.context_line, frame.post_context = \
|
170
|
+
configuration.linecache.get_file_context(frame.abs_path, frame.lineno, configuration[:context_lines])
|
171
|
+
end
|
172
|
+
|
173
|
+
memo << frame if frame.filename
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
private
|
178
|
+
|
179
|
+
def set_core_attributes_from_configuration
|
180
|
+
self.server_name ||= configuration.server_name
|
181
|
+
self.release ||= configuration.release
|
182
|
+
self.modules = list_gem_specs if configuration.send_modules
|
183
|
+
self.environment ||= configuration.current_environment
|
184
|
+
end
|
185
|
+
|
186
|
+
def add_rack_context
|
187
|
+
interface :http do |int|
|
188
|
+
int.from_rack(context.rack_env)
|
189
|
+
end
|
190
|
+
context.user[:ip_address] = calculate_real_ip_from_rack
|
191
|
+
end
|
192
|
+
|
193
|
+
# When behind a proxy (or if the user is using a proxy), we can't use
|
194
|
+
# REMOTE_ADDR to determine the Event IP, and must use other headers instead.
|
195
|
+
def calculate_real_ip_from_rack
|
196
|
+
Utils::RealIp.new(
|
197
|
+
:remote_addr => context.rack_env["REMOTE_ADDR"],
|
198
|
+
:client_ip => context.rack_env["HTTP_CLIENT_IP"],
|
199
|
+
:real_ip => context.rack_env["HTTP_X_REAL_IP"],
|
200
|
+
:forwarded_for => context.rack_env["HTTP_X_FORWARDED_FOR"]
|
201
|
+
).calculate_ip
|
202
|
+
end
|
203
|
+
|
204
|
+
def list_gem_specs
|
205
|
+
# Older versions of Rubygems don't support iterating over all specs
|
206
|
+
Hash[Gem::Specification.map { |spec| [spec.name, spec.version.to_s] }] if Gem::Specification.respond_to?(:map)
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Sentry
|
2
|
+
class Interface
|
3
|
+
def initialize(attributes = nil)
|
4
|
+
attributes&.each do |attr, value|
|
5
|
+
public_send "#{attr}=", value
|
6
|
+
end
|
7
|
+
|
8
|
+
yield self if block_given?
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.inherited(klass)
|
12
|
+
name = klass.name.split("::").last.downcase.gsub("interface", "")
|
13
|
+
registered[name.to_sym] = klass
|
14
|
+
super
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.registered
|
18
|
+
@@registered ||= {} # rubocop:disable Style/ClassVars
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_hash
|
22
|
+
Hash[instance_variables.map { |name| [name[1..-1].to_sym, instance_variable_get(name)] }]
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
require "sentry/interfaces/exception"
|
28
|
+
require "sentry/interfaces/http"
|
29
|
+
require "sentry/interfaces/message"
|
30
|
+
require "sentry/interfaces/single_exception"
|
31
|
+
require "sentry/interfaces/stack_trace"
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Sentry
|
2
|
+
class ExceptionInterface < Interface
|
3
|
+
attr_accessor :values
|
4
|
+
|
5
|
+
def self.sentry_alias
|
6
|
+
:exception
|
7
|
+
end
|
8
|
+
|
9
|
+
def to_hash(*args)
|
10
|
+
data = super(*args)
|
11
|
+
data[:values] = data[:values].map(&:to_hash) if data[:values]
|
12
|
+
data
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Sentry
|
2
|
+
class HttpInterface < Interface
|
3
|
+
attr_accessor :url, :method, :data, :query_string, :cookies, :headers, :env
|
4
|
+
|
5
|
+
def initialize(*arguments)
|
6
|
+
self.headers = {}
|
7
|
+
self.env = {}
|
8
|
+
self.cookies = nil
|
9
|
+
super(*arguments)
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.sentry_alias
|
13
|
+
:request
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Sentry
|
2
|
+
class MessageInterface < Interface
|
3
|
+
attr_accessor :message, :params
|
4
|
+
|
5
|
+
def initialize(*arguments)
|
6
|
+
self.params = []
|
7
|
+
super(*arguments)
|
8
|
+
end
|
9
|
+
|
10
|
+
def unformatted_message
|
11
|
+
Array(params).empty? ? message : message % params
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.sentry_alias
|
15
|
+
:logentry
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Sentry
|
2
|
+
class SingleExceptionInterface < Interface
|
3
|
+
attr_accessor :type
|
4
|
+
attr_accessor :value
|
5
|
+
attr_accessor :module
|
6
|
+
attr_accessor :stacktrace
|
7
|
+
|
8
|
+
def to_hash(*args)
|
9
|
+
data = super(*args)
|
10
|
+
data[:stacktrace] = data[:stacktrace].to_hash if data[:stacktrace]
|
11
|
+
data
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module Sentry
|
2
|
+
class StacktraceInterface < Interface
|
3
|
+
attr_accessor :frames
|
4
|
+
|
5
|
+
def initialize(*arguments)
|
6
|
+
super(*arguments)
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.sentry_alias
|
10
|
+
:stacktrace
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_hash(*args)
|
14
|
+
data = super(*args)
|
15
|
+
data[:frames] = data[:frames].map(&:to_hash)
|
16
|
+
data
|
17
|
+
end
|
18
|
+
|
19
|
+
# Not actually an interface, but I want to use the same style
|
20
|
+
class Frame < Interface
|
21
|
+
attr_accessor :abs_path, :context_line, :function, :in_app,
|
22
|
+
:lineno, :module, :pre_context, :post_context, :vars, :configuration
|
23
|
+
|
24
|
+
def initialize(*arguments)
|
25
|
+
super(*arguments)
|
26
|
+
end
|
27
|
+
|
28
|
+
def filename
|
29
|
+
return if abs_path.nil?
|
30
|
+
return @filename if instance_variable_defined?(:@filename)
|
31
|
+
|
32
|
+
prefix =
|
33
|
+
if under_project_root? && in_app
|
34
|
+
project_root
|
35
|
+
elsif under_project_root?
|
36
|
+
longest_load_path || project_root
|
37
|
+
else
|
38
|
+
longest_load_path
|
39
|
+
end
|
40
|
+
|
41
|
+
@filename = prefix ? abs_path[prefix.to_s.chomp(File::SEPARATOR).length + 1..-1] : abs_path
|
42
|
+
end
|
43
|
+
|
44
|
+
def to_hash(*args)
|
45
|
+
data = super(*args)
|
46
|
+
data[:filename] = filename
|
47
|
+
data.delete(:vars) unless vars && !vars.empty?
|
48
|
+
data.delete(:pre_context) unless pre_context && !pre_context.empty?
|
49
|
+
data.delete(:post_context) unless post_context && !post_context.empty?
|
50
|
+
data.delete(:context_line) unless context_line && !context_line.empty?
|
51
|
+
data
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def under_project_root?
|
57
|
+
project_root && abs_path.start_with?(project_root)
|
58
|
+
end
|
59
|
+
|
60
|
+
def project_root
|
61
|
+
@project_root ||= configuration.project_root&.to_s
|
62
|
+
end
|
63
|
+
|
64
|
+
def longest_load_path
|
65
|
+
$LOAD_PATH.select { |path| abs_path.start_with?(path.to_s) }.max_by(&:size)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Sentry
|
2
|
+
class LineCache
|
3
|
+
def initialize
|
4
|
+
@cache = {}
|
5
|
+
end
|
6
|
+
|
7
|
+
# Any linecache you provide to Sentry must implement this method.
|
8
|
+
# Returns an Array of Strings representing the lines in the source
|
9
|
+
# file. The number of lines retrieved is (2 * context) + 1, the middle
|
10
|
+
# line should be the line requested by lineno. See specs for more information.
|
11
|
+
def get_file_context(filename, lineno, context)
|
12
|
+
return nil, nil, nil unless valid_path?(filename)
|
13
|
+
|
14
|
+
lines = Array.new(2 * context + 1) do |i|
|
15
|
+
getline(filename, lineno - context + i)
|
16
|
+
end
|
17
|
+
[lines[0..(context - 1)], lines[context], lines[(context + 1)..-1]]
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def valid_path?(path)
|
23
|
+
lines = getlines(path)
|
24
|
+
!lines.nil?
|
25
|
+
end
|
26
|
+
|
27
|
+
def getlines(path)
|
28
|
+
@cache[path] ||= begin
|
29
|
+
IO.readlines(path)
|
30
|
+
rescue
|
31
|
+
nil
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def getline(path, n)
|
36
|
+
return nil if n < 1
|
37
|
+
|
38
|
+
lines = getlines(path)
|
39
|
+
return nil if lines.nil?
|
40
|
+
|
41
|
+
lines[n - 1]
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'logger'
|
4
|
+
|
5
|
+
module Sentry
|
6
|
+
class Logger < ::Logger
|
7
|
+
LOG_PREFIX = "** [Sentry] "
|
8
|
+
PROGNAME = "sentry"
|
9
|
+
|
10
|
+
def initialize(*)
|
11
|
+
super
|
12
|
+
@level = ::Logger::INFO
|
13
|
+
original_formatter = ::Logger::Formatter.new
|
14
|
+
@default_formatter = proc do |severity, datetime, _progname, msg|
|
15
|
+
msg = "#{LOG_PREFIX}#{msg}"
|
16
|
+
original_formatter.call(severity, datetime, PROGNAME, msg)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|