hawk-ruby 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 +10 -0
- data/LICENSE +21 -0
- data/README.md +104 -0
- data/docs/configuration.md +160 -0
- data/docs/integrations.md +149 -0
- data/docs/releasing.md +23 -0
- data/docs/verification.md +85 -0
- data/lib/hawk/boundary.rb +26 -0
- data/lib/hawk/breadcrumbs/logger.rb +64 -0
- data/lib/hawk/breadcrumbs/net_http.rb +63 -0
- data/lib/hawk/breadcrumbs/rails.rb +24 -0
- data/lib/hawk/breadcrumbs.rb +92 -0
- data/lib/hawk/client.rb +175 -0
- data/lib/hawk/configuration.rb +138 -0
- data/lib/hawk/delayed_job.rb +61 -0
- data/lib/hawk/delivery.rb +113 -0
- data/lib/hawk/diagnostics.rb +53 -0
- data/lib/hawk/event.rb +136 -0
- data/lib/hawk/filter.rb +36 -0
- data/lib/hawk/filtered_fields.rb +56 -0
- data/lib/hawk/framework_filter.rb +16 -0
- data/lib/hawk/hook.rb +12 -0
- data/lib/hawk/job_context.rb +89 -0
- data/lib/hawk/json_value.rb +77 -0
- data/lib/hawk/process_hooks.rb +24 -0
- data/lib/hawk/rack/body.rb +76 -0
- data/lib/hawk/rack.rb +71 -0
- data/lib/hawk/rails/action_cable.rb +79 -0
- data/lib/hawk/rails/active_job.rb +74 -0
- data/lib/hawk/rails/error_subscriber.rb +38 -0
- data/lib/hawk/rails/integration.rb +51 -0
- data/lib/hawk/rails/payload_filter.rb +34 -0
- data/lib/hawk/rails.rb +5 -0
- data/lib/hawk/rake.rb +29 -0
- data/lib/hawk/release.rb +31 -0
- data/lib/hawk/resque.rb +77 -0
- data/lib/hawk/scope.rb +108 -0
- data/lib/hawk/scope_store.rb +55 -0
- data/lib/hawk/sidekiq.rb +80 -0
- data/lib/hawk/source.rb +83 -0
- data/lib/hawk/token.rb +53 -0
- data/lib/hawk/transport.rb +111 -0
- data/lib/hawk/version.rb +5 -0
- data/lib/hawk.rb +85 -0
- data/sig/hawk/boundary.rbs +7 -0
- data/sig/hawk/breadcrumbs/logger.rbs +17 -0
- data/sig/hawk/breadcrumbs/net_http.rbs +16 -0
- data/sig/hawk/breadcrumbs/rails.rbs +7 -0
- data/sig/hawk/breadcrumbs.rbs +13 -0
- data/sig/hawk/client.rbs +41 -0
- data/sig/hawk/configuration.rbs +61 -0
- data/sig/hawk/delayed_job.rbs +24 -0
- data/sig/hawk/delivery.rbs +27 -0
- data/sig/hawk/diagnostics.rbs +24 -0
- data/sig/hawk/event.rbs +24 -0
- data/sig/hawk/filter.rbs +13 -0
- data/sig/hawk/filtered_fields.rbs +11 -0
- data/sig/hawk/framework_filter.rbs +5 -0
- data/sig/hawk/hook.rbs +5 -0
- data/sig/hawk/job_context.rbs +15 -0
- data/sig/hawk/json_value.rbs +17 -0
- data/sig/hawk/process_hooks.rbs +7 -0
- data/sig/hawk/rack.rbs +74 -0
- data/sig/hawk/rails/action_cable.rbs +40 -0
- data/sig/hawk/rails/active_job.rbs +34 -0
- data/sig/hawk/rails/error_subscriber.rbs +9 -0
- data/sig/hawk/rails/payload_filter.rbs +16 -0
- data/sig/hawk/rails.rbs +26 -0
- data/sig/hawk/rake.rbs +13 -0
- data/sig/hawk/release.rbs +6 -0
- data/sig/hawk/resque.rbs +25 -0
- data/sig/hawk/scope.rbs +31 -0
- data/sig/hawk/scope_store.rbs +15 -0
- data/sig/hawk/sidekiq.rbs +29 -0
- data/sig/hawk/source.rbs +18 -0
- data/sig/hawk/token.rbs +14 -0
- data/sig/hawk/transport.rbs +32 -0
- data/sig/hawk.rbs +16 -0
- metadata +223 -0
data/lib/hawk/source.rb
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Hawk
|
|
4
|
+
# Backtraces remain useful when source files are unavailable or excluded.
|
|
5
|
+
class Source
|
|
6
|
+
def initialize(configuration)
|
|
7
|
+
@enabled = configuration.send_source
|
|
8
|
+
@roots = configuration.source_roots.filter_map { |root| realpath(root) }
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def frames(exception)
|
|
12
|
+
locations = exception.backtrace_locations
|
|
13
|
+
if locations && !locations.empty?
|
|
14
|
+
locations.take(100).filter_map { |location| location_frame(location) }
|
|
15
|
+
else
|
|
16
|
+
(exception.backtrace || []).take(100).filter_map { |line| parse(line) }
|
|
17
|
+
end
|
|
18
|
+
rescue StandardError
|
|
19
|
+
[]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def location_frame(location)
|
|
25
|
+
path = location.absolute_path || location.path
|
|
26
|
+
frame(path, location.lineno, location.base_label) if path
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def realpath(path)
|
|
30
|
+
File.realpath(path)
|
|
31
|
+
rescue SystemCallError, ArgumentError
|
|
32
|
+
nil
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def parse(value)
|
|
36
|
+
match = /\A(.+):(\d+)(?::in [`'](.*)[`'])?\z/.match(value)
|
|
37
|
+
return unless match
|
|
38
|
+
|
|
39
|
+
frame(match[1].to_s, match[2].to_i, match[3])
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def frame(path, line, function)
|
|
43
|
+
return unless line.positive?
|
|
44
|
+
|
|
45
|
+
# @type var result: payload
|
|
46
|
+
result = { "file" => path, "line" => line }
|
|
47
|
+
result["function"] = function if function
|
|
48
|
+
snippets = snippets(path, line)
|
|
49
|
+
result["sourceCode"] = snippets unless snippets.empty?
|
|
50
|
+
result
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def snippets(path, line)
|
|
54
|
+
return [] unless @enabled
|
|
55
|
+
|
|
56
|
+
resolved = readable_path(path)
|
|
57
|
+
return [] unless resolved
|
|
58
|
+
|
|
59
|
+
content = File.binread(resolved, 1_048_577)
|
|
60
|
+
return [] if content.bytesize > 1_048_576
|
|
61
|
+
|
|
62
|
+
excerpt(content, line)
|
|
63
|
+
rescue SystemCallError, IOError, ArgumentError
|
|
64
|
+
[]
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def readable_path(path)
|
|
68
|
+
resolved = realpath(path)
|
|
69
|
+
return unless resolved && @roots.any? { |root| resolved.start_with?("#{root}/") }
|
|
70
|
+
|
|
71
|
+
resolved if File.file?(resolved) && File.size(resolved) <= 1_048_576
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def excerpt(content, line)
|
|
75
|
+
lines = content.force_encoding(Encoding::UTF_8).scrub.lines
|
|
76
|
+
first = [line - 6, 0].max
|
|
77
|
+
width = [line + 5 - first, 11].min
|
|
78
|
+
(lines[first, width] || []).each_with_index.map do |text, index|
|
|
79
|
+
{ "line" => first + index + 1, "content" => text.chomp }
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
data/lib/hawk/token.rb
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "base64"
|
|
4
|
+
require "json"
|
|
5
|
+
require "uri"
|
|
6
|
+
|
|
7
|
+
module Hawk
|
|
8
|
+
class ConfigurationError < ArgumentError; end
|
|
9
|
+
|
|
10
|
+
# Resolves collector identity without exposing the integration secret.
|
|
11
|
+
class Token
|
|
12
|
+
LABEL = /\A[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\z/i
|
|
13
|
+
|
|
14
|
+
def self.decode(value)
|
|
15
|
+
raise ConfigurationError, "Invalid Hawk integration token" if value.bytesize > 8192
|
|
16
|
+
|
|
17
|
+
# @type var data: top
|
|
18
|
+
data = JSON.parse(Base64.strict_decode64(value))
|
|
19
|
+
id = integration_id(data)
|
|
20
|
+
raise ConfigurationError, "Invalid Hawk integration token" unless id
|
|
21
|
+
|
|
22
|
+
new(id)
|
|
23
|
+
rescue JSON::ParserError, ArgumentError
|
|
24
|
+
raise ConfigurationError, "Invalid Hawk integration token"
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def self.integration_id(data)
|
|
28
|
+
case data
|
|
29
|
+
when Hash
|
|
30
|
+
id = data["integrationId"]
|
|
31
|
+
case id
|
|
32
|
+
when String
|
|
33
|
+
id if LABEL.match?(id) && valid_secret?(data["secret"])
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def self.valid_secret?(value)
|
|
39
|
+
case value
|
|
40
|
+
when String then !value.empty?
|
|
41
|
+
else false
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def initialize(integration_id)
|
|
46
|
+
@integration_id = integration_id
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def endpoint
|
|
50
|
+
URI::HTTPS.build(host: "#{@integration_id}.k1.hawk.so")
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "net/http"
|
|
4
|
+
require "timeout"
|
|
5
|
+
require "time"
|
|
6
|
+
|
|
7
|
+
module Hawk
|
|
8
|
+
# Every send performs at most one POST, with a bounded response and deadline.
|
|
9
|
+
class Transport
|
|
10
|
+
class ResponseTooLarge < StandardError; end
|
|
11
|
+
|
|
12
|
+
def initialize(configuration)
|
|
13
|
+
configuration.validate!
|
|
14
|
+
@configuration = configuration
|
|
15
|
+
uri = configuration.collector_uri if configuration.enabled?
|
|
16
|
+
@uri = uri.is_a?(URI::HTTP) ? uri : nil
|
|
17
|
+
reset
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def available?
|
|
21
|
+
reset if @pid != Process.pid
|
|
22
|
+
@mutex.synchronize { !@uri.nil? && monotonic >= @cooldown_until }
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def send(encoded)
|
|
26
|
+
uri = @uri
|
|
27
|
+
return :limited unless uri && available?
|
|
28
|
+
|
|
29
|
+
Breadcrumbs.guard(:sdk) { Timeout.timeout(5.0) { request(encoded, uri) } }
|
|
30
|
+
rescue StandardError
|
|
31
|
+
:failed
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def reset
|
|
37
|
+
@mutex = Mutex.new
|
|
38
|
+
@cooldown_until = 0.0
|
|
39
|
+
@pid = Process.pid
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def monotonic
|
|
43
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def connection(uri)
|
|
47
|
+
http = Net::HTTP.new(uri.hostname.to_s, uri.port, nil)
|
|
48
|
+
http.use_ssl = uri.is_a?(URI::HTTPS)
|
|
49
|
+
http.open_timeout = @configuration.connect_timeout
|
|
50
|
+
http.read_timeout = @configuration.read_timeout
|
|
51
|
+
http.write_timeout = @configuration.write_timeout
|
|
52
|
+
http.max_retries = 0
|
|
53
|
+
http
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def request(encoded, uri)
|
|
57
|
+
post = Net::HTTP::Post.new(uri.request_uri)
|
|
58
|
+
post["Content-Type"] = "application/json"
|
|
59
|
+
post.body = encoded
|
|
60
|
+
result = :failed
|
|
61
|
+
connection(uri).start do |http|
|
|
62
|
+
http.request(post) { |response| result = handle(response) }
|
|
63
|
+
end
|
|
64
|
+
result
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def handle(response)
|
|
68
|
+
case response.code
|
|
69
|
+
when "402", "429"
|
|
70
|
+
cooldown(response["Retry-After"])
|
|
71
|
+
:limited
|
|
72
|
+
when "200"
|
|
73
|
+
success?(response_body(response)) ? :accepted : :failed
|
|
74
|
+
else :failed
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def response_body(response)
|
|
79
|
+
content = +""
|
|
80
|
+
response.read_body do |part|
|
|
81
|
+
raise ResponseTooLarge, "Collector response exceeds limit" if content.bytesize + part.bytesize > 16_384
|
|
82
|
+
|
|
83
|
+
content << part
|
|
84
|
+
end
|
|
85
|
+
content
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def success?(content)
|
|
89
|
+
# @type var data: top
|
|
90
|
+
data = JSON.parse(content)
|
|
91
|
+
case data
|
|
92
|
+
when Hash then JSONValue.object(data).values_at("code", "error") == [200, false]
|
|
93
|
+
else false
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def cooldown(header)
|
|
98
|
+
delay = retry_delay(header)
|
|
99
|
+
@mutex.synchronize { @cooldown_until = monotonic + delay.clamp(0.0, 300.0) }
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def retry_delay(header)
|
|
103
|
+
return @configuration.limit_cooldown unless header
|
|
104
|
+
return header.to_f if /\A\d+\z/.match?(header)
|
|
105
|
+
|
|
106
|
+
Time.httpdate(header) - Time.now
|
|
107
|
+
rescue ArgumentError
|
|
108
|
+
@configuration.limit_cooldown
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
data/lib/hawk/version.rb
ADDED
data/lib/hawk.rb
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "hawk/version"
|
|
4
|
+
require_relative "hawk/token"
|
|
5
|
+
require_relative "hawk/configuration"
|
|
6
|
+
require_relative "hawk/release"
|
|
7
|
+
require_relative "hawk/json_value"
|
|
8
|
+
require_relative "hawk/filter"
|
|
9
|
+
require_relative "hawk/hook"
|
|
10
|
+
require_relative "hawk/filtered_fields"
|
|
11
|
+
require_relative "hawk/framework_filter"
|
|
12
|
+
require_relative "hawk/source"
|
|
13
|
+
require_relative "hawk/event"
|
|
14
|
+
require_relative "hawk/diagnostics"
|
|
15
|
+
require_relative "hawk/scope"
|
|
16
|
+
require_relative "hawk/scope_store"
|
|
17
|
+
require_relative "hawk/client"
|
|
18
|
+
require_relative "hawk/breadcrumbs"
|
|
19
|
+
require_relative "hawk/job_context"
|
|
20
|
+
require_relative "hawk/boundary"
|
|
21
|
+
require_relative "hawk/transport"
|
|
22
|
+
require_relative "hawk/delivery"
|
|
23
|
+
require_relative "hawk/process_hooks"
|
|
24
|
+
|
|
25
|
+
# The default client offers the same capture API as independent project clients.
|
|
26
|
+
module Hawk
|
|
27
|
+
class << self
|
|
28
|
+
attr_reader :client
|
|
29
|
+
|
|
30
|
+
def init
|
|
31
|
+
configuration = Configuration.new
|
|
32
|
+
yield configuration
|
|
33
|
+
Rails.configure(configuration) if defined?(Hawk::Rails)
|
|
34
|
+
replacement = Client.build(configuration)
|
|
35
|
+
@client&.close
|
|
36
|
+
@client = replacement
|
|
37
|
+
Breadcrumbs.install(configuration)
|
|
38
|
+
ProcessHooks.install if configuration.enabled? && configuration.global_errors
|
|
39
|
+
replacement
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def capture_exception(exception, context: {}, user: nil, level: :error)
|
|
43
|
+
@client&.capture_exception(exception, context: context, user: user, level: level)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def capture_message(message, context: {}, user: nil, level: :info)
|
|
47
|
+
@client&.capture_message(message, context: context, user: user, level: level)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def set_context(context)
|
|
51
|
+
@client&.set_context(context)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def add_breadcrumb(entry)
|
|
55
|
+
@client&.add_breadcrumb(entry)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def set_user(user)
|
|
59
|
+
@client&.set_user(user)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def with_scope(&)
|
|
63
|
+
client = @client
|
|
64
|
+
client ? client.with_scope(&) : yield(Scope.new)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def capture(&)
|
|
68
|
+
client = @client
|
|
69
|
+
client ? client.capture(&) : yield
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def flush(timeout: nil)
|
|
73
|
+
client = @client
|
|
74
|
+
client ? client.flush(timeout: timeout || client.configuration.flush_timeout) : true
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def close(timeout: nil)
|
|
78
|
+
previous = @client
|
|
79
|
+
@client = nil
|
|
80
|
+
previous ? previous.close(timeout: timeout || previous.configuration.flush_timeout) : true
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
require_relative "hawk/rails/integration" if defined?(Rails::Railtie)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module Hawk::Breadcrumbs
|
|
2
|
+
interface _Logger
|
|
3
|
+
def level: () -> Integer
|
|
4
|
+
def add: (Integer?, ?top, ?String?) ?{ () -> top } -> bool
|
|
5
|
+
end
|
|
6
|
+
module Logger
|
|
7
|
+
LEVELS: Array[Symbol]
|
|
8
|
+
def self.install: () -> void
|
|
9
|
+
def self.record: (Hawk::Client, Integer, top) -> void
|
|
10
|
+
def self.empty_message?: (top) -> bool
|
|
11
|
+
def self.message: (top, String?) -> top
|
|
12
|
+
module Methods : _Logger
|
|
13
|
+
def add: (Integer?, ?top, ?String?) ?{ () -> top } -> bool
|
|
14
|
+
alias log add
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
module Hawk::Breadcrumbs
|
|
2
|
+
interface _HTTP
|
|
3
|
+
def start: [A] () ?{ (::Net::HTTP) -> A } -> (::Net::HTTP | A)
|
|
4
|
+
def address: () -> String
|
|
5
|
+
def request: (::Net::HTTPRequest, ?String?) ?{ (::Net::HTTPResponse) -> top } -> ::Net::HTTPResponse
|
|
6
|
+
end
|
|
7
|
+
module NetHTTP
|
|
8
|
+
def self.install: () -> void
|
|
9
|
+
def self.record: (Hawk::Client, ::Net::HTTPRequest, String, String?, Float) -> void
|
|
10
|
+
def self.connection_failed: (Hawk::Client, String, Float) -> void
|
|
11
|
+
module Methods : _HTTP
|
|
12
|
+
def start: [A] () ?{ (::Net::HTTP) -> A } -> (::Net::HTTP | A)
|
|
13
|
+
def request: (::Net::HTTPRequest, ?String?) ?{ (::Net::HTTPResponse) -> top } -> ::Net::HTTPResponse
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
module Hawk
|
|
2
|
+
module Breadcrumbs
|
|
3
|
+
def self.install: (Configuration) -> void
|
|
4
|
+
def self.guard: [A] (Symbol) { () -> A } -> A
|
|
5
|
+
def self.suppressed?: (Symbol) -> bool
|
|
6
|
+
def self.client: (Symbol) -> Client?
|
|
7
|
+
def self.add: (Client, raw_context) -> void
|
|
8
|
+
private
|
|
9
|
+
def self.filtered: (Configuration, raw_context) -> payload?
|
|
10
|
+
def self.framework_filtered: (Configuration, payload) -> payload?
|
|
11
|
+
def self.enabled?: (Configuration, Symbol) -> bool
|
|
12
|
+
end
|
|
13
|
+
end
|
data/sig/hawk/client.rbs
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
module Hawk
|
|
2
|
+
interface _Delivery
|
|
3
|
+
def enqueue: (String, String) -> bool
|
|
4
|
+
def flush: (timeout: Float) -> bool
|
|
5
|
+
def close: (timeout: Float) -> bool
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
class Client
|
|
9
|
+
@delivery: _Delivery
|
|
10
|
+
@store: ScopeStore
|
|
11
|
+
@closed: bool
|
|
12
|
+
attr_reader configuration: Configuration
|
|
13
|
+
attr_reader diagnostics: Diagnostics
|
|
14
|
+
def self.build: (Configuration) -> Client
|
|
15
|
+
def initialize: (Configuration, delivery: _Delivery, ?diagnostics: Diagnostics?) -> void
|
|
16
|
+
def current_scope: () -> Scope
|
|
17
|
+
def enabled?: () -> bool
|
|
18
|
+
def using_scope: [A] (Scope) { () -> A } -> A
|
|
19
|
+
def set_context: (raw_context) -> void
|
|
20
|
+
def add_breadcrumb: (raw_context) -> void
|
|
21
|
+
def set_user: (raw_context?) -> void
|
|
22
|
+
def with_scope: [A] () { (Scope) -> A } -> A
|
|
23
|
+
def with_boundary: [A] (kind: Symbol, metadata: payload, ?inherit: bool) { () -> A } -> A
|
|
24
|
+
def capture_exception: (Exception, ?context: raw_context, ?user: raw_context?, ?level: Symbol) -> String?
|
|
25
|
+
def capture_message: (String, ?context: raw_context, ?user: raw_context?, ?level: Symbol) -> String?
|
|
26
|
+
def capture: [A] () { () -> A } -> A
|
|
27
|
+
def report: (Exception, mechanism: String, ?context: payload, ?level: Symbol, ?handled: bool) -> String?
|
|
28
|
+
def remember_escape: (Exception) -> void
|
|
29
|
+
def consume_escape: (Exception) -> bool
|
|
30
|
+
def flush: (?timeout: Float) -> bool
|
|
31
|
+
def close: (?timeout: Float) -> bool
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
def boundary_scope: (Scope, Symbol, payload, bool) -> Scope
|
|
36
|
+
def dispatch: (?exception: Exception?, ?message: String?, ?context: raw_context, ?user: raw_context?, ?level: Symbol, ?addons: payload) -> String?
|
|
37
|
+
def eligible?: (Exception?) -> bool
|
|
38
|
+
def normal_termination?: (Exception) -> bool
|
|
39
|
+
def expected_request_error?: (Exception) -> bool
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
module Hawk
|
|
2
|
+
type raw_context = Hash[String | Symbol, top]
|
|
3
|
+
type payload = Hash[String, json]
|
|
4
|
+
type payload_hook = ^(payload) -> top
|
|
5
|
+
|
|
6
|
+
class Configuration
|
|
7
|
+
attr_accessor diagnostic_logger: _DiagnosticLogger?
|
|
8
|
+
attr_accessor token: String?
|
|
9
|
+
attr_accessor endpoint: String?
|
|
10
|
+
attr_accessor environment: String
|
|
11
|
+
attr_accessor enabled_environments: Array[String]?
|
|
12
|
+
attr_accessor release: String?
|
|
13
|
+
attr_accessor detect_release: bool
|
|
14
|
+
attr_accessor sample_rate: Float
|
|
15
|
+
attr_accessor delivery_mode: Symbol
|
|
16
|
+
attr_accessor queue_capacity: Integer
|
|
17
|
+
attr_accessor source_roots: Array[String]
|
|
18
|
+
attr_accessor send_source: bool
|
|
19
|
+
attr_accessor connect_timeout: Float
|
|
20
|
+
attr_accessor read_timeout: Float
|
|
21
|
+
attr_accessor write_timeout: Float
|
|
22
|
+
attr_accessor flush_timeout: Float
|
|
23
|
+
attr_accessor limit_cooldown: Float
|
|
24
|
+
attr_accessor context: raw_context
|
|
25
|
+
attr_accessor user: raw_context?
|
|
26
|
+
attr_accessor ignored_exceptions: Array[String]
|
|
27
|
+
attr_accessor filter_parameters: Array[String | Regexp]
|
|
28
|
+
attr_accessor integrations: Hash[Symbol, bool]
|
|
29
|
+
attr_accessor global_errors: bool
|
|
30
|
+
attr_accessor before_send: payload_hook?
|
|
31
|
+
attr_accessor before_breadcrumb: payload_hook?
|
|
32
|
+
attr_accessor framework_filter: payload_hook?
|
|
33
|
+
attr_accessor diagnostic_callback: (^(Hash[Symbol, Integer]) -> void)?
|
|
34
|
+
attr_accessor propagate_job_context: bool
|
|
35
|
+
attr_accessor include_request_body: bool
|
|
36
|
+
attr_accessor include_job_arguments: bool
|
|
37
|
+
attr_accessor include_headers: bool
|
|
38
|
+
attr_accessor include_cookies: bool
|
|
39
|
+
attr_accessor breadcrumbs_logger: bool
|
|
40
|
+
attr_accessor breadcrumbs_http: bool
|
|
41
|
+
attr_accessor breadcrumbs_rails: bool
|
|
42
|
+
attr_accessor logger_error_level: Integer?
|
|
43
|
+
|
|
44
|
+
def initialize: () -> void
|
|
45
|
+
def validate!: () -> void
|
|
46
|
+
def enabled?: () -> bool
|
|
47
|
+
def collector_uri: () -> URI::Generic
|
|
48
|
+
def integration_enabled?: (Symbol) -> bool
|
|
49
|
+
|
|
50
|
+
private
|
|
51
|
+
|
|
52
|
+
def allowed_uri?: (URI::Generic) -> bool
|
|
53
|
+
def initialize_identity: () -> void
|
|
54
|
+
def initialize_delivery: () -> void
|
|
55
|
+
def initialize_privacy: () -> void
|
|
56
|
+
def initialize_hooks: () -> void
|
|
57
|
+
def validate_delivery: () -> void
|
|
58
|
+
def valid_number?: (top) -> bool
|
|
59
|
+
def validate_callbacks: () -> void
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
module Hawk
|
|
2
|
+
interface _DelayedJob
|
|
3
|
+
def id: () -> Integer?
|
|
4
|
+
def queue: () -> String?
|
|
5
|
+
def attempts: () -> Integer
|
|
6
|
+
def error: () -> Exception?
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
interface _DelayedLifecycle
|
|
10
|
+
def around: (Symbol) { (top, _DelayedJob) -> top } -> void
|
|
11
|
+
def after: (Symbol) { (top, _DelayedJob) -> top } -> void
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
module DelayedJob
|
|
15
|
+
def self.install: () -> void
|
|
16
|
+
def self.supported_version?: () -> bool
|
|
17
|
+
def self.client: () -> Client?
|
|
18
|
+
def self.run: [A] (_DelayedJob) { () -> A } -> A
|
|
19
|
+
def self.report: (_DelayedJob) -> void
|
|
20
|
+
AROUND: ^(top, _DelayedJob) ?{ () -> top } -> top
|
|
21
|
+
class Plugin
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module Hawk
|
|
2
|
+
class Delivery
|
|
3
|
+
@configuration: Configuration
|
|
4
|
+
@transport: _Transport
|
|
5
|
+
@diagnostics: Diagnostics
|
|
6
|
+
@mutex: Thread::Mutex
|
|
7
|
+
@condition: Thread::ConditionVariable
|
|
8
|
+
@queue: Array[String]
|
|
9
|
+
@pending: Integer
|
|
10
|
+
@worker: Thread?
|
|
11
|
+
@pid: Integer
|
|
12
|
+
@closed: bool
|
|
13
|
+
def initialize: (Configuration, transport: _Transport, diagnostics: Diagnostics) -> void
|
|
14
|
+
def enqueue: (String, String) -> bool
|
|
15
|
+
def flush: (timeout: Float) -> bool
|
|
16
|
+
def close: (timeout: Float) -> bool
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def reset: () -> void
|
|
21
|
+
def monotonic: () -> Float
|
|
22
|
+
def accept: (String) -> bool
|
|
23
|
+
def next_event: () -> String?
|
|
24
|
+
def work: () -> void
|
|
25
|
+
def deliver: (String) -> void
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
module Hawk
|
|
2
|
+
interface _DiagnosticLogger
|
|
3
|
+
def warn: (String) -> top
|
|
4
|
+
end
|
|
5
|
+
type diagnostic_hook = ^(Hash[Symbol, Integer]) -> void
|
|
6
|
+
|
|
7
|
+
class Diagnostics
|
|
8
|
+
@logger: _DiagnosticLogger?
|
|
9
|
+
@callback: (^(Hash[Symbol, Integer]) -> void)?
|
|
10
|
+
@pid: Integer
|
|
11
|
+
@mutex: Thread::Mutex
|
|
12
|
+
@counts: Hash[Symbol, Integer]
|
|
13
|
+
@notifying: bool
|
|
14
|
+
def initialize: (?diagnostic_hook?, ?logger: _DiagnosticLogger?) -> void
|
|
15
|
+
def increment: (Symbol) -> void
|
|
16
|
+
def snapshot: () -> Hash[Symbol, Integer]
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def notify: () -> void
|
|
21
|
+
def emit: () -> void
|
|
22
|
+
def reset: () -> void
|
|
23
|
+
end
|
|
24
|
+
end
|
data/sig/hawk/event.rbs
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
module Hawk
|
|
2
|
+
class Event
|
|
3
|
+
@addons: payload
|
|
4
|
+
@configuration: Configuration
|
|
5
|
+
@payload: payload
|
|
6
|
+
@filtered_paths: Array[Array[String]]
|
|
7
|
+
def initialize: (configuration: Configuration, id: String, ?exception: Exception?, ?message: String?, ?context: raw_context, ?user: raw_context?, ?breadcrumbs: Array[payload], ?addons: payload, ?level: Symbol, ?filtered_paths: Array[Array[String]]) -> void
|
|
8
|
+
def encode: () -> String?
|
|
9
|
+
|
|
10
|
+
private
|
|
11
|
+
|
|
12
|
+
def filtered_payload: () -> payload?
|
|
13
|
+
def title: (Exception) -> String
|
|
14
|
+
def metadata: (String, Symbol) -> payload
|
|
15
|
+
def attach_exception: (Exception) -> void
|
|
16
|
+
def causes: (Exception) -> Array[payload]
|
|
17
|
+
def valid_payload?: (payload) -> bool
|
|
18
|
+
def envelope: (payload) -> String
|
|
19
|
+
def bounded_envelope: (payload) -> String?
|
|
20
|
+
def trim: (payload, Symbol) -> void
|
|
21
|
+
def trim_sources: (payload) -> void
|
|
22
|
+
def keep_first: (payload, String, ?newest: bool) -> void
|
|
23
|
+
end
|
|
24
|
+
end
|
data/sig/hawk/filter.rbs
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
module Hawk
|
|
2
|
+
class FilteredFields
|
|
3
|
+
@entries: Array[[Array[String], String, json]]
|
|
4
|
+
def initialize: (payload, Array[Array[String]], ?containers_only: bool) -> void
|
|
5
|
+
def restore: (payload) { (String, json) -> json } -> payload
|
|
6
|
+
private
|
|
7
|
+
def extract: (payload, Array[String], bool) -> void
|
|
8
|
+
def container?: (json) -> bool
|
|
9
|
+
def parent_at: (payload, Array[String]) -> payload?
|
|
10
|
+
end
|
|
11
|
+
end
|
data/sig/hawk/hook.rbs
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module Hawk
|
|
2
|
+
module JobContext
|
|
3
|
+
def self.dump: (Client) -> payload?
|
|
4
|
+
def self.load: (top) -> payload?
|
|
5
|
+
def self.apply: (Client, top) -> void
|
|
6
|
+
private
|
|
7
|
+
def self.valid?: (top, Integer, Hash[Symbol, Integer]) -> bool
|
|
8
|
+
def self.valid_header?: (payload) -> bool
|
|
9
|
+
def self.object?: (top, ?optional: bool) -> bool
|
|
10
|
+
def self.valid_scalar?: (top) -> bool
|
|
11
|
+
def self.valid_key?: (top) -> bool
|
|
12
|
+
def self.valid_object?: (Hash[top, top], Integer, Hash[Symbol, Integer]) -> bool
|
|
13
|
+
def self.valid_array?: (Array[top], Integer, Hash[Symbol, Integer]) -> bool
|
|
14
|
+
end
|
|
15
|
+
end
|