sentry-ruby 0.3.0 → 4.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +102 -14
  3. metadata +41 -54
  4. data/.craft.yml +0 -19
  5. data/.gitignore +0 -11
  6. data/.rspec +0 -3
  7. data/.travis.yml +0 -6
  8. data/CHANGELOG.md +0 -31
  9. data/CODE_OF_CONDUCT.md +0 -74
  10. data/Gemfile +0 -16
  11. data/Rakefile +0 -8
  12. data/bin/console +0 -14
  13. data/bin/setup +0 -8
  14. data/lib/sentry/backtrace.rb +0 -128
  15. data/lib/sentry/benchmarks/benchmark_transport.rb +0 -14
  16. data/lib/sentry/breadcrumb/sentry_logger.rb +0 -87
  17. data/lib/sentry/breadcrumb.rb +0 -25
  18. data/lib/sentry/breadcrumb_buffer.rb +0 -47
  19. data/lib/sentry/client.rb +0 -80
  20. data/lib/sentry/configuration.rb +0 -387
  21. data/lib/sentry/core_ext/object/deep_dup.rb +0 -57
  22. data/lib/sentry/core_ext/object/duplicable.rb +0 -153
  23. data/lib/sentry/dsn.rb +0 -48
  24. data/lib/sentry/event.rb +0 -177
  25. data/lib/sentry/hub.rb +0 -137
  26. data/lib/sentry/interface.rb +0 -22
  27. data/lib/sentry/interfaces/exception.rb +0 -11
  28. data/lib/sentry/interfaces/request.rb +0 -95
  29. data/lib/sentry/interfaces/single_exception.rb +0 -14
  30. data/lib/sentry/interfaces/stacktrace.rb +0 -57
  31. data/lib/sentry/linecache.rb +0 -44
  32. data/lib/sentry/logger.rb +0 -20
  33. data/lib/sentry/rack/capture_exception.rb +0 -45
  34. data/lib/sentry/rack/tracing.rb +0 -39
  35. data/lib/sentry/rack.rb +0 -5
  36. data/lib/sentry/scope.rb +0 -214
  37. data/lib/sentry/span.rb +0 -155
  38. data/lib/sentry/transaction.rb +0 -113
  39. data/lib/sentry/transaction_event.rb +0 -29
  40. data/lib/sentry/transport/configuration.rb +0 -21
  41. data/lib/sentry/transport/dummy_transport.rb +0 -14
  42. data/lib/sentry/transport/http_transport.rb +0 -65
  43. data/lib/sentry/transport/state.rb +0 -40
  44. data/lib/sentry/transport.rb +0 -97
  45. data/lib/sentry/utils/exception_cause_chain.rb +0 -20
  46. data/lib/sentry/utils/real_ip.rb +0 -70
  47. data/lib/sentry/utils/request_id.rb +0 -16
  48. data/lib/sentry/version.rb +0 -3
  49. data/lib/sentry-ruby.rb +0 -123
  50. data/sentry-ruby.gemspec +0 -26
