tinymonrb 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/lib/tinymon/client.rb +60 -0
- data/lib/tinymon/event_builder.rb +43 -0
- data/lib/tinymon/integrations.rb +26 -0
- data/lib/tinymon/scope.rb +45 -0
- data/lib/tinymon/stacktrace.rb +77 -0
- data/lib/tinymon/transport.rb +89 -0
- data/lib/tinymon/version.rb +6 -0
- data/lib/tinymon.rb +64 -0
- data/lib/tinymonrb.rb +64 -0
- metadata +82 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: c33d3e807a92d0f19e975e8d384e2a6a9e78ed22e62c4f2fdf5a5c2e3ff953c7
|
|
4
|
+
data.tar.gz: 667a99ab8a3b6d3e08780c56e99ccbadbf0c748cd3c2524dfd8ecc78e8911b6b
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: '085fdbe62bc6c876ee0c15d40de22f7645141064d7f12cd9035789d2684bfcf3f19f7c1eeb0e0a830311df6eaaa219d3018997b0a0fb96576147a63fe0cd455d'
|
|
7
|
+
data.tar.gz: 13543ba9734ac10fc3a9ccda8b9c456d7d39e57314449f7583ab4dc48572c9d40051d0bd8f4cfe62d3660f74b23b3dcef5834fac20a464c709685eefd2f9af78
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "event_builder"
|
|
4
|
+
require_relative "scope"
|
|
5
|
+
require_relative "transport"
|
|
6
|
+
|
|
7
|
+
module Tinymon
|
|
8
|
+
class Client
|
|
9
|
+
DEFAULT_ENDPOINT = "https://console.tinymon.dev/api/ingest"
|
|
10
|
+
|
|
11
|
+
def initialize(dsn:, endpoint: nil, environment: nil, release: nil, sample_rate: 1.0, before_send: nil)
|
|
12
|
+
@dsn = dsn
|
|
13
|
+
@endpoint = endpoint || DEFAULT_ENDPOINT
|
|
14
|
+
@environment = environment
|
|
15
|
+
@release = release
|
|
16
|
+
@sample_rate = sample_rate
|
|
17
|
+
@before_send = before_send
|
|
18
|
+
@transport = Transport.new(@endpoint, dsn)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def capture_exception(exception)
|
|
22
|
+
return if rand > @sample_rate
|
|
23
|
+
snap = SCOPE.snapshot
|
|
24
|
+
event = EventBuilder.build(
|
|
25
|
+
exception,
|
|
26
|
+
release: @release,
|
|
27
|
+
environment: @environment,
|
|
28
|
+
user: snap[:user],
|
|
29
|
+
tags: snap[:tags],
|
|
30
|
+
breadcrumbs: snap[:breadcrumbs],
|
|
31
|
+
)
|
|
32
|
+
if @before_send
|
|
33
|
+
event = @before_send.call(event)
|
|
34
|
+
return if event.nil?
|
|
35
|
+
end
|
|
36
|
+
@transport.enqueue(event)
|
|
37
|
+
rescue StandardError
|
|
38
|
+
# SWALLOW. The SDK must never throw into the host app.
|
|
39
|
+
nil
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def capture_message(message, level: "info")
|
|
43
|
+
synthetic = StandardError.new(message)
|
|
44
|
+
snap = SCOPE.snapshot
|
|
45
|
+
event = EventBuilder.build(
|
|
46
|
+
synthetic,
|
|
47
|
+
release: @release,
|
|
48
|
+
environment: @environment,
|
|
49
|
+
user: snap[:user],
|
|
50
|
+
tags: snap[:tags],
|
|
51
|
+
breadcrumbs: snap[:breadcrumbs],
|
|
52
|
+
)
|
|
53
|
+
event["level"] = level
|
|
54
|
+
event["exception"]["type"] = "Message"
|
|
55
|
+
@transport.enqueue(event)
|
|
56
|
+
rescue StandardError
|
|
57
|
+
nil
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "securerandom"
|
|
4
|
+
require_relative "version"
|
|
5
|
+
require_relative "stacktrace"
|
|
6
|
+
|
|
7
|
+
module Tinymon
|
|
8
|
+
# Pure construction of a wire-format event from a Ruby Exception.
|
|
9
|
+
# Mirrors packages/browser/src/eventBuilder.ts and packages/python/.../event_builder.py.
|
|
10
|
+
module EventBuilder
|
|
11
|
+
module_function
|
|
12
|
+
|
|
13
|
+
SENSITIVE = /password|token|secret|auth|card|cvv|ssn/i.freeze
|
|
14
|
+
|
|
15
|
+
def build(exception, release: nil, environment: nil, user: nil, tags: nil, breadcrumbs: nil, url: nil)
|
|
16
|
+
event = {
|
|
17
|
+
"event_id" => SecureRandom.uuid,
|
|
18
|
+
"timestamp" => Time.now.to_f,
|
|
19
|
+
"platform" => "ruby",
|
|
20
|
+
"level" => "error",
|
|
21
|
+
"sdk" => { "name" => SDK_NAME, "version" => VERSION },
|
|
22
|
+
"exception" => {
|
|
23
|
+
"type" => exception.class.name.to_s,
|
|
24
|
+
"value" => exception.message.to_s,
|
|
25
|
+
"stacktrace" => { "frames" => Stacktrace.parse(exception) },
|
|
26
|
+
},
|
|
27
|
+
"breadcrumbs" => (breadcrumbs || []).dup,
|
|
28
|
+
"user" => (user || {}).dup,
|
|
29
|
+
"tags" => scrub(tags || {}),
|
|
30
|
+
}
|
|
31
|
+
event["release"] = release if release
|
|
32
|
+
event["environment"] = environment if environment
|
|
33
|
+
event["request"] = { "url" => url } if url
|
|
34
|
+
event
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def scrub(tags)
|
|
38
|
+
tags.each_with_object({}) do |(k, v), out|
|
|
39
|
+
out[k.to_s] = SENSITIVE.match?(k.to_s) ? "[redacted]" : v
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Tinymon
|
|
4
|
+
# Capture unhandled exceptions at process exit. Ruby doesn't have a true
|
|
5
|
+
# global "uncaught exception" hook the way Python (sys.excepthook) or Java
|
|
6
|
+
# (Thread.setDefaultUncaughtExceptionHandler) do — the closest equivalent is
|
|
7
|
+
# checking $! inside an at_exit block, which fires after a fatal exception
|
|
8
|
+
# has propagated out of `main`.
|
|
9
|
+
module Integrations
|
|
10
|
+
module_function
|
|
11
|
+
|
|
12
|
+
def install(client)
|
|
13
|
+
at_exit do
|
|
14
|
+
exc = $! # rubocop:disable Style/SpecialGlobalVars
|
|
15
|
+
# SystemExit is normal program exit; ignore it.
|
|
16
|
+
if exc && !exc.is_a?(SystemExit)
|
|
17
|
+
begin
|
|
18
|
+
client.capture_exception(exc)
|
|
19
|
+
rescue StandardError
|
|
20
|
+
# swallow
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Tinymon
|
|
4
|
+
# Process-wide user/tags/breadcrumbs that ride along with every event.
|
|
5
|
+
class Scope
|
|
6
|
+
MAX_BREADCRUMBS = 50
|
|
7
|
+
|
|
8
|
+
attr_reader :user, :tags, :breadcrumbs
|
|
9
|
+
|
|
10
|
+
def initialize
|
|
11
|
+
@mutex = Mutex.new
|
|
12
|
+
@user = {}
|
|
13
|
+
@tags = {}
|
|
14
|
+
@breadcrumbs = []
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def set_user(user)
|
|
18
|
+
@mutex.synchronize { @user = user.dup }
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def set_tag(key, value)
|
|
22
|
+
@mutex.synchronize { @tags[key.to_s] = value }
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def add_breadcrumb(crumb)
|
|
26
|
+
@mutex.synchronize do
|
|
27
|
+
@breadcrumbs.push(crumb)
|
|
28
|
+
@breadcrumbs.shift if @breadcrumbs.length > MAX_BREADCRUMBS
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def snapshot
|
|
33
|
+
@mutex.synchronize do
|
|
34
|
+
{
|
|
35
|
+
user: @user.dup,
|
|
36
|
+
tags: @tags.dup,
|
|
37
|
+
breadcrumbs: @breadcrumbs.dup,
|
|
38
|
+
}
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Singleton instance — mirrors the JS/Python SDKs' module-level scope.
|
|
44
|
+
SCOPE = Scope.new
|
|
45
|
+
end
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rbconfig"
|
|
4
|
+
|
|
5
|
+
module Tinymon
|
|
6
|
+
# Convert a Ruby Exception's backtrace into wire-format stack frames.
|
|
7
|
+
#
|
|
8
|
+
# Wire format wants frames ordered deepest-LAST. Ruby's #backtrace returns
|
|
9
|
+
# them deepest-FIRST (raise site first, then callers), so we reverse.
|
|
10
|
+
module Stacktrace
|
|
11
|
+
module_function
|
|
12
|
+
|
|
13
|
+
# Falsy heuristic: a frame is NOT in_app if its path lives inside a gem
|
|
14
|
+
# directory, the Ruby stdlib, or is a built-in (`<internal:...>`).
|
|
15
|
+
GEM_MARKER = "/gems/"
|
|
16
|
+
INTERNAL_PREFIX = "<"
|
|
17
|
+
STDLIB_PATH = RbConfig::CONFIG["rubylibdir"].to_s
|
|
18
|
+
|
|
19
|
+
def parse(exception)
|
|
20
|
+
return [] unless exception
|
|
21
|
+
|
|
22
|
+
locations = nil
|
|
23
|
+
begin
|
|
24
|
+
locations = exception.backtrace_locations
|
|
25
|
+
rescue StandardError
|
|
26
|
+
locations = nil
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
if locations && !locations.empty?
|
|
30
|
+
frames = locations.map { |loc| from_location(loc) }
|
|
31
|
+
else
|
|
32
|
+
bt = exception.backtrace || []
|
|
33
|
+
frames = bt.map { |line| parse_string(line) }.compact
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Ruby gives deepest-first; wire format wants deepest-LAST.
|
|
37
|
+
frames.reverse
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def from_location(loc)
|
|
41
|
+
path = loc.path.to_s
|
|
42
|
+
{
|
|
43
|
+
"filename" => path,
|
|
44
|
+
"function" => (loc.base_label || loc.label || "<anonymous>").to_s,
|
|
45
|
+
"lineno" => loc.lineno.to_i,
|
|
46
|
+
"colno" => 0,
|
|
47
|
+
"in_app" => in_app?(path),
|
|
48
|
+
}
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Match strings like:
|
|
52
|
+
# "path/to/file.rb:123:in `method_name'"
|
|
53
|
+
# "path/to/file.rb:123:in 'method_name'"
|
|
54
|
+
BT_LINE = /\A(.+?):(\d+)(?::in [`'](.+?)')?\z/.freeze
|
|
55
|
+
|
|
56
|
+
def parse_string(line)
|
|
57
|
+
m = BT_LINE.match(line.to_s)
|
|
58
|
+
return nil unless m
|
|
59
|
+
filename = m[1]
|
|
60
|
+
{
|
|
61
|
+
"filename" => filename,
|
|
62
|
+
"function" => (m[3] || "<anonymous>"),
|
|
63
|
+
"lineno" => m[2].to_i,
|
|
64
|
+
"colno" => 0,
|
|
65
|
+
"in_app" => in_app?(filename),
|
|
66
|
+
}
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def in_app?(path)
|
|
70
|
+
return false if path.nil? || path.empty?
|
|
71
|
+
return false if path.start_with?(INTERNAL_PREFIX)
|
|
72
|
+
return false if path.include?(GEM_MARKER)
|
|
73
|
+
return false if !STDLIB_PATH.empty? && path.start_with?(STDLIB_PATH)
|
|
74
|
+
true
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
require "net/http"
|
|
5
|
+
require "uri"
|
|
6
|
+
|
|
7
|
+
module Tinymon
|
|
8
|
+
# Batched HTTP transport. stdlib-only. A background thread flushes every
|
|
9
|
+
# 5 seconds; at_exit drains the queue on shutdown.
|
|
10
|
+
class Transport
|
|
11
|
+
FLUSH_INTERVAL = 5.0 # seconds
|
|
12
|
+
MAX_BATCH = 10
|
|
13
|
+
MAX_QUEUE = 30
|
|
14
|
+
REQUEST_TIMEOUT = 5 # seconds
|
|
15
|
+
|
|
16
|
+
def initialize(endpoint, dsn)
|
|
17
|
+
@endpoint = endpoint
|
|
18
|
+
@dsn = dsn
|
|
19
|
+
@queue = []
|
|
20
|
+
@mutex = Mutex.new
|
|
21
|
+
@stop = false
|
|
22
|
+
@thread = Thread.new { run_loop }
|
|
23
|
+
@thread.name = "tinymon-transport" if @thread.respond_to?(:name=)
|
|
24
|
+
at_exit { shutdown }
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def enqueue(event)
|
|
28
|
+
should_flush = false
|
|
29
|
+
@mutex.synchronize do
|
|
30
|
+
@queue.shift while @queue.length >= MAX_QUEUE
|
|
31
|
+
@queue.push(event)
|
|
32
|
+
should_flush = @queue.length >= MAX_BATCH
|
|
33
|
+
end
|
|
34
|
+
flush if should_flush
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def flush
|
|
38
|
+
batch = nil
|
|
39
|
+
@mutex.synchronize do
|
|
40
|
+
batch = @queue.shift(MAX_BATCH)
|
|
41
|
+
end
|
|
42
|
+
return if batch.nil? || batch.empty?
|
|
43
|
+
batch.each { |event| send_one(event) }
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
private
|
|
47
|
+
|
|
48
|
+
def send_one(event)
|
|
49
|
+
uri = URI.parse(@endpoint)
|
|
50
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
|
51
|
+
http.use_ssl = (uri.scheme == "https")
|
|
52
|
+
http.open_timeout = REQUEST_TIMEOUT
|
|
53
|
+
http.read_timeout = REQUEST_TIMEOUT
|
|
54
|
+
req = Net::HTTP::Post.new(uri.request_uri, {
|
|
55
|
+
"Content-Type" => "application/json",
|
|
56
|
+
"X-Tinymon-Key" => @dsn,
|
|
57
|
+
})
|
|
58
|
+
req.body = JSON.dump(event)
|
|
59
|
+
begin
|
|
60
|
+
http.request(req)
|
|
61
|
+
rescue StandardError
|
|
62
|
+
# Network failed — re-enqueue if there's room.
|
|
63
|
+
@mutex.synchronize do
|
|
64
|
+
@queue.unshift(event) if @queue.length < MAX_QUEUE
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def run_loop
|
|
70
|
+
until @stop
|
|
71
|
+
sleep(FLUSH_INTERVAL)
|
|
72
|
+
begin
|
|
73
|
+
flush
|
|
74
|
+
rescue StandardError
|
|
75
|
+
# swallow — never crash the host app
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def shutdown
|
|
81
|
+
@stop = true
|
|
82
|
+
begin
|
|
83
|
+
flush
|
|
84
|
+
rescue StandardError
|
|
85
|
+
nil
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
data/lib/tinymon.rb
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "tinymon/version"
|
|
4
|
+
require_relative "tinymon/stacktrace"
|
|
5
|
+
require_relative "tinymon/event_builder"
|
|
6
|
+
require_relative "tinymon/scope"
|
|
7
|
+
require_relative "tinymon/transport"
|
|
8
|
+
require_relative "tinymon/client"
|
|
9
|
+
require_relative "tinymon/integrations"
|
|
10
|
+
|
|
11
|
+
# Public API:
|
|
12
|
+
#
|
|
13
|
+
# require "tinymon"
|
|
14
|
+
# Tinymon.init(dsn: "tm_pub_xxx", environment: "production", release: "1.0.0")
|
|
15
|
+
#
|
|
16
|
+
# begin
|
|
17
|
+
# risky_thing
|
|
18
|
+
# rescue => e
|
|
19
|
+
# Tinymon.capture_exception(e)
|
|
20
|
+
# end
|
|
21
|
+
#
|
|
22
|
+
module Tinymon
|
|
23
|
+
@client = nil
|
|
24
|
+
|
|
25
|
+
class << self
|
|
26
|
+
def init(dsn:, endpoint: nil, environment: nil, release: nil, sample_rate: 1.0, before_send: nil)
|
|
27
|
+
@client = Client.new(
|
|
28
|
+
dsn: dsn,
|
|
29
|
+
endpoint: endpoint,
|
|
30
|
+
environment: environment,
|
|
31
|
+
release: release,
|
|
32
|
+
sample_rate: sample_rate,
|
|
33
|
+
before_send: before_send,
|
|
34
|
+
)
|
|
35
|
+
Integrations.install(@client)
|
|
36
|
+
@client
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def capture_exception(exception)
|
|
40
|
+
@client&.capture_exception(exception)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def capture_message(message, level: "info")
|
|
44
|
+
@client&.capture_message(message, level: level)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def set_user(user)
|
|
48
|
+
SCOPE.set_user(user)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def set_tag(key, value)
|
|
52
|
+
SCOPE.set_tag(key, value)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def add_breadcrumb(crumb)
|
|
56
|
+
SCOPE.add_breadcrumb(crumb)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Exposed for the cross-language contract test in test/test_contract.rb.
|
|
60
|
+
def _build_event(exception, **kwargs)
|
|
61
|
+
EventBuilder.build(exception, **kwargs)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
data/lib/tinymonrb.rb
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "tinymon/version"
|
|
4
|
+
require_relative "tinymon/stacktrace"
|
|
5
|
+
require_relative "tinymon/event_builder"
|
|
6
|
+
require_relative "tinymon/scope"
|
|
7
|
+
require_relative "tinymon/transport"
|
|
8
|
+
require_relative "tinymon/client"
|
|
9
|
+
require_relative "tinymon/integrations"
|
|
10
|
+
|
|
11
|
+
# Public API:
|
|
12
|
+
#
|
|
13
|
+
# require "tinymon"
|
|
14
|
+
# Tinymon.init(dsn: "tm_pub_xxx", environment: "production", release: "1.0.0")
|
|
15
|
+
#
|
|
16
|
+
# begin
|
|
17
|
+
# risky_thing
|
|
18
|
+
# rescue => e
|
|
19
|
+
# Tinymon.capture_exception(e)
|
|
20
|
+
# end
|
|
21
|
+
#
|
|
22
|
+
module Tinymon
|
|
23
|
+
@client = nil
|
|
24
|
+
|
|
25
|
+
class << self
|
|
26
|
+
def init(dsn:, endpoint: nil, environment: nil, release: nil, sample_rate: 1.0, before_send: nil)
|
|
27
|
+
@client = Client.new(
|
|
28
|
+
dsn: dsn,
|
|
29
|
+
endpoint: endpoint,
|
|
30
|
+
environment: environment,
|
|
31
|
+
release: release,
|
|
32
|
+
sample_rate: sample_rate,
|
|
33
|
+
before_send: before_send,
|
|
34
|
+
)
|
|
35
|
+
Integrations.install(@client)
|
|
36
|
+
@client
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def capture_exception(exception)
|
|
40
|
+
@client&.capture_exception(exception)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def capture_message(message, level: "info")
|
|
44
|
+
@client&.capture_message(message, level: level)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def set_user(user)
|
|
48
|
+
SCOPE.set_user(user)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def set_tag(key, value)
|
|
52
|
+
SCOPE.set_tag(key, value)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def add_breadcrumb(crumb)
|
|
56
|
+
SCOPE.add_breadcrumb(crumb)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Exposed for the cross-language contract test in test/test_contract.rb.
|
|
60
|
+
def _build_event(exception, **kwargs)
|
|
61
|
+
EventBuilder.build(exception, **kwargs)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: tinymonrb
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- tinymon
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2026-06-06 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: json_schemer
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '2.0'
|
|
20
|
+
type: :development
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '2.0'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: minitest
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '5.0'
|
|
34
|
+
type: :development
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '5.0'
|
|
41
|
+
description: Captures unhandled exceptions and ships them to a tinymon ingest endpoint.
|
|
42
|
+
email:
|
|
43
|
+
executables: []
|
|
44
|
+
extensions: []
|
|
45
|
+
extra_rdoc_files: []
|
|
46
|
+
files:
|
|
47
|
+
- lib/tinymon.rb
|
|
48
|
+
- lib/tinymon/client.rb
|
|
49
|
+
- lib/tinymon/event_builder.rb
|
|
50
|
+
- lib/tinymon/integrations.rb
|
|
51
|
+
- lib/tinymon/scope.rb
|
|
52
|
+
- lib/tinymon/stacktrace.rb
|
|
53
|
+
- lib/tinymon/transport.rb
|
|
54
|
+
- lib/tinymon/version.rb
|
|
55
|
+
- lib/tinymonrb.rb
|
|
56
|
+
homepage: https://tinymon.dev
|
|
57
|
+
licenses:
|
|
58
|
+
- MIT
|
|
59
|
+
metadata:
|
|
60
|
+
homepage_uri: https://tinymon.dev
|
|
61
|
+
documentation_uri: https://tinymon.dev/docs/ruby.html
|
|
62
|
+
source_code_uri: https://github.com/tinymon/tinymon
|
|
63
|
+
post_install_message:
|
|
64
|
+
rdoc_options: []
|
|
65
|
+
require_paths:
|
|
66
|
+
- lib
|
|
67
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
68
|
+
requirements:
|
|
69
|
+
- - ">="
|
|
70
|
+
- !ruby/object:Gem::Version
|
|
71
|
+
version: '2.7'
|
|
72
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
73
|
+
requirements:
|
|
74
|
+
- - ">="
|
|
75
|
+
- !ruby/object:Gem::Version
|
|
76
|
+
version: '0'
|
|
77
|
+
requirements: []
|
|
78
|
+
rubygems_version: 3.0.3.1
|
|
79
|
+
signing_key:
|
|
80
|
+
specification_version: 4
|
|
81
|
+
summary: Tiny error monitoring SDK for Ruby.
|
|
82
|
+
test_files: []
|