tg_error_notifier 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/LICENSE.txt +21 -0
- data/README.md +92 -0
- data/lib/tg_error_notifier/configuration.rb +41 -0
- data/lib/tg_error_notifier/middleware.rb +25 -0
- data/lib/tg_error_notifier/notifier.rb +128 -0
- data/lib/tg_error_notifier/railtie.rb +36 -0
- data/lib/tg_error_notifier/subscriber.rb +28 -0
- data/lib/tg_error_notifier/version.rb +5 -0
- data/lib/tg_error_notifier.rb +36 -0
- metadata +67 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: d8c70bb799ac75d0ec7db9e1f15d089bb493d1a76e905f6a88a33e2ecbf26ad8
|
|
4
|
+
data.tar.gz: 01c6e5de7fc99ad1f7603627f9c9db23d6c9a817e35b2d659288ff6bdbf6abd0
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: a7a076c6107c81900dfb8f189b63f0bc4c4c0265ce26f587114fb548b39aca5e54c75ae80e400a38e1dc759d7f5034d56a6e1c9bb88f66aae89d53baecbc6e68
|
|
7
|
+
data.tar.gz: 0c9a3ecc60610f7a53a82fa1d86da36908e78c45232ec66edcdc96c56dd0b9538b18e87323b8a5fb0af70353a1c3354f4c6879ebc7fd19091b835070dc2e39ba
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# tg_error_notifier
|
|
2
|
+
|
|
3
|
+
Gem for Rails error notifications to Telegram.
|
|
4
|
+
|
|
5
|
+
## What it catches
|
|
6
|
+
- Unhandled errors in Rack/Rails request cycle.
|
|
7
|
+
- Failed ActiveJob executions.
|
|
8
|
+
|
|
9
|
+
## Quick usage
|
|
10
|
+
```ruby
|
|
11
|
+
# Gemfile
|
|
12
|
+
gem "tg_error_notifier"
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
```ruby
|
|
16
|
+
# config/initializers/telegram_error_notifier.rb
|
|
17
|
+
Rails.application.configure do
|
|
18
|
+
config.telegram_error_notifier.bot_token = ENV["TELEGRAM_BOT_TOKEN"]
|
|
19
|
+
config.telegram_error_notifier.chat_id = ENV["TELEGRAM_ERRORS_CHAT_ID"]
|
|
20
|
+
config.telegram_error_notifier.app_name = "my_app"
|
|
21
|
+
end
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Environment variables
|
|
25
|
+
- `TELEGRAM_BOT_TOKEN`
|
|
26
|
+
- `TELEGRAM_ERRORS_CHAT_ID`
|
|
27
|
+
- `TELEGRAM_ERRORS_APP_NAME` (optional)
|
|
28
|
+
|
|
29
|
+
## Telegram setup (bot, private channel/group, chat_id)
|
|
30
|
+
|
|
31
|
+
### 1. Create a bot and get token
|
|
32
|
+
1. Open Telegram and start chat with `@BotFather`.
|
|
33
|
+
2. Send `/newbot` and follow prompts (bot name + username ending with `bot`).
|
|
34
|
+
3. Copy the HTTP API token (looks like `123456:ABC...`) and save it as `TELEGRAM_BOT_TOKEN`.
|
|
35
|
+
|
|
36
|
+
### 2. Create a private channel or private group
|
|
37
|
+
|
|
38
|
+
#### Private channel
|
|
39
|
+
1. Telegram -> New Channel -> set as **Private**.
|
|
40
|
+
2. Open channel settings -> Administrators -> add your bot as admin.
|
|
41
|
+
3. Grant at least permission to post messages.
|
|
42
|
+
|
|
43
|
+
#### Private group (or supergroup)
|
|
44
|
+
1. Telegram -> New Group -> add at least one member.
|
|
45
|
+
2. Add your bot to the group.
|
|
46
|
+
3. Promote bot to admin if needed (recommended for reliability).
|
|
47
|
+
4. Keep group private (no public username).
|
|
48
|
+
|
|
49
|
+
### 3. Get `chat_id`
|
|
50
|
+
|
|
51
|
+
#### Method A (easy): `@userinfobot` / `@RawDataBot`
|
|
52
|
+
- Add bot `@userinfobot` (or `@RawDataBot`) into your target channel/group.
|
|
53
|
+
- Send any message there.
|
|
54
|
+
- Open the helper bot dialog and read chat id.
|
|
55
|
+
- For channels/supergroups it is usually negative and starts with `-100...`.
|
|
56
|
+
- Delete this bot from your channel.
|
|
57
|
+
|
|
58
|
+
#### Method B (official API): `getUpdates`
|
|
59
|
+
1. Send at least one message in target chat after adding your bot.
|
|
60
|
+
2. Open in browser:
|
|
61
|
+
`https://api.telegram.org/bot<TELEGRAM_BOT_TOKEN>/getUpdates`
|
|
62
|
+
3. Find `chat` object and copy `chat.id`.
|
|
63
|
+
|
|
64
|
+
Examples:
|
|
65
|
+
- Private channel/supergroup: `-1001234567890`
|
|
66
|
+
- Private group (old style): `-123456789`
|
|
67
|
+
|
|
68
|
+
### 4. Validate before using in Rails
|
|
69
|
+
- Ensure bot is present in the target chat.
|
|
70
|
+
- Ensure bot has permission to send messages.
|
|
71
|
+
- Put value into `TELEGRAM_ERRORS_CHAT_ID` and run a smoke test.
|
|
72
|
+
|
|
73
|
+
## Manual notification
|
|
74
|
+
```ruby
|
|
75
|
+
begin
|
|
76
|
+
do_work
|
|
77
|
+
rescue => e
|
|
78
|
+
pp TgErrorNotifier.capture_exception(e)
|
|
79
|
+
# or with extra context:
|
|
80
|
+
TgErrorNotifier.capture_exception(
|
|
81
|
+
e,
|
|
82
|
+
source: "custom",
|
|
83
|
+
context: { feature: "sync", user_id: current_user&.id }
|
|
84
|
+
)
|
|
85
|
+
raise
|
|
86
|
+
end
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
`capture_exception` returns a diagnostic hash, e.g.:
|
|
90
|
+
- `{ sent: true, status: :sent, code: 200 }`
|
|
91
|
+
- `{ sent: false, status: :skipped, reason: "missing_chat_id" }`
|
|
92
|
+
- `{ sent: false, status: :failed, reason: "telegram_api_error", code: 400, body: "..." }`
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module TgErrorNotifier
|
|
4
|
+
class Configuration
|
|
5
|
+
attr_accessor :enabled,
|
|
6
|
+
:bot_token,
|
|
7
|
+
:chat_id,
|
|
8
|
+
:api_base,
|
|
9
|
+
:environment,
|
|
10
|
+
:app_name,
|
|
11
|
+
:max_backtrace_lines,
|
|
12
|
+
:ignored_exceptions,
|
|
13
|
+
:ignored_environments,
|
|
14
|
+
:open_timeout,
|
|
15
|
+
:read_timeout,
|
|
16
|
+
:logger,
|
|
17
|
+
:include_backtrace,
|
|
18
|
+
:active_job_enabled
|
|
19
|
+
|
|
20
|
+
def initialize
|
|
21
|
+
@enabled = true
|
|
22
|
+
@bot_token = ENV["TELEGRAM_BOT_TOKEN"]
|
|
23
|
+
@chat_id = ENV["TELEGRAM_ERRORS_CHAT_ID"]
|
|
24
|
+
@api_base = "https://api.telegram.org"
|
|
25
|
+
@environment = ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development"
|
|
26
|
+
@app_name = ENV["TELEGRAM_ERRORS_APP_NAME"] || "Rails App"
|
|
27
|
+
@max_backtrace_lines = 20
|
|
28
|
+
@ignored_exceptions = [
|
|
29
|
+
"ActionController::RoutingError",
|
|
30
|
+
"ActiveRecord::RecordNotFound",
|
|
31
|
+
"ActionController::UnknownFormat"
|
|
32
|
+
]
|
|
33
|
+
@ignored_environments = ["test"]
|
|
34
|
+
@open_timeout = 2
|
|
35
|
+
@read_timeout = 5
|
|
36
|
+
@logger = nil
|
|
37
|
+
@include_backtrace = true
|
|
38
|
+
@active_job_enabled = true
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module TgErrorNotifier
|
|
4
|
+
class Middleware
|
|
5
|
+
def initialize(app)
|
|
6
|
+
@app = app
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def call(env)
|
|
10
|
+
@app.call(env)
|
|
11
|
+
rescue StandardError => e
|
|
12
|
+
TgErrorNotifier.notify(
|
|
13
|
+
exception: e,
|
|
14
|
+
source: "rack",
|
|
15
|
+
context: {
|
|
16
|
+
method: env["REQUEST_METHOD"],
|
|
17
|
+
path: env["PATH_INFO"],
|
|
18
|
+
query: env["QUERY_STRING"],
|
|
19
|
+
request_id: env["action_dispatch.request_id"]
|
|
20
|
+
}
|
|
21
|
+
)
|
|
22
|
+
raise
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "net/http"
|
|
4
|
+
require "json"
|
|
5
|
+
require "cgi"
|
|
6
|
+
|
|
7
|
+
module TgErrorNotifier
|
|
8
|
+
class Notifier
|
|
9
|
+
MAX_MESSAGE_LENGTH = 3800
|
|
10
|
+
|
|
11
|
+
def initialize(config)
|
|
12
|
+
@config = config
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def notify(exception:, source:, context: {})
|
|
16
|
+
enabled_check = enabled_status
|
|
17
|
+
unless enabled_check[:enabled]
|
|
18
|
+
log("skipped: #{enabled_check[:reason]}")
|
|
19
|
+
return { sent: false, status: :skipped, reason: enabled_check[:reason] }
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
if ignored_exception?(exception)
|
|
23
|
+
return { sent: false, status: :skipped, reason: "ignored_exception" }
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
payload = build_payload(exception: exception, source: source, context: context)
|
|
27
|
+
send_payload(payload)
|
|
28
|
+
rescue StandardError => e
|
|
29
|
+
log("notify failed: #{e.class}: #{e.message}")
|
|
30
|
+
{ sent: false, status: :failed, reason: e.class.name, error: e.message }
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
attr_reader :config
|
|
36
|
+
|
|
37
|
+
def enabled_status
|
|
38
|
+
return { enabled: false, reason: "disabled" } unless resolve(config.enabled)
|
|
39
|
+
if config.ignored_environments.include?(resolve(config.environment).to_s)
|
|
40
|
+
return { enabled: false, reason: "ignored_environment" }
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
token_present = resolve(config.bot_token).to_s != ""
|
|
44
|
+
chat_present = resolve(config.chat_id).to_s != ""
|
|
45
|
+
return { enabled: false, reason: "missing_bot_token" } unless token_present
|
|
46
|
+
return { enabled: false, reason: "missing_chat_id" } unless chat_present
|
|
47
|
+
|
|
48
|
+
{ enabled: true }
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def ignored_exception?(exception)
|
|
52
|
+
ignored = config.ignored_exceptions.map(&:to_s)
|
|
53
|
+
ignored.include?(exception.class.name)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def send_payload(payload)
|
|
57
|
+
token = resolve(config.bot_token)
|
|
58
|
+
uri = URI("#{resolve(config.api_base)}/bot#{token}/sendMessage")
|
|
59
|
+
|
|
60
|
+
request = Net::HTTP::Post.new(uri)
|
|
61
|
+
request["Content-Type"] = "application/json"
|
|
62
|
+
request.body = payload.to_json
|
|
63
|
+
|
|
64
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
|
65
|
+
http.use_ssl = uri.scheme == "https"
|
|
66
|
+
http.open_timeout = config.open_timeout
|
|
67
|
+
http.read_timeout = config.read_timeout
|
|
68
|
+
|
|
69
|
+
response = http.request(request)
|
|
70
|
+
if response.is_a?(Net::HTTPSuccess)
|
|
71
|
+
return { sent: true, status: :sent, code: response.code.to_i }
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
log("telegram api error: HTTP #{response.code} #{response.body}")
|
|
75
|
+
{ sent: false, status: :failed, reason: "telegram_api_error", code: response.code.to_i, body: response.body.to_s }
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def build_payload(exception:, source:, context: {})
|
|
79
|
+
text = [
|
|
80
|
+
"<b>🚨 #{escape(resolve(config.app_name).to_s)}: #{escape(resolve(config.environment).to_s)}</b>",
|
|
81
|
+
"<b>Source:</b> #{escape(source.to_s)}",
|
|
82
|
+
"<b>Exception:</b> <code>#{escape(exception.class.name)}</code>",
|
|
83
|
+
"<b>Message:</b> #{escape(exception.message.to_s)}",
|
|
84
|
+
context_block(context)
|
|
85
|
+
].compact.join("\n")
|
|
86
|
+
|
|
87
|
+
if config.include_backtrace && exception.backtrace
|
|
88
|
+
lines = exception.backtrace.first(config.max_backtrace_lines)
|
|
89
|
+
bt = escape(lines.join("\n"))
|
|
90
|
+
text = "#{text}\n<b>Backtrace:</b>\n<pre>#{bt}</pre>"
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
{
|
|
94
|
+
chat_id: resolve(config.chat_id),
|
|
95
|
+
text: truncate(text),
|
|
96
|
+
parse_mode: "HTML",
|
|
97
|
+
disable_web_page_preview: true
|
|
98
|
+
}
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def context_block(context)
|
|
102
|
+
return nil if context.nil? || context.empty?
|
|
103
|
+
|
|
104
|
+
formatted = context.map { |k, v| "<b>#{escape(k.to_s)}:</b> #{escape(v.to_s)}" }
|
|
105
|
+
formatted.join("\n")
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def truncate(text)
|
|
109
|
+
return text if text.length <= MAX_MESSAGE_LENGTH
|
|
110
|
+
|
|
111
|
+
text[0...MAX_MESSAGE_LENGTH] + "\n...truncated"
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def resolve(value)
|
|
115
|
+
value.respond_to?(:call) ? value.call : value
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def escape(text)
|
|
119
|
+
CGI.escapeHTML(text.to_s)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def log(message)
|
|
123
|
+
return unless config.logger
|
|
124
|
+
|
|
125
|
+
config.logger.error("[TgErrorNotifier] #{message}")
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module TgErrorNotifier
|
|
4
|
+
class Railtie < Rails::Railtie
|
|
5
|
+
config.telegram_error_notifier = ActiveSupport::OrderedOptions.new
|
|
6
|
+
|
|
7
|
+
initializer "tg_error_notifier.configure", after: :load_config_initializers do |app|
|
|
8
|
+
options = app.config.telegram_error_notifier
|
|
9
|
+
|
|
10
|
+
TgErrorNotifier.configure do |config|
|
|
11
|
+
config.enabled = options.enabled unless options.enabled.nil?
|
|
12
|
+
config.bot_token = options.bot_token unless options.bot_token.nil?
|
|
13
|
+
config.chat_id = options.chat_id unless options.chat_id.nil?
|
|
14
|
+
config.api_base = options.api_base unless options.api_base.nil?
|
|
15
|
+
config.environment = options.environment unless options.environment.nil?
|
|
16
|
+
config.app_name = options.app_name unless options.app_name.nil?
|
|
17
|
+
config.max_backtrace_lines = options.max_backtrace_lines unless options.max_backtrace_lines.nil?
|
|
18
|
+
config.ignored_exceptions = options.ignored_exceptions unless options.ignored_exceptions.nil?
|
|
19
|
+
config.ignored_environments = options.ignored_environments unless options.ignored_environments.nil?
|
|
20
|
+
config.open_timeout = options.open_timeout unless options.open_timeout.nil?
|
|
21
|
+
config.read_timeout = options.read_timeout unless options.read_timeout.nil?
|
|
22
|
+
config.logger = options.logger unless options.logger.nil?
|
|
23
|
+
config.include_backtrace = options.include_backtrace unless options.include_backtrace.nil?
|
|
24
|
+
config.active_job_enabled = options.active_job_enabled unless options.active_job_enabled.nil?
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
initializer "tg_error_notifier.middleware" do |app|
|
|
29
|
+
app.middleware.use TgErrorNotifier::Middleware
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
initializer "tg_error_notifier.subscriber", after: :load_config_initializers do
|
|
33
|
+
TgErrorNotifier::Subscriber.attach! if TgErrorNotifier.configuration.active_job_enabled
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module TgErrorNotifier
|
|
4
|
+
class Subscriber
|
|
5
|
+
def self.attach!
|
|
6
|
+
return if @attached
|
|
7
|
+
|
|
8
|
+
ActiveSupport::Notifications.subscribe("perform.active_job") do |_name, _start, _finish, _id, payload|
|
|
9
|
+
exception = payload[:exception_object]
|
|
10
|
+
next unless exception
|
|
11
|
+
|
|
12
|
+
job = payload[:job]
|
|
13
|
+
TgErrorNotifier.notify(
|
|
14
|
+
exception: exception,
|
|
15
|
+
source: "active_job",
|
|
16
|
+
context: {
|
|
17
|
+
job_class: job&.class&.name,
|
|
18
|
+
job_id: job&.job_id,
|
|
19
|
+
queue: job&.queue_name,
|
|
20
|
+
executions: job&.executions
|
|
21
|
+
}
|
|
22
|
+
)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
@attached = true
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails"
|
|
4
|
+
require_relative "tg_error_notifier/version"
|
|
5
|
+
require_relative "tg_error_notifier/configuration"
|
|
6
|
+
require_relative "tg_error_notifier/notifier"
|
|
7
|
+
require_relative "tg_error_notifier/middleware"
|
|
8
|
+
require_relative "tg_error_notifier/subscriber"
|
|
9
|
+
require_relative "tg_error_notifier/railtie"
|
|
10
|
+
|
|
11
|
+
module TgErrorNotifier
|
|
12
|
+
class << self
|
|
13
|
+
def configuration
|
|
14
|
+
@configuration ||= Configuration.new
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def configure
|
|
18
|
+
yield(configuration)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def notify(exception:, source:, context: {})
|
|
22
|
+
notifier.notify(exception: exception, source: source, context: context)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# API similar to Sentry.capture_exception(error)
|
|
26
|
+
def capture_exception(exception, source: "manual", context: {})
|
|
27
|
+
notify(exception: exception, source: source, context: context)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
def notifier
|
|
33
|
+
@notifier ||= Notifier.new(configuration)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: tg_error_notifier
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Sergei Ustinov
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: rails
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - ">="
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '7.0'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - ">="
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '7.0'
|
|
26
|
+
description: Catches Rails request and ActiveJob exceptions and sends detailed alerts
|
|
27
|
+
to Telegram.
|
|
28
|
+
email:
|
|
29
|
+
- se.ustinov@gmail.com
|
|
30
|
+
executables: []
|
|
31
|
+
extensions: []
|
|
32
|
+
extra_rdoc_files: []
|
|
33
|
+
files:
|
|
34
|
+
- LICENSE.txt
|
|
35
|
+
- README.md
|
|
36
|
+
- lib/tg_error_notifier.rb
|
|
37
|
+
- lib/tg_error_notifier/configuration.rb
|
|
38
|
+
- lib/tg_error_notifier/middleware.rb
|
|
39
|
+
- lib/tg_error_notifier/notifier.rb
|
|
40
|
+
- lib/tg_error_notifier/railtie.rb
|
|
41
|
+
- lib/tg_error_notifier/subscriber.rb
|
|
42
|
+
- lib/tg_error_notifier/version.rb
|
|
43
|
+
homepage: https://github.com/sergeyustinov/TgErrorNotifier
|
|
44
|
+
licenses:
|
|
45
|
+
- MIT
|
|
46
|
+
metadata:
|
|
47
|
+
homepage_uri: https://github.com/sergeyustinov/TgErrorNotifier
|
|
48
|
+
source_code_uri: https://github.com/sergeyustinov/TgErrorNotifier
|
|
49
|
+
changelog_uri: https://github.com/sergeyustinov/TgErrorNotifier/releases
|
|
50
|
+
rdoc_options: []
|
|
51
|
+
require_paths:
|
|
52
|
+
- lib
|
|
53
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
54
|
+
requirements:
|
|
55
|
+
- - ">="
|
|
56
|
+
- !ruby/object:Gem::Version
|
|
57
|
+
version: '3.1'
|
|
58
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
59
|
+
requirements:
|
|
60
|
+
- - ">="
|
|
61
|
+
- !ruby/object:Gem::Version
|
|
62
|
+
version: '0'
|
|
63
|
+
requirements: []
|
|
64
|
+
rubygems_version: 4.0.5
|
|
65
|
+
specification_version: 4
|
|
66
|
+
summary: Rails error notifications to Telegram
|
|
67
|
+
test_files: []
|