sentry-ruby 5.23.0 → 5.27.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.
- checksums.yaml +4 -4
- data/.rspec +3 -1
- data/Gemfile +1 -3
- data/README.md +11 -6
- data/Rakefile +7 -11
- data/lib/sentry/background_worker.rb +2 -3
- data/lib/sentry/backpressure_monitor.rb +1 -1
- data/lib/sentry/breadcrumb.rb +5 -4
- data/lib/sentry/check_in_event.rb +2 -1
- data/lib/sentry/client.rb +84 -4
- data/lib/sentry/configuration.rb +63 -2
- data/lib/sentry/debug_structured_logger.rb +94 -0
- data/lib/sentry/dsn.rb +32 -0
- data/lib/sentry/envelope/item.rb +1 -1
- data/lib/sentry/event.rb +2 -1
- data/lib/sentry/hub.rb +13 -1
- data/lib/sentry/interfaces/request.rb +1 -1
- data/lib/sentry/log_event.rb +206 -0
- data/lib/sentry/log_event_buffer.rb +75 -0
- data/lib/sentry/metrics/aggregator.rb +1 -1
- data/lib/sentry/profiler.rb +3 -2
- data/lib/sentry/propagation_context.rb +59 -22
- data/lib/sentry/scope.rb +13 -3
- data/lib/sentry/session_flusher.rb +1 -1
- data/lib/sentry/span.rb +4 -3
- data/lib/sentry/std_lib_logger.rb +50 -0
- data/lib/sentry/structured_logger.rb +138 -0
- data/lib/sentry/test_helper.rb +29 -0
- data/lib/sentry/threaded_periodic_worker.rb +3 -3
- data/lib/sentry/transaction.rb +30 -8
- data/lib/sentry/transport/debug_transport.rb +70 -0
- data/lib/sentry/transport/dummy_transport.rb +1 -0
- data/lib/sentry/transport/http_transport.rb +9 -5
- data/lib/sentry/transport.rb +17 -8
- data/lib/sentry/utils/logging_helper.rb +10 -3
- data/lib/sentry/utils/sample_rand.rb +97 -0
- data/lib/sentry/utils/uuid.rb +13 -0
- data/lib/sentry/vernier/profiler.rb +3 -2
- data/lib/sentry/version.rb +1 -1
- data/lib/sentry-ruby.rb +67 -4
- metadata +17 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b489d374f24123e3e62626462b08bfa3ea1d0a8c03f7332dd8d353860b065bdf
|
4
|
+
data.tar.gz: f6548949011e59234ce7b90c04f6a3cc95fb0876e93ac598907f6fac7ccd4560
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0f02b67848b924a4fe9827ca5abfb3010035ebe41194d0859bd412b1effce07018c261fd59b1eb28efb9721452985ef6895efb4ba5fa297d82fc58c880d1c5ae
|
7
|
+
data.tar.gz: 1a8f620b58693aa0b30a81b9fdbdd94f78761c519fb49bbb9a57f6bb82296de8d248f3e537718ebb5325f730abac55da0ebd446db86d9e196f56532db1414097
|
data/.rspec
CHANGED
data/Gemfile
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
source "https://rubygems.org"
|
4
4
|
git_source(:github) { |name| "https://github.com/#{name}.git" }
|
5
5
|
|
6
|
-
eval_gemfile "../Gemfile"
|
6
|
+
eval_gemfile "../Gemfile.dev"
|
7
7
|
|
8
8
|
gem "sentry-ruby", path: "./"
|
9
9
|
|
@@ -11,8 +11,6 @@ rack_version = ENV["RACK_VERSION"]
|
|
11
11
|
rack_version = "3.0.0" if rack_version.nil?
|
12
12
|
gem "rack", "~> #{Gem::Version.new(rack_version)}" unless rack_version == "0"
|
13
13
|
|
14
|
-
gem "ostruct" if RUBY_VERSION >= "3.4"
|
15
|
-
|
16
14
|
redis_rb_version = ENV.fetch("REDIS_RB_VERSION", "5.0")
|
17
15
|
gem "redis", "~> #{redis_rb_version}"
|
18
16
|
|
data/README.md
CHANGED
@@ -15,12 +15,12 @@ Sentry SDK for Ruby
|
|
15
15
|
|
16
16
|
| Current version | Build | Coverage | API doc |
|
17
17
|
| ---------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------- |
|
18
|
-
| [](https://rubygems.org/gems/sentry-ruby) | [](https://rubygems.org/gems/sentry-rails) | [](https://rubygems.org/gems/sentry-sidekiq) | [](https://rubygems.org/gems/sentry-delayed_job) | [](https://rubygems.org/gems/sentry-resque) | [](https://rubygems.org/gems/sentry-opentelemetry) | [](https://rubygems.org/gems/sentry-ruby) | [](https://github.com/getsentry/sentry-ruby/actions/workflows/tests.yml) | [](https://codecov.io/gh/getsentry/sentry-ruby) | [](https://www.rubydoc.info/gems/sentry-ruby) |
|
19
|
+
| [](https://rubygems.org/gems/sentry-rails) | [](https://github.com/getsentry/sentry-ruby/actions/workflows/tests.yml) | [](https://codecov.io/gh/getsentry/sentry-ruby) | [](https://www.rubydoc.info/gems/sentry-rails) |
|
20
|
+
| [](https://rubygems.org/gems/sentry-sidekiq) | [](https://github.com/getsentry/sentry-ruby/actions/workflows/tests.yml) | [](https://codecov.io/gh/getsentry/sentry-ruby) | [](https://www.rubydoc.info/gems/sentry-sidekiq) |
|
21
|
+
| [](https://rubygems.org/gems/sentry-delayed_job) | [](https://github.com/getsentry/sentry-ruby/actions/workflows/tests.yml) | [](https://codecov.io/gh/getsentry/sentry-ruby) | [](https://www.rubydoc.info/gems/sentry-delayed_job) |
|
22
|
+
| [](https://rubygems.org/gems/sentry-resque) | [](https://github.com/getsentry/sentry-ruby/actions/workflows/tests.yml) | [](https://codecov.io/gh/getsentry/sentry-ruby) | [](https://www.rubydoc.info/gems/sentry-resque) |
|
23
|
+
| [](https://rubygems.org/gems/sentry-opentelemetry) | [](https://github.com/getsentry/sentry-ruby/actions/workflows/tests.yml) | [](https://codecov.io/gh/getsentry/sentry-ruby) | [](https://www.rubydoc.info/gems/sentry-opentelemetry) |
|
24
24
|
|
25
25
|
|
26
26
|
|
@@ -59,6 +59,8 @@ gem "sentry-opentelemetry"
|
|
59
59
|
|
60
60
|
You need to use Sentry.init to initialize and configure your SDK:
|
61
61
|
```ruby
|
62
|
+
require "sentry-ruby"
|
63
|
+
|
62
64
|
Sentry.init do |config|
|
63
65
|
config.dsn = "MY_DSN"
|
64
66
|
end
|
@@ -116,3 +118,6 @@ Thanks to everyone who has contributed to this project so far.
|
|
116
118
|
<a href="https://github.com/getsentry/sentry-ruby/graphs/contributors">
|
117
119
|
<img src="https://contributors-img.web.app/image?repo=getsentry/sentry-ruby" />
|
118
120
|
</a>
|
121
|
+
|
122
|
+
> [!WARNING]
|
123
|
+
> Example and sample code in sentry-rails/examples and sentry-rails/spec/dummy is unmaintained. Sample code may contain security vulnerabilities, should never be used in production, and exists only for illustrative purposes.
|
data/Rakefile
CHANGED
@@ -6,17 +6,13 @@ CLOBBER.include "pkg"
|
|
6
6
|
require "bundler/gem_helper"
|
7
7
|
Bundler::GemHelper.install_tasks(name: "sentry-ruby")
|
8
8
|
|
9
|
-
|
9
|
+
require_relative "../lib/sentry/test/rake_tasks"
|
10
10
|
|
11
|
-
|
12
|
-
task.rspec_opts = "--order rand"
|
13
|
-
task.exclude_pattern = "spec/isolated/**/*_spec.rb"
|
14
|
-
end
|
11
|
+
ISOLATED_SPECS = "spec/isolated/**/*_spec.rb"
|
15
12
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
end
|
13
|
+
Sentry::Test::RakeTasks.define_spec_tasks(
|
14
|
+
isolated_specs_pattern: ISOLATED_SPECS,
|
15
|
+
spec_exclude_pattern: ISOLATED_SPECS
|
16
|
+
)
|
21
17
|
|
22
|
-
task default: [:spec, :
|
18
|
+
task default: [:spec, :"spec:isolated"]
|
@@ -9,8 +9,7 @@ module Sentry
|
|
9
9
|
include LoggingHelper
|
10
10
|
|
11
11
|
attr_reader :max_queue, :number_of_threads
|
12
|
-
|
13
|
-
attr_reader :logger
|
12
|
+
|
14
13
|
attr_accessor :shutdown_timeout
|
15
14
|
|
16
15
|
DEFAULT_MAX_QUEUE = 30
|
@@ -19,7 +18,7 @@ module Sentry
|
|
19
18
|
@shutdown_timeout = 1
|
20
19
|
@number_of_threads = configuration.background_worker_threads
|
21
20
|
@max_queue = configuration.background_worker_max_queue
|
22
|
-
@
|
21
|
+
@sdk_logger = configuration.sdk_logger
|
23
22
|
@debug = configuration.debug
|
24
23
|
@shutdown_callback = nil
|
25
24
|
|
data/lib/sentry/breadcrumb.rb
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
module Sentry
|
4
4
|
class Breadcrumb
|
5
|
+
MAX_NESTING = 10
|
5
6
|
DATA_SERIALIZATION_ERROR_MESSAGE = "[data were removed due to serialization issues]"
|
6
7
|
|
7
8
|
# @return [String, nil]
|
@@ -47,7 +48,7 @@ module Sentry
|
|
47
48
|
# @param message [String]
|
48
49
|
# @return [void]
|
49
50
|
def message=(message)
|
50
|
-
@message = message ? message.byteslice(0..Event::MAX_MESSAGE_SIZE_IN_BYTES) : ""
|
51
|
+
@message = message && Utils::EncodingHelper.valid_utf_8?(message) ? message.byteslice(0..Event::MAX_MESSAGE_SIZE_IN_BYTES) : ""
|
51
52
|
end
|
52
53
|
|
53
54
|
# @param level [String]
|
@@ -60,16 +61,16 @@ module Sentry
|
|
60
61
|
|
61
62
|
def serialized_data
|
62
63
|
begin
|
63
|
-
::JSON.parse(::JSON.generate(@data))
|
64
|
+
::JSON.parse(::JSON.generate(@data, max_nesting: MAX_NESTING))
|
64
65
|
rescue Exception => e
|
65
|
-
Sentry.
|
66
|
+
Sentry.sdk_logger.debug(LOGGER_PROGNAME) do
|
66
67
|
<<~MSG
|
67
68
|
can't serialize breadcrumb data because of error: #{e}
|
68
69
|
data: #{@data}
|
69
70
|
MSG
|
70
71
|
end
|
71
72
|
|
72
|
-
DATA_SERIALIZATION_ERROR_MESSAGE
|
73
|
+
{ error: DATA_SERIALIZATION_ERROR_MESSAGE }
|
73
74
|
end
|
74
75
|
end
|
75
76
|
end
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require "securerandom"
|
4
4
|
require "sentry/cron/monitor_config"
|
5
|
+
require "sentry/utils/uuid"
|
5
6
|
|
6
7
|
module Sentry
|
7
8
|
class CheckInEvent < Event
|
@@ -43,7 +44,7 @@ module Sentry
|
|
43
44
|
self.status = status
|
44
45
|
self.duration = duration
|
45
46
|
self.monitor_config = monitor_config
|
46
|
-
self.check_in_id = check_in_id ||
|
47
|
+
self.check_in_id = check_in_id || Utils.uuid
|
47
48
|
end
|
48
49
|
|
49
50
|
# @return [Hash]
|
data/lib/sentry/client.rb
CHANGED
@@ -1,6 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "sentry/transport"
|
4
|
+
require "sentry/log_event"
|
5
|
+
require "sentry/log_event_buffer"
|
6
|
+
require "sentry/utils/uuid"
|
4
7
|
|
5
8
|
module Sentry
|
6
9
|
class Client
|
@@ -14,16 +17,16 @@ module Sentry
|
|
14
17
|
# @return [SpotlightTransport, nil]
|
15
18
|
attr_reader :spotlight_transport
|
16
19
|
|
20
|
+
# @!visibility private
|
21
|
+
attr_reader :log_event_buffer
|
22
|
+
|
17
23
|
# @!macro configuration
|
18
24
|
attr_reader :configuration
|
19
25
|
|
20
|
-
# @deprecated Use Sentry.logger to retrieve the current logger instead.
|
21
|
-
attr_reader :logger
|
22
|
-
|
23
26
|
# @param configuration [Configuration]
|
24
27
|
def initialize(configuration)
|
25
28
|
@configuration = configuration
|
26
|
-
@
|
29
|
+
@sdk_logger = configuration.sdk_logger
|
27
30
|
|
28
31
|
if transport_class = configuration.transport.transport_class
|
29
32
|
@transport = transport_class.new(configuration)
|
@@ -38,6 +41,10 @@ module Sentry
|
|
38
41
|
end
|
39
42
|
|
40
43
|
@spotlight_transport = SpotlightTransport.new(configuration) if configuration.spotlight
|
44
|
+
|
45
|
+
if configuration.enable_logs
|
46
|
+
@log_event_buffer = LogEventBuffer.new(configuration, self).start
|
47
|
+
end
|
41
48
|
end
|
42
49
|
|
43
50
|
# Applies the given scope's data to the event and sends it to Sentry.
|
@@ -88,6 +95,15 @@ module Sentry
|
|
88
95
|
nil
|
89
96
|
end
|
90
97
|
|
98
|
+
# Buffer a log event to be sent later with other logs in a single envelope
|
99
|
+
# @param event [LogEvent] the log event to be buffered
|
100
|
+
# @return [LogEvent]
|
101
|
+
def buffer_log_event(event, scope)
|
102
|
+
return unless event.is_a?(LogEvent)
|
103
|
+
@log_event_buffer.add_event(scope.apply_to_event(event))
|
104
|
+
event
|
105
|
+
end
|
106
|
+
|
91
107
|
# Capture an envelope directly.
|
92
108
|
# @param envelope [Envelope] the envelope to be captured.
|
93
109
|
# @return [void]
|
@@ -100,6 +116,7 @@ module Sentry
|
|
100
116
|
def flush
|
101
117
|
transport.flush if configuration.sending_to_dsn_allowed?
|
102
118
|
spotlight_transport.flush if spotlight_transport
|
119
|
+
@log_event_buffer&.flush
|
103
120
|
end
|
104
121
|
|
105
122
|
# Initializes an Event object with the given exception. Returns `nil` if the exception's class is excluded from reporting.
|
@@ -167,6 +184,22 @@ module Sentry
|
|
167
184
|
)
|
168
185
|
end
|
169
186
|
|
187
|
+
# Initializes a LogEvent object with the given message and options
|
188
|
+
#
|
189
|
+
# @param message [String] the log message
|
190
|
+
# @param level [Symbol] the log level (:trace, :debug, :info, :warn, :error, :fatal)
|
191
|
+
# @param options [Hash] additional options
|
192
|
+
# @option options [Array] :parameters Array of values to replace template tokens in the message
|
193
|
+
#
|
194
|
+
# @return [LogEvent] the created log event
|
195
|
+
def event_from_log(message, level:, **options)
|
196
|
+
return unless configuration.sending_allowed?
|
197
|
+
|
198
|
+
attributes = options.reject { |k, _| k == :level || k == :severity }
|
199
|
+
|
200
|
+
LogEvent.new(level: level, body: message, attributes: attributes)
|
201
|
+
end
|
202
|
+
|
170
203
|
# Initializes an Event object with the given Transaction object.
|
171
204
|
# @param transaction [Transaction] the transaction to be recorded.
|
172
205
|
# @return [TransactionEvent]
|
@@ -237,6 +270,53 @@ module Sentry
|
|
237
270
|
raise
|
238
271
|
end
|
239
272
|
|
273
|
+
# Send an envelope with batched logs
|
274
|
+
# @param log_events [Array<LogEvent>] the log events to be sent
|
275
|
+
# @api private
|
276
|
+
# @return [void]
|
277
|
+
def send_logs(log_events)
|
278
|
+
envelope = Envelope.new(
|
279
|
+
event_id: Sentry::Utils.uuid,
|
280
|
+
sent_at: Sentry.utc_now.iso8601,
|
281
|
+
dsn: configuration.dsn,
|
282
|
+
sdk: Sentry.sdk_meta
|
283
|
+
)
|
284
|
+
|
285
|
+
discarded_count = 0
|
286
|
+
envelope_items = []
|
287
|
+
|
288
|
+
if configuration.before_send_log
|
289
|
+
log_events.each do |log_event|
|
290
|
+
processed_log_event = configuration.before_send_log.call(log_event)
|
291
|
+
|
292
|
+
if processed_log_event
|
293
|
+
envelope_items << processed_log_event.to_hash
|
294
|
+
else
|
295
|
+
discarded_count += 1
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
envelope_items
|
300
|
+
else
|
301
|
+
envelope_items = log_events.map(&:to_hash)
|
302
|
+
end
|
303
|
+
|
304
|
+
envelope.add_item(
|
305
|
+
{
|
306
|
+
type: "log",
|
307
|
+
item_count: envelope_items.size,
|
308
|
+
content_type: "application/vnd.sentry.items.log+json"
|
309
|
+
},
|
310
|
+
{ items: envelope_items }
|
311
|
+
)
|
312
|
+
|
313
|
+
send_envelope(envelope)
|
314
|
+
|
315
|
+
unless discarded_count.zero?
|
316
|
+
transport.record_lost_event(:before_send, "log_item", num: discarded_count)
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
240
320
|
# Send an envelope directly to Sentry.
|
241
321
|
# @param envelope [Envelope] the envelope to be sent.
|
242
322
|
# @return [void]
|
data/lib/sentry/configuration.rb
CHANGED
@@ -12,6 +12,9 @@ require "sentry/cron/configuration"
|
|
12
12
|
require "sentry/metrics/configuration"
|
13
13
|
require "sentry/linecache"
|
14
14
|
require "sentry/interfaces/stacktrace_builder"
|
15
|
+
require "sentry/logger"
|
16
|
+
require "sentry/structured_logger"
|
17
|
+
require "sentry/log_event_buffer"
|
15
18
|
|
16
19
|
module Sentry
|
17
20
|
class Configuration
|
@@ -99,6 +102,15 @@ module Sentry
|
|
99
102
|
# @return [Proc]
|
100
103
|
attr_reader :before_send_transaction
|
101
104
|
|
105
|
+
# Optional Proc, called before sending an event to the server
|
106
|
+
# @example
|
107
|
+
# config.before_send_log = lambda do |log|
|
108
|
+
# log.attributes["sentry"] = true
|
109
|
+
# log
|
110
|
+
# end
|
111
|
+
# @return [Proc]
|
112
|
+
attr_accessor :before_send_log
|
113
|
+
|
102
114
|
# An array of breadcrumbs loggers to be used. Available options are:
|
103
115
|
# - :sentry_logger
|
104
116
|
# - :http_logger
|
@@ -183,7 +195,24 @@ module Sentry
|
|
183
195
|
# Logger used by Sentry. In Rails, this is the Rails logger, otherwise
|
184
196
|
# Sentry provides its own Sentry::Logger.
|
185
197
|
# @return [Logger]
|
186
|
-
attr_accessor :
|
198
|
+
attr_accessor :sdk_logger
|
199
|
+
|
200
|
+
# File path for DebugTransport to log events to. If not set, defaults to a temporary file.
|
201
|
+
# This is useful for debugging and testing purposes.
|
202
|
+
# @return [String, nil]
|
203
|
+
attr_accessor :sdk_debug_transport_log_file
|
204
|
+
|
205
|
+
# @deprecated Use {#sdk_logger=} instead.
|
206
|
+
def logger=(logger)
|
207
|
+
warn "[sentry] `config.logger=` is deprecated. Please use `config.sdk_logger=` instead."
|
208
|
+
self.sdk_logger = logger
|
209
|
+
end
|
210
|
+
|
211
|
+
# @deprecated Use {#sdk_logger} instead.
|
212
|
+
def logger
|
213
|
+
warn "[sentry] `config.logger` is deprecated. Please use `config.sdk_logger` instead."
|
214
|
+
self.sdk_logger
|
215
|
+
end
|
187
216
|
|
188
217
|
# Project directory root for in_app detection. Could be Rails root, etc.
|
189
218
|
# Set automatically for Rails.
|
@@ -262,6 +291,14 @@ module Sentry
|
|
262
291
|
# @return [Proc]
|
263
292
|
attr_accessor :traces_sampler
|
264
293
|
|
294
|
+
# Enable Structured Logging
|
295
|
+
# @return [Boolean]
|
296
|
+
attr_accessor :enable_logs
|
297
|
+
|
298
|
+
# Structured logging configuration.
|
299
|
+
# @return [StructuredLoggingConfiguration]
|
300
|
+
attr_reader :structured_logging
|
301
|
+
|
265
302
|
# Easier way to use performance tracing
|
266
303
|
# If set to true, will set traces_sample_rate to 1.0
|
267
304
|
# @deprecated It will be removed in the next major release.
|
@@ -307,6 +344,10 @@ module Sentry
|
|
307
344
|
# @return [Array<Symbol>]
|
308
345
|
attr_accessor :enabled_patches
|
309
346
|
|
347
|
+
# Maximum number of log events to buffer before sending
|
348
|
+
# @return [Integer]
|
349
|
+
attr_accessor :max_log_events
|
350
|
+
|
310
351
|
# these are not config options
|
311
352
|
# @!visibility private
|
312
353
|
attr_reader :errors, :gem_specs
|
@@ -419,7 +460,7 @@ module Sentry
|
|
419
460
|
self.excluded_exceptions = IGNORE_DEFAULT + PUMA_IGNORE_DEFAULT
|
420
461
|
self.inspect_exception_causes_for_exclusion = true
|
421
462
|
self.linecache = ::Sentry::LineCache.new
|
422
|
-
self.
|
463
|
+
self.sdk_logger = ::Sentry::Logger.new(STDOUT)
|
423
464
|
self.project_root = Dir.pwd
|
424
465
|
self.propagate_traces = true
|
425
466
|
|
@@ -443,18 +484,23 @@ module Sentry
|
|
443
484
|
|
444
485
|
self.before_send = nil
|
445
486
|
self.before_send_transaction = nil
|
487
|
+
self.before_send_log = nil
|
446
488
|
self.rack_env_whitelist = RACK_ENV_WHITELIST_DEFAULT
|
447
489
|
self.traces_sampler = nil
|
448
490
|
self.enable_tracing = nil
|
491
|
+
self.enable_logs = false
|
449
492
|
|
450
493
|
self.profiler_class = Sentry::Profiler
|
451
494
|
|
452
495
|
@transport = Transport::Configuration.new
|
453
496
|
@cron = Cron::Configuration.new
|
454
497
|
@metrics = Metrics::Configuration.new
|
498
|
+
@structured_logging = StructuredLoggingConfiguration.new
|
455
499
|
@gem_specs = Hash[Gem::Specification.map { |spec| [spec.name, spec.version.to_s] }] if Gem::Specification.respond_to?(:map)
|
456
500
|
|
457
501
|
run_post_initialization_callbacks
|
502
|
+
|
503
|
+
self.max_log_events = LogEventBuffer::DEFAULT_MAX_EVENTS
|
458
504
|
end
|
459
505
|
|
460
506
|
def validate
|
@@ -749,4 +795,19 @@ module Sentry
|
|
749
795
|
available_processor_count || Concurrent.processor_count
|
750
796
|
end
|
751
797
|
end
|
798
|
+
|
799
|
+
class StructuredLoggingConfiguration
|
800
|
+
# File path for DebugStructuredLogger to log events to
|
801
|
+
# @return [String, Pathname, nil]
|
802
|
+
attr_accessor :file_path
|
803
|
+
|
804
|
+
# The class to use as a structured logger.
|
805
|
+
# @return [Class]
|
806
|
+
attr_accessor :logger_class
|
807
|
+
|
808
|
+
def initialize
|
809
|
+
@file_path = nil
|
810
|
+
@logger_class = Sentry::StructuredLogger
|
811
|
+
end
|
812
|
+
end
|
752
813
|
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "json"
|
4
|
+
require "fileutils"
|
5
|
+
require "pathname"
|
6
|
+
require "delegate"
|
7
|
+
|
8
|
+
module Sentry
|
9
|
+
# DebugStructuredLogger is a logger that captures structured log events to a file for debugging purposes.
|
10
|
+
#
|
11
|
+
# It can optionally also send log events to Sentry via the normal structured logger if logging
|
12
|
+
# is enabled.
|
13
|
+
class DebugStructuredLogger < SimpleDelegator
|
14
|
+
DEFAULT_LOG_FILE_PATH = File.join("log", "sentry_debug_logs.log")
|
15
|
+
|
16
|
+
attr_reader :log_file, :backend
|
17
|
+
|
18
|
+
def initialize(configuration)
|
19
|
+
@log_file = initialize_log_file(
|
20
|
+
configuration.structured_logging.file_path || DEFAULT_LOG_FILE_PATH
|
21
|
+
)
|
22
|
+
@backend = initialize_backend(configuration)
|
23
|
+
|
24
|
+
super(@backend)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Override all log level methods to capture events
|
28
|
+
%i[trace debug info warn error fatal].each do |level|
|
29
|
+
define_method(level) do |message, parameters = [], **attributes|
|
30
|
+
log_event = capture_log_event(level, message, parameters, **attributes)
|
31
|
+
backend.public_send(level, message, parameters, **attributes)
|
32
|
+
log_event
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def log(level, message, parameters:, **attributes)
|
37
|
+
log_event = capture_log_event(level, message, parameters, **attributes)
|
38
|
+
backend.log(level, message, parameters: parameters, **attributes)
|
39
|
+
log_event
|
40
|
+
end
|
41
|
+
|
42
|
+
def capture_log_event(level, message, parameters, **attributes)
|
43
|
+
log_event_json = {
|
44
|
+
timestamp: Time.now.utc.iso8601,
|
45
|
+
level: level.to_s,
|
46
|
+
message: message,
|
47
|
+
parameters: parameters,
|
48
|
+
attributes: attributes
|
49
|
+
}
|
50
|
+
|
51
|
+
File.open(log_file, "a") { |file| file << JSON.dump(log_event_json) << "\n" }
|
52
|
+
log_event_json
|
53
|
+
end
|
54
|
+
|
55
|
+
def logged_events
|
56
|
+
File.readlines(log_file).map do |line|
|
57
|
+
JSON.parse(line)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def clear
|
62
|
+
File.write(log_file, "")
|
63
|
+
if backend.respond_to?(:config)
|
64
|
+
backend.config.sdk_logger.debug("DebugStructuredLogger: Cleared events from #{log_file}")
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def initialize_backend(configuration)
|
71
|
+
if configuration.enable_logs
|
72
|
+
StructuredLogger.new(configuration)
|
73
|
+
else
|
74
|
+
# Create a no-op logger if logging is disabled
|
75
|
+
NoOpLogger.new
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def initialize_log_file(log_file_path)
|
80
|
+
log_file = Pathname(log_file_path)
|
81
|
+
|
82
|
+
FileUtils.mkdir_p(log_file.dirname) unless log_file.dirname.exist?
|
83
|
+
|
84
|
+
log_file
|
85
|
+
end
|
86
|
+
|
87
|
+
# No-op logger for when structured logging is disabled
|
88
|
+
class NoOpLogger
|
89
|
+
%i[trace debug info warn error fatal log].each do |method|
|
90
|
+
define_method(method) { |*args, **kwargs| nil }
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
data/lib/sentry/dsn.rb
CHANGED
@@ -1,11 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "uri"
|
4
|
+
require "ipaddr"
|
5
|
+
require "resolv"
|
4
6
|
|
5
7
|
module Sentry
|
6
8
|
class DSN
|
7
9
|
PORT_MAP = { "http" => 80, "https" => 443 }.freeze
|
8
10
|
REQUIRED_ATTRIBUTES = %w[host path public_key project_id].freeze
|
11
|
+
LOCALHOST_NAMES = %w[localhost 127.0.0.1 ::1 [::1]].freeze
|
12
|
+
LOCALHOST_PATTERN = /\.local(host|domain)?$/i
|
9
13
|
|
10
14
|
attr_reader :scheme, :secret_key, :port, *REQUIRED_ATTRIBUTES
|
11
15
|
|
@@ -49,5 +53,33 @@ module Sentry
|
|
49
53
|
def envelope_endpoint
|
50
54
|
"#{path}/api/#{project_id}/envelope/"
|
51
55
|
end
|
56
|
+
|
57
|
+
def local?
|
58
|
+
@local ||= (localhost? || private_ip? || resolved_ips_private?)
|
59
|
+
end
|
60
|
+
|
61
|
+
def localhost?
|
62
|
+
LOCALHOST_NAMES.include?(host.downcase) || LOCALHOST_PATTERN.match?(host)
|
63
|
+
end
|
64
|
+
|
65
|
+
def private_ip?
|
66
|
+
@private_ip ||= begin
|
67
|
+
begin
|
68
|
+
IPAddr.new(host).private?
|
69
|
+
rescue IPAddr::InvalidAddressError
|
70
|
+
false
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def resolved_ips_private?
|
76
|
+
@resolved_ips_private ||= begin
|
77
|
+
begin
|
78
|
+
Resolv.getaddresses(host).any? { |ip| IPAddr.new(ip).private? }
|
79
|
+
rescue Resolv::ResolvError, IPAddr::InvalidAddressError
|
80
|
+
false
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
52
84
|
end
|
53
85
|
end
|
data/lib/sentry/envelope/item.rb
CHANGED
@@ -15,7 +15,7 @@ module Sentry
|
|
15
15
|
# rate limits and client reports use the data_category rather than envelope item type
|
16
16
|
def self.data_category(type)
|
17
17
|
case type
|
18
|
-
when "session", "attachment", "transaction", "profile", "span" then type
|
18
|
+
when "session", "attachment", "transaction", "profile", "span", "log" then type
|
19
19
|
when "sessions" then "session"
|
20
20
|
when "check_in" then "monitor"
|
21
21
|
when "statsd", "metric_meta" then "metric_bucket"
|
data/lib/sentry/event.rb
CHANGED
@@ -7,6 +7,7 @@ require "sentry/backtrace"
|
|
7
7
|
require "sentry/utils/real_ip"
|
8
8
|
require "sentry/utils/request_id"
|
9
9
|
require "sentry/utils/custom_inspection"
|
10
|
+
require "sentry/utils/uuid"
|
10
11
|
|
11
12
|
module Sentry
|
12
13
|
# This is an abstract class that defines the shared attributes of an event.
|
@@ -50,7 +51,7 @@ module Sentry
|
|
50
51
|
# @param message [String, nil]
|
51
52
|
def initialize(configuration:, integration_meta: nil, message: nil)
|
52
53
|
# Set some simple default values
|
53
|
-
@event_id =
|
54
|
+
@event_id = Utils.uuid
|
54
55
|
@timestamp = Sentry.utc_now.iso8601
|
55
56
|
@platform = :ruby
|
56
57
|
@type = self.class::TYPE
|