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.
Files changed (80) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +10 -0
  3. data/LICENSE +21 -0
  4. data/README.md +104 -0
  5. data/docs/configuration.md +160 -0
  6. data/docs/integrations.md +149 -0
  7. data/docs/releasing.md +23 -0
  8. data/docs/verification.md +85 -0
  9. data/lib/hawk/boundary.rb +26 -0
  10. data/lib/hawk/breadcrumbs/logger.rb +64 -0
  11. data/lib/hawk/breadcrumbs/net_http.rb +63 -0
  12. data/lib/hawk/breadcrumbs/rails.rb +24 -0
  13. data/lib/hawk/breadcrumbs.rb +92 -0
  14. data/lib/hawk/client.rb +175 -0
  15. data/lib/hawk/configuration.rb +138 -0
  16. data/lib/hawk/delayed_job.rb +61 -0
  17. data/lib/hawk/delivery.rb +113 -0
  18. data/lib/hawk/diagnostics.rb +53 -0
  19. data/lib/hawk/event.rb +136 -0
  20. data/lib/hawk/filter.rb +36 -0
  21. data/lib/hawk/filtered_fields.rb +56 -0
  22. data/lib/hawk/framework_filter.rb +16 -0
  23. data/lib/hawk/hook.rb +12 -0
  24. data/lib/hawk/job_context.rb +89 -0
  25. data/lib/hawk/json_value.rb +77 -0
  26. data/lib/hawk/process_hooks.rb +24 -0
  27. data/lib/hawk/rack/body.rb +76 -0
  28. data/lib/hawk/rack.rb +71 -0
  29. data/lib/hawk/rails/action_cable.rb +79 -0
  30. data/lib/hawk/rails/active_job.rb +74 -0
  31. data/lib/hawk/rails/error_subscriber.rb +38 -0
  32. data/lib/hawk/rails/integration.rb +51 -0
  33. data/lib/hawk/rails/payload_filter.rb +34 -0
  34. data/lib/hawk/rails.rb +5 -0
  35. data/lib/hawk/rake.rb +29 -0
  36. data/lib/hawk/release.rb +31 -0
  37. data/lib/hawk/resque.rb +77 -0
  38. data/lib/hawk/scope.rb +108 -0
  39. data/lib/hawk/scope_store.rb +55 -0
  40. data/lib/hawk/sidekiq.rb +80 -0
  41. data/lib/hawk/source.rb +83 -0
  42. data/lib/hawk/token.rb +53 -0
  43. data/lib/hawk/transport.rb +111 -0
  44. data/lib/hawk/version.rb +5 -0
  45. data/lib/hawk.rb +85 -0
  46. data/sig/hawk/boundary.rbs +7 -0
  47. data/sig/hawk/breadcrumbs/logger.rbs +17 -0
  48. data/sig/hawk/breadcrumbs/net_http.rbs +16 -0
  49. data/sig/hawk/breadcrumbs/rails.rbs +7 -0
  50. data/sig/hawk/breadcrumbs.rbs +13 -0
  51. data/sig/hawk/client.rbs +41 -0
  52. data/sig/hawk/configuration.rbs +61 -0
  53. data/sig/hawk/delayed_job.rbs +24 -0
  54. data/sig/hawk/delivery.rbs +27 -0
  55. data/sig/hawk/diagnostics.rbs +24 -0
  56. data/sig/hawk/event.rbs +24 -0
  57. data/sig/hawk/filter.rbs +13 -0
  58. data/sig/hawk/filtered_fields.rbs +11 -0
  59. data/sig/hawk/framework_filter.rbs +5 -0
  60. data/sig/hawk/hook.rbs +5 -0
  61. data/sig/hawk/job_context.rbs +15 -0
  62. data/sig/hawk/json_value.rbs +17 -0
  63. data/sig/hawk/process_hooks.rbs +7 -0
  64. data/sig/hawk/rack.rbs +74 -0
  65. data/sig/hawk/rails/action_cable.rbs +40 -0
  66. data/sig/hawk/rails/active_job.rbs +34 -0
  67. data/sig/hawk/rails/error_subscriber.rbs +9 -0
  68. data/sig/hawk/rails/payload_filter.rbs +16 -0
  69. data/sig/hawk/rails.rbs +26 -0
  70. data/sig/hawk/rake.rbs +13 -0
  71. data/sig/hawk/release.rbs +6 -0
  72. data/sig/hawk/resque.rbs +25 -0
  73. data/sig/hawk/scope.rbs +31 -0
  74. data/sig/hawk/scope_store.rbs +15 -0
  75. data/sig/hawk/sidekiq.rbs +29 -0
  76. data/sig/hawk/source.rbs +18 -0
  77. data/sig/hawk/token.rbs +14 -0
  78. data/sig/hawk/transport.rbs +32 -0
  79. data/sig/hawk.rbs +16 -0
  80. metadata +223 -0
@@ -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
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hawk
4
+ VERSION = "0.1.0"
5
+ end
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,7 @@
1
+ module Hawk
2
+ module Boundary
3
+ def self.run: [A] (Client, kind: Symbol, metadata: payload, ?inherit: bool) { () -> A } -> A
4
+ def self.resume: [A] (Client, Scope) { () -> A } -> A
5
+ private def self.protect: [A] (Client, Symbol) { () -> A } -> A
6
+ end
7
+ end
@@ -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,7 @@
1
+ module Hawk::Breadcrumbs
2
+ module Rails
3
+ self.@installed: bool?
4
+ EVENTS: Regexp
5
+ def self.install: () -> void
6
+ end
7
+ 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
@@ -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
@@ -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
@@ -0,0 +1,13 @@
1
+ module Hawk
2
+ class Filter
3
+ SENSITIVE: Regexp
4
+ @patterns: Array[Regexp]
5
+ def initialize: (Configuration) -> void
6
+ def call: (json) -> json
7
+
8
+ private
9
+
10
+ def filter: (json) -> json
11
+ def sensitive?: (String) -> bool
12
+ end
13
+ end
@@ -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
@@ -0,0 +1,5 @@
1
+ module Hawk
2
+ module FrameworkFilter
3
+ def self.call: (Configuration, payload, ?Array[Array[String]]) -> payload?
4
+ end
5
+ end
data/sig/hawk/hook.rbs ADDED
@@ -0,0 +1,5 @@
1
+ module Hawk
2
+ module Hook
3
+ def self.call: [A] () { () -> A } -> A?
4
+ end
5
+ end
@@ -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