@@ -1,57 +0,0 @@
1
- module Sentry
2
- class StacktraceInterface < Interface
3
- attr_accessor :frames
4
-
5
- def to_hash
6
- data = super
7
- data[:frames] = data[:frames].map(&:to_hash)
8
- data
9
- end
10
-
11
- # Not actually an interface, but I want to use the same style
12
- class Frame < Interface
13
- attr_accessor :abs_path, :context_line, :function, :in_app,
14
- :lineno, :module, :pre_context, :post_context, :vars
15
-
16
- def initialize(project_root)
17
- @project_root = project_root
18
- end
19
-
20
- def filename
21
- return if abs_path.nil?
22
- return @filename if instance_variable_defined?(:@filename)
23
-
24
- prefix =
25
- if under_project_root? && in_app
26
- @project_root
27
- elsif under_project_root?
28
- longest_load_path || @project_root
29
- else
30
- longest_load_path
31
- end
32
-
33
- @filename = prefix ? abs_path[prefix.to_s.chomp(File::SEPARATOR).length + 1..-1] : abs_path
34
- end
35
-
36
- def to_hash(*args)
37
- data = super(*args)
38
- data[:filename] = filename
39
- data.delete(:vars) unless vars && !vars.empty?
40
- data.delete(:pre_context) unless pre_context && !pre_context.empty?
41
- data.delete(:post_context) unless post_context && !post_context.empty?
42
- data.delete(:context_line) unless context_line && !context_line.empty?
43
- data
44
- end
45
-
46
- private
47
-
48
- def under_project_root?
49
- @project_root && abs_path.start_with?(@project_root)
50
- end
51
-
52
- def longest_load_path
53
- $LOAD_PATH.select { |path| abs_path.start_with?(path.to_s) }.max_by(&:size)
54
- end
55
- end
56
- end
57
- end
@@ -1,44 +0,0 @@
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
data/lib/sentry/logger.rb DELETED
@@ -1,20 +0,0 @@
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
@@ -1,45 +0,0 @@
1
- module Sentry
2
- module Rack
3
- class CaptureException
4
- def initialize(app)
5
- @app = app
6
- end
7
-
8
- def call(env)
9
- # this call clones the main (global) hub
10
- # and assigns it to the current thread's Sentry#get_current_hub
11
- # it's essential for multi-thread servers (e.g. puma)
12
- Sentry.clone_hub_to_current_thread unless Sentry.get_current_hub
13
- # this call creates an isolated scope for every request
14
- # it's essential for multi-process servers (e.g. unicorn)
15
- Sentry.with_scope do |scope|
16
- # there could be some breadcrumbs already stored in the top-level scope
17
- # and for request information, we don't need those breadcrumbs
18
- scope.clear_breadcrumbs
19
- env['sentry.client'] = Sentry.get_current_client
20
-
21
- scope.set_transaction_name(env["PATH_INFO"]) if env["PATH_INFO"]
22
- scope.set_rack_env(env)
23
-
24
- begin
25
- response = @app.call(env)
26
- rescue Sentry::Error
27
- raise # Don't capture Sentry errors
28
- rescue Exception => e
29
- Sentry.capture_exception(e)
30
- raise
31
- end
32
-
33
- exception = collect_exception(env)
34
- Sentry.capture_exception(exception) if exception
35
-
36
- response
37
- end
38
- end
39
-
40
- def collect_exception(env)
41
- env['rack.exception'] || env['sinatra.error']
42
- end
43
- end
44
- end
45
- end
@@ -1,39 +0,0 @@
1
- module Sentry
2
- module Rack
3
- class Tracing
4
- def initialize(app)
5
- @app = app
6
- end
7
-
8
- def call(env)
9
- Sentry.clone_hub_to_current_thread unless Sentry.get_current_hub
10
-
11
- if Sentry.configuration.traces_sample_rate.to_f == 0.0
12
- return @app.call(env)
13
- end
14
-
15
- Sentry.with_scope do |scope|
16
- scope.clear_breadcrumbs
17
- scope.set_transaction_name(env["PATH_INFO"]) if env["PATH_INFO"]
18
- span = Sentry.start_transaction(name: scope.transaction_name, op: "rack.request")
19
- scope.set_span(span)
20
-
21
- begin
22
- response = @app.call(env)
23
- rescue
24
- finish_span(span, 500)
25
- raise
26
- end
27
-
28
- finish_span(span, response[0])
29
- response
30
- end
31
- end
32
-
33
- def finish_span(span, status_code)
34
- span.set_http_status(status_code)
35
- span.finish
36
- end
37
- end
38
- end
39
- end
data/lib/sentry/rack.rb DELETED
@@ -1,5 +0,0 @@
1
- require 'time'
2
- require 'rack'
3
-
4
- require 'sentry/rack/capture_exception'
5
- require 'sentry/rack/tracing'
data/lib/sentry/scope.rb DELETED
@@ -1,214 +0,0 @@
1
- require "sentry/breadcrumb_buffer"
2
- require "etc"
3
-
4
- module Sentry
5
- class Scope
6
- ATTRIBUTES = [:transaction_names, :contexts, :extra, :tags, :user, :level, :breadcrumbs, :fingerprint, :event_processors, :rack_env, :span]
7
-
8
- attr_reader(*ATTRIBUTES)
9
-
10
- def initialize
11
- set_default_value
12
- end
13
-
14
- def clear
15
- set_default_value
16
- end
17
-
18
- def apply_to_event(event, hint = nil)
19
- event.tags = tags.merge(event.tags)
20
- event.user = user.merge(event.user)
21
- event.extra = extra.merge(event.extra)
22
- event.contexts = contexts.merge(event.contexts)
23
-
24
- if span
25
- event.contexts[:trace] = span.get_trace_context
26
- end
27
-
28
- event.fingerprint = fingerprint
29
- event.level = level
30
- event.transaction = transaction_names.last
31
- event.breadcrumbs = breadcrumbs
32
- event.rack_env = rack_env
33
-
34
- unless @event_processors.empty?
35
- @event_processors.each do |processor_block|
36
- event = processor_block.call(event, hint)
37
- end
38
- end
39
-
40
- event
41
- end
42
-
43
- def add_breadcrumb(breadcrumb)
44
- breadcrumbs.record(breadcrumb)
45
- end
46
-
47
- def clear_breadcrumbs
48
- @breadcrumbs = BreadcrumbBuffer.new
49
- end
50
-
51
- def dup
52
- copy = super
53
- copy.breadcrumbs = breadcrumbs.dup
54
- copy.contexts = contexts.deep_dup
55
- copy.extra = extra.deep_dup
56
- copy.tags = tags.deep_dup
57
- copy.user = user.deep_dup
58
- copy.transaction_names = transaction_names.deep_dup
59
- copy.fingerprint = fingerprint.deep_dup
60
- copy.span = span
61
- copy
62
- end
63
-
64
- def update_from_scope(scope)
65
- self.breadcrumbs = scope.breadcrumbs
66
- self.contexts = scope.contexts
67
- self.extra = scope.extra
68
- self.tags = scope.tags
69
- self.user = scope.user
70
- self.transaction_names = scope.transaction_names
71
- self.fingerprint = scope.fingerprint
72
- self.span = scope.span
73
- end
74
-
75
- def update_from_options(
76
- contexts: nil,
77
- extra: nil,
78
- tags: nil,
79
- user: nil,
80
- level: nil,
81
- fingerprint: nil
82
- )
83
- self.contexts.merge!(contexts) if contexts
84
- self.extra.merge!(extra) if extra
85
- self.tags.merge!(tags) if tags
86
- self.user = user if user
87
- self.level = level if level
88
- self.fingerprint = fingerprint if fingerprint
89
- end
90
-
91
- def set_rack_env(env)
92
- env = env || {}
93
- @rack_env = env
94
- end
95
-
96
- def set_span(span)
97
- check_argument_type!(span, Span)
98
- @span = span
99
- end
100
-
101
- def set_user(user_hash)
102
- check_argument_type!(user_hash, Hash)
103
- @user = user_hash
104
- end
105
-
106
- def set_extras(extras_hash)
107
- check_argument_type!(extras_hash, Hash)
108
- @extra.merge!(extras_hash)
109
- end
110
-
111
- def set_extra(key, value)
112
- @extra.merge!(key => value)
113
- end
114
-
115
- def set_tags(tags_hash)
116
- check_argument_type!(tags_hash, Hash)
117
- @tags.merge!(tags_hash)
118
- end
119
-
120
- def set_tag(key, value)
121
- @tags.merge!(key => value)
122
- end
123
-
124
- def set_contexts(contexts_hash)
125
- check_argument_type!(contexts_hash, Hash)
126
- @contexts = contexts_hash
127
- end
128
-
129
- def set_context(key, value)
130
- @contexts.merge!(key => value)
131
- end
132
-
133
- def set_level(level)
134
- @level = level
135
- end
136
-
137
- def set_transaction_name(transaction_name)
138
- @transaction_names << transaction_name
139
- end
140
-
141
- def transaction_name
142
- @transaction_names.last
143
- end
144
-
145
- def get_transaction
146
- # transaction will always be the first in the span_recorder
147
- span.span_recorder.spans.first if span
148
- end
149
-
150
- def get_span
151
- span
152
- end
153
-
154
- def set_fingerprint(fingerprint)
155
- check_argument_type!(fingerprint, Array)
156
-
157
- @fingerprint = fingerprint
158
- end
159
-
160
- def add_event_processor(&block)
161
- @event_processors << block
162
- end
163
-
164
- protected
165
-
166
- # for duplicating scopes internally
167
- attr_writer(*ATTRIBUTES)
168
-
169
- private
170
-
171
- def check_argument_type!(argument, expected_type)
172
- unless argument.is_a?(expected_type)
173
- raise ArgumentError, "expect the argument to be a #{expected_type}, got #{argument.class} (#{argument})"
174
- end
175
- end
176
-
177
- def set_default_value
178
- @breadcrumbs = BreadcrumbBuffer.new
179
- @contexts = { :os => self.class.os_context, :runtime => self.class.runtime_context }
180
- @extra = {}
181
- @tags = {}
182
- @user = {}
183
- @level = :error
184
- @fingerprint = []
185
- @transaction_names = []
186
- @event_processors = []
187
- @rack_env = {}
188
- @span = nil
189
- end
190
-
191
- class << self
192
- def os_context
193
- @os_context ||=
194
- begin
195
- uname = Etc.uname
196
- {
197
- name: uname[:sysname] || RbConfig::CONFIG["host_os"],
198
- version: uname[:version],
199
- build: uname[:release],
200
- kernel_version: uname[:version]
201
- }
202
- end
203
- end
204
-
205
- def runtime_context
206
- @runtime_context ||= {
207
- name: RbConfig::CONFIG["ruby_install_name"],
208
- version: RUBY_DESCRIPTION || Sentry.sys_command("ruby -v")
209
- }
210
- end
211
- end
212
-
213
- end
214
- end
data/lib/sentry/span.rb DELETED
@@ -1,155 +0,0 @@
1
- # frozen_string_literal: true
2
- require "securerandom"
3
-
4
- module Sentry
5
- class Span
6
- STATUS_MAP = {
7
- 400 => "invalid_argument",
8
- 401 => "unauthenticated",
9
- 403 => "permission_denied",
10
- 404 => "not_found",
11
- 409 => "already_exists",
12
- 429 => "resource_exhausted",
13
- 499 => "cancelled",
14
- 500 => "internal_error",
15
- 501 => "unimplemented",
16
- 503 => "unavailable",
17
- 504 => "deadline_exceeded"
18
- }
19
-
20
-
21
- attr_reader :trace_id, :span_id, :parent_span_id, :sampled, :start_timestamp, :timestamp, :description, :op, :status, :tags, :data
22
- attr_accessor :span_recorder
23
-
24
- def initialize(description: nil, op: nil, status: nil, trace_id: nil, parent_span_id: nil, sampled: nil, start_timestamp: nil, timestamp: nil)
25
- @trace_id = trace_id || SecureRandom.uuid.delete("-")
26
- @span_id = SecureRandom.hex(8)
27
- @parent_span_id = parent_span_id
28
- @sampled = sampled
29
- @start_timestamp = start_timestamp || Sentry.utc_now.to_f
30
- @timestamp = timestamp
31
- @description = description
32
- @op = op
33
- @status = status
34
- @data = {}
35
- @tags = {}
36
- end
37
-
38
- def set_span_recorder
39
- @span_recorder = SpanRecorder.new(1000)
40
- @span_recorder.add(self)
41
- end
42
-
43
- def finish
44
- # already finished
45
- return if @timestamp
46
-
47
- @timestamp = Sentry.utc_now.to_f
48
- self
49
- end
50
-
51
- def to_sentry_trace
52
- sampled_flag = ""
53
- sampled_flag = @sampled ? 1 : 0 unless @sampled.nil?
54
-
55
- "#{@trace_id}-#{@span_id}-#{sampled_flag}"
56
- end
57
-
58
- def to_hash
59
- {
60
- trace_id: @trace_id,
61
- span_id: @span_id,
62
- parent_span_id: @parent_span_id,
63
- start_timestamp: @start_timestamp,
64
- timestamp: @timestamp,
65
- description: @description,
66
- op: @op,
67
- status: @status,
68
- tags: @tags,
69
- data: @data
70
- }
71
- end
72
-
73
- def get_trace_context
74
- {
75
- trace_id: @trace_id,
76
- span_id: @span_id,
77
- description: @description,
78
- op: @op,
79
- status: @status
80
- }
81
- end
82
-
83
- def start_child(**options)
84
- options = options.dup.merge(trace_id: @trace_id, parent_span_id: @span_id, sampled: @sampled)
85
- child_span = Span.new(options)
86
- child_span.span_recorder = @span_recorder
87
-
88
- if @span_recorder && @sampled
89
- @span_recorder.add(child_span)
90
- end
91
-
92
- child_span
93
- end
94
-
95
- def with_child_span(**options, &block)
96
- child_span = start_child(**options)
97
-
98
- yield(child_span)
99
-
100
- child_span.finish
101
- end
102
-
103
- def set_op(op)
104
- @op = op
105
- end
106
-
107
- def set_description(description)
108
- @description = description
109
- end
110
-
111
- def set_status(status)
112
- @status = status
113
- end
114
-
115
- def set_timestamp(timestamp)
116
- @timestamp = timestamp
117
- end
118
-
119
- def set_http_status(status_code)
120
- status_code = status_code.to_i
121
- set_data("status_code", status_code)
122
-
123
- status =
124
- if status_code >= 200 && status_code < 299
125
- "ok"
126
- else
127
- STATUS_MAP[status_code]
128
- end
129
- set_status(status)
130
- end
131
-
132
- def set_data(key, value)
133
- @data[key] = value
134
- end
135
-
136
- def set_tag(key, value)
137
- @tags[key] = value
138
- end
139
-
140
- class SpanRecorder
141
- attr_reader :max_length, :spans
142
-
143
- def initialize(max_length)
144
- @max_length = max_length
145
- @spans = []
146
- end
147
-
148
- def add(span)
149
- if @spans.count < @max_length
150
- @spans << span
151
- end
152
- end
153
- end
154
- end
155
- end
@@ -1,113 +0,0 @@
1
- module Sentry
2
- class Transaction < Span
3
- SENTRY_TRACE_REGEXP = Regexp.new(
4
- "^[ \t]*" + # whitespace
5
- "([0-9a-f]{32})?" + # trace_id
6
- "-?([0-9a-f]{16})?" + # span_id
7
- "-?([01])?" + # sampled
8
- "[ \t]*$" # whitespace
9
- )
10
- UNLABELD_NAME = "<unlabeled transaction>".freeze
11
- MESSAGE_PREFIX = "[Tracing]"
12
-
13
- attr_reader :name, :parent_sampled
14
-
15
- def initialize(name: nil, parent_sampled: nil, **options)
16
- super(**options)
17
-
18
- @name = name
19
- @parent_sampled = parent_sampled
20
- set_span_recorder
21
- end
22
-
23
- def self.from_sentry_trace(sentry_trace, **options)
24
- return unless sentry_trace
25
-
26
- match = SENTRY_TRACE_REGEXP.match(sentry_trace)
27
- trace_id, parent_span_id, sampled_flag = match[1..3]
28
-
29
- sampled = sampled_flag != "0"
30
-
31
- new(trace_id: trace_id, parent_span_id: parent_span_id, parent_sampled: sampled, **options)
32
- end
33
-
34
- def to_hash
35
- hash = super
36
- hash.merge!(name: @name, sampled: @sampled, parent_sampled: @parent_sampled)
37
- hash
38
- end
39
-
40
- def set_initial_sample_desicion(sampling_context = {})
41
- unless Sentry.configuration.tracing_enabled?
42
- @sampled = false
43
- return
44
- end
45
-
46
- return unless @sampled.nil?
47
-
48
- transaction_description = generate_transaction_description
49
-
50
- logger = Sentry.configuration.logger
51
- sample_rate = Sentry.configuration.traces_sample_rate
52
- traces_sampler = Sentry.configuration.traces_sampler
53
-
54
- if traces_sampler.is_a?(Proc)
55
- sampling_context = sampling_context.merge(
56
- parent_sampled: @parent_sampled,
57
- transaction_context: self.to_hash
58
- )
59
-
60
- sample_rate = traces_sampler.call(sampling_context)
61
- end
62
-
63
- unless [true, false].include?(sample_rate) || (sample_rate.is_a?(Float) && sample_rate >= 0.0 && sample_rate <= 1.0)
64
- @sampled = false
65
- logger.warn("#{MESSAGE_PREFIX} Discarding #{transaction_description} because of invalid sample_rate: #{sample_rate}")
66
- return
67
- end
68
-
69
- if sample_rate == 0.0 || sample_rate == false
70
- @sampled = false
71
- logger.debug("#{MESSAGE_PREFIX} Discarding #{transaction_description} because traces_sampler returned 0 or false")
72
- return
73
- end
74
-
75
- if sample_rate == true
76
- @sampled = true
77
- else
78
- @sampled = Random.rand < sample_rate
79
- end
80
-
81
- if @sampled
82
- logger.debug("#{MESSAGE_PREFIX} Starting #{transaction_description}")
83
- else
84
- logger.debug(
85
- "#{MESSAGE_PREFIX} Discarding #{transaction_description} because it's not included in the random sample (sampling rate = #{sample_rate})"
86
- )
87
- end
88
- end
89
-
90
- def finish(hub: nil)
91
- super() # Span#finish doesn't take arguments
92
-
93
- if @name.nil?
94
- @name = UNLABELD_NAME
95
- end
96
-
97
- return unless @sampled
98
-
99
- hub ||= Sentry.get_current_hub
100
- event = hub.current_client.event_from_transaction(self)
101
- hub.capture_event(event)
102
- end
103
-
104
- private
105
-
106
- def generate_transaction_description
107
- result = op.nil? ? "" : "<#{@op}> "
108
- result += "transaction"
109
- result += " <#{@name}>" if @name
110
- result
111
- end
112
- end
113
- end