goodsorcery 0.1.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 +7 -0
- data/CHANGELOG.md +17 -0
- data/LICENSE +21 -0
- data/README.md +299 -0
- data/lib/generators/goodsorcery/install/credentials_api_key.rb +64 -0
- data/lib/generators/goodsorcery/install/install_generator.rb +64 -0
- data/lib/generators/goodsorcery/install/templates/initializer.rb +54 -0
- data/lib/goodsorcery/backtrace/code_context.rb +27 -0
- data/lib/goodsorcery/backtrace/line_cache.rb +57 -0
- data/lib/goodsorcery/backtrace/parser.rb +38 -0
- data/lib/goodsorcery/backtrace/paths.rb +42 -0
- data/lib/goodsorcery/bundler_plugin.rb +117 -0
- data/lib/goodsorcery/client.rb +180 -0
- data/lib/goodsorcery/configuration/validation.rb +59 -0
- data/lib/goodsorcery/configuration.rb +204 -0
- data/lib/goodsorcery/defaults.rb +40 -0
- data/lib/goodsorcery/delivery/active_job_queue.rb +71 -0
- data/lib/goodsorcery/delivery/async.rb +122 -0
- data/lib/goodsorcery/delivery/backoff.rb +20 -0
- data/lib/goodsorcery/delivery/custom.rb +27 -0
- data/lib/goodsorcery/delivery/event_queue.rb +124 -0
- data/lib/goodsorcery/delivery/sync.rb +27 -0
- data/lib/goodsorcery/delivery/test.rb +30 -0
- data/lib/goodsorcery/delivery/worker.rb +71 -0
- data/lib/goodsorcery/delivery.rb +39 -0
- data/lib/goodsorcery/delivery_job.rb +26 -0
- data/lib/goodsorcery/env_flag.rb +24 -0
- data/lib/goodsorcery/environment_gate.rb +61 -0
- data/lib/goodsorcery/errors.rb +14 -0
- data/lib/goodsorcery/event/breadcrumb.rb +32 -0
- data/lib/goodsorcery/event/builder.rb +77 -0
- data/lib/goodsorcery/event/cause_chain.rb +39 -0
- data/lib/goodsorcery/event/exception_section.rb +68 -0
- data/lib/goodsorcery/event/fields.rb +61 -0
- data/lib/goodsorcery/event/job_section.rb +34 -0
- data/lib/goodsorcery/event/request_section.rb +41 -0
- data/lib/goodsorcery/event/runtime_context.rb +52 -0
- data/lib/goodsorcery/event/tag_set.rb +41 -0
- data/lib/goodsorcery/event/user_section.rb +36 -0
- data/lib/goodsorcery/event_filter.rb +54 -0
- data/lib/goodsorcery/event_pipeline.rb +35 -0
- data/lib/goodsorcery/event_serializer.rb +25 -0
- data/lib/goodsorcery/exception_coercion.rb +18 -0
- data/lib/goodsorcery/extra_filter_probe.rb +32 -0
- data/lib/goodsorcery/ignore_list.rb +15 -0
- data/lib/goodsorcery/install_check.rb +58 -0
- data/lib/goodsorcery/integrations/action_cable.rb +75 -0
- data/lib/goodsorcery/integrations/active_job/job_details.rb +90 -0
- data/lib/goodsorcery/integrations/active_job.rb +39 -0
- data/lib/goodsorcery/integrations/rails/controller_action.rb +40 -0
- data/lib/goodsorcery/integrations/rails/controller_enricher.rb +27 -0
- data/lib/goodsorcery/integrations/rails/error_subscriber.rb +40 -0
- data/lib/goodsorcery/integrations/rails/notification_breadcrumbs.rb +82 -0
- data/lib/goodsorcery/integrations/rails/sql_statement.rb +31 -0
- data/lib/goodsorcery/integrations/rails/user_lookup.rb +39 -0
- data/lib/goodsorcery/integrations/rails.rb +56 -0
- data/lib/goodsorcery/integrations/rake.rb +68 -0
- data/lib/goodsorcery/integrations/sidekiq/job_details.rb +54 -0
- data/lib/goodsorcery/integrations/sidekiq.rb +55 -0
- data/lib/goodsorcery/integrations.rb +27 -0
- data/lib/goodsorcery/job_arguments.rb +77 -0
- data/lib/goodsorcery/key_filter.rb +99 -0
- data/lib/goodsorcery/log.rb +55 -0
- data/lib/goodsorcery/masked_key.rb +29 -0
- data/lib/goodsorcery/rack/middleware.rb +57 -0
- data/lib/goodsorcery/rack/request_details.rb +120 -0
- data/lib/goodsorcery/rack/request_enricher.rb +20 -0
- data/lib/goodsorcery/rails_filter_parameters.rb +24 -0
- data/lib/goodsorcery/railtie.rb +29 -0
- data/lib/goodsorcery/release_detector.rb +42 -0
- data/lib/goodsorcery/reported_mark.rb +19 -0
- data/lib/goodsorcery/sanitizer.rb +71 -0
- data/lib/goodsorcery/scope.rb +106 -0
- data/lib/goodsorcery/status_report.rb +50 -0
- data/lib/goodsorcery/tasks.rb +46 -0
- data/lib/goodsorcery/test_event.rb +46 -0
- data/lib/goodsorcery/text.rb +35 -0
- data/lib/goodsorcery/transport/batch_chunks.rb +40 -0
- data/lib/goodsorcery/transport/connection.rb +87 -0
- data/lib/goodsorcery/transport/result.rb +103 -0
- data/lib/goodsorcery/transport.rb +172 -0
- data/lib/goodsorcery/verification.rb +47 -0
- data/lib/goodsorcery/version.rb +6 -0
- data/lib/goodsorcery.rb +176 -0
- data/plugins.rb +6 -0
- metadata +130 -0
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "transport/result"
|
|
4
|
+
require_relative "transport/connection"
|
|
5
|
+
require_relative "transport/batch_chunks"
|
|
6
|
+
|
|
7
|
+
module GoodSorcery
|
|
8
|
+
# Talks to the ingest API over HTTP(S): keep-alive, gzip, Bearer auth.
|
|
9
|
+
# Takes serialized events (JSON strings) and returns Transport::Result
|
|
10
|
+
# objects. Logs statuses and counts only, never bodies or the full key.
|
|
11
|
+
class Transport
|
|
12
|
+
EVENTS_PATH = "/api/v1/events"
|
|
13
|
+
BATCH_PATH = "/api/v1/events/batch"
|
|
14
|
+
VERIFY_PATH = "/api/v1/verify"
|
|
15
|
+
GZIP_MIN_BYTES = 1_024
|
|
16
|
+
|
|
17
|
+
def initialize(endpoint:, api_key:, open_timeout:, read_timeout:, log:)
|
|
18
|
+
@uri = URI(endpoint)
|
|
19
|
+
@api_key = api_key.to_s
|
|
20
|
+
@timeouts = { open_timeout: open_timeout, read_timeout: read_timeout }
|
|
21
|
+
@log = log
|
|
22
|
+
@connection = Connection.new(@uri, **@timeouts)
|
|
23
|
+
@connection_lock = Mutex.new
|
|
24
|
+
@batch_supported = true
|
|
25
|
+
warn_about_plain_http
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def post_event(json)
|
|
29
|
+
result = send_request(post(EVENTS_PATH, json))
|
|
30
|
+
log_result(result, 1)
|
|
31
|
+
result
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Sends events in as few requests as possible. On a 429 or a retryable
|
|
35
|
+
# failure it stops and returns that result with the unsent events in
|
|
36
|
+
# +pending+. Falls back to one request per event if the server has no
|
|
37
|
+
# batch endpoint (404), and remembers that. A batch the server (or a
|
|
38
|
+
# proxy in front of it) refuses as too large (413) is split in halves.
|
|
39
|
+
def post_batch(jsons)
|
|
40
|
+
return post_each(jsons) unless @batch_supported
|
|
41
|
+
|
|
42
|
+
chunks = BatchChunks.split(jsons)
|
|
43
|
+
chunks.each_with_index do |chunk, index|
|
|
44
|
+
result = post_chunk(chunk)
|
|
45
|
+
return result.with_pending(unsent(result, chunk, chunks[(index + 1)..])) if result.retry_later?
|
|
46
|
+
return post_each(chunks[index..].flatten) if result.not_found? && batch_unsupported!
|
|
47
|
+
end
|
|
48
|
+
Result.new(:success)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def verify
|
|
52
|
+
send_request(Net::HTTP::Get.new(path(VERIFY_PATH), headers))
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def close
|
|
56
|
+
@connection_lock.synchronize { @connection.close }
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def batch_supported?
|
|
60
|
+
@batch_supported
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Shows the host and the masked key only.
|
|
64
|
+
def inspect
|
|
65
|
+
"#<#{self.class.name} #{@uri.scheme}://#{@uri.host}:#{@uri.port} api_key=#{MaskedKey.new(@api_key)}>"
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
private
|
|
69
|
+
|
|
70
|
+
def post_chunk(chunk)
|
|
71
|
+
result = send_request(post(BATCH_PATH, BatchChunks.body(chunk)))
|
|
72
|
+
return post_halves(chunk) if result.status == 413 && chunk.size > 1
|
|
73
|
+
|
|
74
|
+
log_result(result, chunk.size) unless result.not_found?
|
|
75
|
+
log_partial_rejections(result) if result.success?
|
|
76
|
+
result
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def post_halves(chunk)
|
|
80
|
+
halves = chunk.each_slice((chunk.size + 1) / 2).to_a
|
|
81
|
+
halves.each_with_index do |half, index|
|
|
82
|
+
result = post_chunk(half)
|
|
83
|
+
return result.with_pending(unsent(result, half, halves[(index + 1)..])) if result.retry_later?
|
|
84
|
+
end
|
|
85
|
+
Result.new(:success)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# What is left after a 429 or retryable result for +chunk+.
|
|
89
|
+
def unsent(result, chunk, later_chunks)
|
|
90
|
+
(result.pending.empty? ? chunk : result.pending) + later_chunks.flatten
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def post_each(jsons)
|
|
94
|
+
jsons.each_with_index do |json, index|
|
|
95
|
+
result = post_event(json)
|
|
96
|
+
return result.with_pending(jsons[index..]) if result.retry_later?
|
|
97
|
+
end
|
|
98
|
+
Result.new(:success)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def batch_unsupported!
|
|
102
|
+
@log.info("the server has no batch endpoint; sending events one per request")
|
|
103
|
+
@batch_supported = false
|
|
104
|
+
true
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def send_request(request)
|
|
108
|
+
Result.from_response(perform(request))
|
|
109
|
+
rescue StandardError => e
|
|
110
|
+
Result.from_error(e)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# The persistent connection serves one thread at a time; a concurrent
|
|
114
|
+
# caller (the :sync delivery in a busy app) gets a short-lived one.
|
|
115
|
+
def perform(request)
|
|
116
|
+
return Connection.new(@uri, **@timeouts).request_once(request) unless @connection_lock.try_lock
|
|
117
|
+
|
|
118
|
+
begin
|
|
119
|
+
@connection.request(request)
|
|
120
|
+
ensure
|
|
121
|
+
@connection_lock.unlock
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def post(path_name, body)
|
|
126
|
+
request = Net::HTTP::Post.new(path(path_name), headers)
|
|
127
|
+
if body.bytesize >= GZIP_MIN_BYTES
|
|
128
|
+
request["Content-Encoding"] = "gzip"
|
|
129
|
+
body = Zlib.gzip(body, level: Zlib::BEST_SPEED)
|
|
130
|
+
end
|
|
131
|
+
request.body = body
|
|
132
|
+
request
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def headers
|
|
136
|
+
{
|
|
137
|
+
"Authorization" => "Bearer #{@api_key}",
|
|
138
|
+
"Content-Type" => "application/json",
|
|
139
|
+
"Accept" => "application/json",
|
|
140
|
+
"User-Agent" => "#{NOTIFIER_NAME}/#{VERSION}"
|
|
141
|
+
}
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def path(name)
|
|
145
|
+
"#{@uri.path.chomp("/")}#{name}"
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def log_result(result, count)
|
|
149
|
+
return log_invalid_key if result.status == 401
|
|
150
|
+
return if result.success? || result.retry_later?
|
|
151
|
+
|
|
152
|
+
@log.warn_every(:"rejected_#{result.status}", 60, "the server rejected #{count} event(s) (#{result.description})")
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def log_invalid_key
|
|
156
|
+
@log.warn_once(:invalid_api_key, "invalid API key #{MaskedKey.new(@api_key)} (HTTP 401); events are dropped")
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def log_partial_rejections(result)
|
|
160
|
+
rejected = Array(result.body["rejected"])
|
|
161
|
+
return if rejected.empty?
|
|
162
|
+
|
|
163
|
+
@log.warn_every(:batch_rejections, 60, "the server rejected #{rejected.size} event(s) of a batch as invalid")
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def warn_about_plain_http
|
|
167
|
+
return unless @uri.scheme == "http" && !%w[localhost 127.0.0.1 ::1].include?(@uri.host)
|
|
168
|
+
|
|
169
|
+
@log.warn_once(:plain_http, "endpoint #{@uri.host} uses plain HTTP; the API key is sent unencrypted")
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module GoodSorcery
|
|
4
|
+
# The outcome of GoodSorcery.verify: can this endpoint be reached, and does
|
|
5
|
+
# it accept the API key? Messages show the masked key only.
|
|
6
|
+
class Verification
|
|
7
|
+
attr_reader :message, :environment
|
|
8
|
+
|
|
9
|
+
NO_KEY = "no API key configured (set GOODSORCERY_API_KEY or config.api_key)"
|
|
10
|
+
|
|
11
|
+
def self.run(config, transport)
|
|
12
|
+
return new(false, NO_KEY) if config.api_key.to_s.empty?
|
|
13
|
+
|
|
14
|
+
from_result(transport.verify, config)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def self.from_result(result, config)
|
|
18
|
+
return success(result, config) if result.success?
|
|
19
|
+
return new(false, "the server rejected API key #{config.masked_api_key} (HTTP 401)") if result.status == 401
|
|
20
|
+
return new(false, "#{config.endpoint_label} has no verify endpoint (HTTP 404)") if result.not_found?
|
|
21
|
+
return new(false, "rate limited (HTTP 429); try again in #{result.retry_after} s") if result.rate_limited?
|
|
22
|
+
|
|
23
|
+
new(false, "could not reach #{config.endpoint_label} (#{result.description})")
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def self.success(result, config)
|
|
27
|
+
environment = result.body["environment"]
|
|
28
|
+
label = environment ? " for environment #{environment.to_s.inspect}" : ""
|
|
29
|
+
message = "API key #{config.masked_api_key} is valid#{label} at #{config.endpoint_label}"
|
|
30
|
+
new(true, message, environment: environment)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def initialize(succeeded, message, environment: nil)
|
|
34
|
+
@ok = succeeded
|
|
35
|
+
@message = message
|
|
36
|
+
@environment = environment
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def ok?
|
|
40
|
+
@ok
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def to_s
|
|
44
|
+
message
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
data/lib/goodsorcery.rb
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
require "logger"
|
|
5
|
+
require "monitor"
|
|
6
|
+
require "net/http"
|
|
7
|
+
require "securerandom"
|
|
8
|
+
require "socket"
|
|
9
|
+
require "time"
|
|
10
|
+
require "uri"
|
|
11
|
+
require "zlib"
|
|
12
|
+
|
|
13
|
+
require_relative "goodsorcery/version"
|
|
14
|
+
require_relative "goodsorcery/errors"
|
|
15
|
+
require_relative "goodsorcery/log"
|
|
16
|
+
require_relative "goodsorcery/defaults"
|
|
17
|
+
require_relative "goodsorcery/env_flag"
|
|
18
|
+
require_relative "goodsorcery/masked_key"
|
|
19
|
+
require_relative "goodsorcery/release_detector"
|
|
20
|
+
require_relative "goodsorcery/configuration"
|
|
21
|
+
require_relative "goodsorcery/environment_gate"
|
|
22
|
+
require_relative "goodsorcery/text"
|
|
23
|
+
require_relative "goodsorcery/sanitizer"
|
|
24
|
+
require_relative "goodsorcery/key_filter"
|
|
25
|
+
require_relative "goodsorcery/extra_filter_probe"
|
|
26
|
+
require_relative "goodsorcery/event_filter"
|
|
27
|
+
require_relative "goodsorcery/rails_filter_parameters"
|
|
28
|
+
require_relative "goodsorcery/job_arguments"
|
|
29
|
+
require_relative "goodsorcery/scope"
|
|
30
|
+
require_relative "goodsorcery/backtrace/parser"
|
|
31
|
+
require_relative "goodsorcery/backtrace/paths"
|
|
32
|
+
require_relative "goodsorcery/backtrace/line_cache"
|
|
33
|
+
require_relative "goodsorcery/backtrace/code_context"
|
|
34
|
+
require_relative "goodsorcery/event/fields"
|
|
35
|
+
require_relative "goodsorcery/event/exception_section"
|
|
36
|
+
require_relative "goodsorcery/event/cause_chain"
|
|
37
|
+
require_relative "goodsorcery/event/runtime_context"
|
|
38
|
+
require_relative "goodsorcery/event/user_section"
|
|
39
|
+
require_relative "goodsorcery/event/tag_set"
|
|
40
|
+
require_relative "goodsorcery/event/request_section"
|
|
41
|
+
require_relative "goodsorcery/event/job_section"
|
|
42
|
+
require_relative "goodsorcery/event/breadcrumb"
|
|
43
|
+
require_relative "goodsorcery/event/builder"
|
|
44
|
+
require_relative "goodsorcery/event_pipeline"
|
|
45
|
+
require_relative "goodsorcery/event_serializer"
|
|
46
|
+
require_relative "goodsorcery/reported_mark"
|
|
47
|
+
require_relative "goodsorcery/ignore_list"
|
|
48
|
+
require_relative "goodsorcery/exception_coercion"
|
|
49
|
+
require_relative "goodsorcery/transport"
|
|
50
|
+
require_relative "goodsorcery/delivery"
|
|
51
|
+
require_relative "goodsorcery/verification"
|
|
52
|
+
require_relative "goodsorcery/test_event"
|
|
53
|
+
require_relative "goodsorcery/client"
|
|
54
|
+
require_relative "goodsorcery/rack/middleware"
|
|
55
|
+
|
|
56
|
+
# Reports exceptions to a Good Sorcery error tracker. See README.md.
|
|
57
|
+
module GoodSorcery
|
|
58
|
+
LOCK = Mutex.new
|
|
59
|
+
@log = Log.new { configuration.logger }
|
|
60
|
+
|
|
61
|
+
class << self
|
|
62
|
+
def configuration
|
|
63
|
+
@configuration || LOCK.synchronize { @configuration ||= Configuration.new }
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Yields the configuration. Rebuilds the delivery when a delivery-related
|
|
67
|
+
# setting changed, and recompiles filters.
|
|
68
|
+
def configure
|
|
69
|
+
before = configuration.delivery_settings
|
|
70
|
+
yield configuration
|
|
71
|
+
client.reconfigure(rebuild_delivery: before != configuration.delivery_settings)
|
|
72
|
+
configuration
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def client
|
|
76
|
+
return @client if @client
|
|
77
|
+
|
|
78
|
+
config = configuration
|
|
79
|
+
LOCK.synchronize { @client ||= Client.new(config, log) }
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# The gem's own logger (prefixed, rate-limited; see GoodSorcery::Log).
|
|
83
|
+
attr_reader :log
|
|
84
|
+
|
|
85
|
+
# Reports an exception (or a message). => event id, or nil. Never raises.
|
|
86
|
+
def notify(exception_or_message, context: nil, tags: nil, user: nil, level: nil,
|
|
87
|
+
fingerprint: nil, transaction: nil)
|
|
88
|
+
options = { context: context, tags: tags, user: user, level: level,
|
|
89
|
+
fingerprint: fingerprint, transaction: transaction }.compact
|
|
90
|
+
client.notify(exception_or_message, **options)
|
|
91
|
+
rescue StandardError
|
|
92
|
+
nil
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def enabled?
|
|
96
|
+
client.enabled?
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def scope
|
|
100
|
+
Scope.current
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def clear_scope
|
|
104
|
+
Scope.clear
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Runs the block with a fresh scope (one request or job), then restores
|
|
108
|
+
# the previous one.
|
|
109
|
+
def with_scope
|
|
110
|
+
previous = Thread.current[Scope::STORAGE_KEY]
|
|
111
|
+
Scope.current = Scope.new(unit_of_work: true)
|
|
112
|
+
yield Scope.current
|
|
113
|
+
ensure
|
|
114
|
+
Scope.current = previous
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def with_context(hash, &)
|
|
118
|
+
scope.with_context(hash, &)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def context(hash)
|
|
122
|
+
scope.merge_context(hash)
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def user=(user)
|
|
126
|
+
scope.user = user
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def tags(hash)
|
|
130
|
+
scope.merge_tags(hash)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def add_breadcrumb(message, category: "custom", level: "info", data: nil)
|
|
134
|
+
client.add_breadcrumb(message, category: category, level: level, data: data)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def flush(timeout = 5)
|
|
138
|
+
client.flush(timeout)
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def shutdown(timeout = nil)
|
|
142
|
+
@client&.shutdown(timeout || configuration.shutdown_timeout)
|
|
143
|
+
rescue StandardError
|
|
144
|
+
nil
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def verify
|
|
148
|
+
client.verify
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def test_events
|
|
152
|
+
client.test_events
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def clear_test_events
|
|
156
|
+
client.clear_test_events
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# Forgets configuration, client and the current scope. For tests.
|
|
160
|
+
def reset!
|
|
161
|
+
shutdown(0.5)
|
|
162
|
+
LOCK.synchronize do
|
|
163
|
+
@client = nil
|
|
164
|
+
@configuration = nil
|
|
165
|
+
end
|
|
166
|
+
clear_scope
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
require_relative "goodsorcery/railtie" if defined?(Rails::Railtie)
|
|
172
|
+
|
|
173
|
+
if defined?(Sidekiq)
|
|
174
|
+
require_relative "goodsorcery/integrations/sidekiq"
|
|
175
|
+
GoodSorcery::Integrations::Sidekiq.install
|
|
176
|
+
end
|
data/plugins.rb
ADDED
metadata
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: goodsorcery
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Philip Q Nguyen
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies: []
|
|
12
|
+
description: Reports exceptions from Ruby and Rails apps to Good Sorcery. Filters
|
|
13
|
+
sensitive data in-process and delivers events in batches from a background thread,
|
|
14
|
+
without blocking the host app.
|
|
15
|
+
email:
|
|
16
|
+
- 5519675+philipqnguyen@users.noreply.github.com
|
|
17
|
+
executables: []
|
|
18
|
+
extensions: []
|
|
19
|
+
extra_rdoc_files: []
|
|
20
|
+
files:
|
|
21
|
+
- CHANGELOG.md
|
|
22
|
+
- LICENSE
|
|
23
|
+
- README.md
|
|
24
|
+
- lib/generators/goodsorcery/install/credentials_api_key.rb
|
|
25
|
+
- lib/generators/goodsorcery/install/install_generator.rb
|
|
26
|
+
- lib/generators/goodsorcery/install/templates/initializer.rb
|
|
27
|
+
- lib/goodsorcery.rb
|
|
28
|
+
- lib/goodsorcery/backtrace/code_context.rb
|
|
29
|
+
- lib/goodsorcery/backtrace/line_cache.rb
|
|
30
|
+
- lib/goodsorcery/backtrace/parser.rb
|
|
31
|
+
- lib/goodsorcery/backtrace/paths.rb
|
|
32
|
+
- lib/goodsorcery/bundler_plugin.rb
|
|
33
|
+
- lib/goodsorcery/client.rb
|
|
34
|
+
- lib/goodsorcery/configuration.rb
|
|
35
|
+
- lib/goodsorcery/configuration/validation.rb
|
|
36
|
+
- lib/goodsorcery/defaults.rb
|
|
37
|
+
- lib/goodsorcery/delivery.rb
|
|
38
|
+
- lib/goodsorcery/delivery/active_job_queue.rb
|
|
39
|
+
- lib/goodsorcery/delivery/async.rb
|
|
40
|
+
- lib/goodsorcery/delivery/backoff.rb
|
|
41
|
+
- lib/goodsorcery/delivery/custom.rb
|
|
42
|
+
- lib/goodsorcery/delivery/event_queue.rb
|
|
43
|
+
- lib/goodsorcery/delivery/sync.rb
|
|
44
|
+
- lib/goodsorcery/delivery/test.rb
|
|
45
|
+
- lib/goodsorcery/delivery/worker.rb
|
|
46
|
+
- lib/goodsorcery/delivery_job.rb
|
|
47
|
+
- lib/goodsorcery/env_flag.rb
|
|
48
|
+
- lib/goodsorcery/environment_gate.rb
|
|
49
|
+
- lib/goodsorcery/errors.rb
|
|
50
|
+
- lib/goodsorcery/event/breadcrumb.rb
|
|
51
|
+
- lib/goodsorcery/event/builder.rb
|
|
52
|
+
- lib/goodsorcery/event/cause_chain.rb
|
|
53
|
+
- lib/goodsorcery/event/exception_section.rb
|
|
54
|
+
- lib/goodsorcery/event/fields.rb
|
|
55
|
+
- lib/goodsorcery/event/job_section.rb
|
|
56
|
+
- lib/goodsorcery/event/request_section.rb
|
|
57
|
+
- lib/goodsorcery/event/runtime_context.rb
|
|
58
|
+
- lib/goodsorcery/event/tag_set.rb
|
|
59
|
+
- lib/goodsorcery/event/user_section.rb
|
|
60
|
+
- lib/goodsorcery/event_filter.rb
|
|
61
|
+
- lib/goodsorcery/event_pipeline.rb
|
|
62
|
+
- lib/goodsorcery/event_serializer.rb
|
|
63
|
+
- lib/goodsorcery/exception_coercion.rb
|
|
64
|
+
- lib/goodsorcery/extra_filter_probe.rb
|
|
65
|
+
- lib/goodsorcery/ignore_list.rb
|
|
66
|
+
- lib/goodsorcery/install_check.rb
|
|
67
|
+
- lib/goodsorcery/integrations.rb
|
|
68
|
+
- lib/goodsorcery/integrations/action_cable.rb
|
|
69
|
+
- lib/goodsorcery/integrations/active_job.rb
|
|
70
|
+
- lib/goodsorcery/integrations/active_job/job_details.rb
|
|
71
|
+
- lib/goodsorcery/integrations/rails.rb
|
|
72
|
+
- lib/goodsorcery/integrations/rails/controller_action.rb
|
|
73
|
+
- lib/goodsorcery/integrations/rails/controller_enricher.rb
|
|
74
|
+
- lib/goodsorcery/integrations/rails/error_subscriber.rb
|
|
75
|
+
- lib/goodsorcery/integrations/rails/notification_breadcrumbs.rb
|
|
76
|
+
- lib/goodsorcery/integrations/rails/sql_statement.rb
|
|
77
|
+
- lib/goodsorcery/integrations/rails/user_lookup.rb
|
|
78
|
+
- lib/goodsorcery/integrations/rake.rb
|
|
79
|
+
- lib/goodsorcery/integrations/sidekiq.rb
|
|
80
|
+
- lib/goodsorcery/integrations/sidekiq/job_details.rb
|
|
81
|
+
- lib/goodsorcery/job_arguments.rb
|
|
82
|
+
- lib/goodsorcery/key_filter.rb
|
|
83
|
+
- lib/goodsorcery/log.rb
|
|
84
|
+
- lib/goodsorcery/masked_key.rb
|
|
85
|
+
- lib/goodsorcery/rack/middleware.rb
|
|
86
|
+
- lib/goodsorcery/rack/request_details.rb
|
|
87
|
+
- lib/goodsorcery/rack/request_enricher.rb
|
|
88
|
+
- lib/goodsorcery/rails_filter_parameters.rb
|
|
89
|
+
- lib/goodsorcery/railtie.rb
|
|
90
|
+
- lib/goodsorcery/release_detector.rb
|
|
91
|
+
- lib/goodsorcery/reported_mark.rb
|
|
92
|
+
- lib/goodsorcery/sanitizer.rb
|
|
93
|
+
- lib/goodsorcery/scope.rb
|
|
94
|
+
- lib/goodsorcery/status_report.rb
|
|
95
|
+
- lib/goodsorcery/tasks.rb
|
|
96
|
+
- lib/goodsorcery/test_event.rb
|
|
97
|
+
- lib/goodsorcery/text.rb
|
|
98
|
+
- lib/goodsorcery/transport.rb
|
|
99
|
+
- lib/goodsorcery/transport/batch_chunks.rb
|
|
100
|
+
- lib/goodsorcery/transport/connection.rb
|
|
101
|
+
- lib/goodsorcery/transport/result.rb
|
|
102
|
+
- lib/goodsorcery/verification.rb
|
|
103
|
+
- lib/goodsorcery/version.rb
|
|
104
|
+
- plugins.rb
|
|
105
|
+
homepage: https://app.goodsorcery.com
|
|
106
|
+
licenses:
|
|
107
|
+
- MIT
|
|
108
|
+
metadata:
|
|
109
|
+
rubygems_mfa_required: 'true'
|
|
110
|
+
source_code_uri: https://github.com/creativesorcery/goodsorcery-ruby
|
|
111
|
+
changelog_uri: https://github.com/creativesorcery/goodsorcery-ruby/blob/main/CHANGELOG.md
|
|
112
|
+
bug_tracker_uri: https://github.com/creativesorcery/goodsorcery-ruby/issues
|
|
113
|
+
rdoc_options: []
|
|
114
|
+
require_paths:
|
|
115
|
+
- lib
|
|
116
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
117
|
+
requirements:
|
|
118
|
+
- - ">="
|
|
119
|
+
- !ruby/object:Gem::Version
|
|
120
|
+
version: '3.2'
|
|
121
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
122
|
+
requirements:
|
|
123
|
+
- - ">="
|
|
124
|
+
- !ruby/object:Gem::Version
|
|
125
|
+
version: '0'
|
|
126
|
+
requirements: []
|
|
127
|
+
rubygems_version: 4.0.16
|
|
128
|
+
specification_version: 4
|
|
129
|
+
summary: Error reporting client for the Good Sorcery error tracker.
|
|
130
|
+
test_files: []
|