emissary-ruby 0.0.1

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 (8) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/LICENSE +21 -0
  4. data/README.md +130 -0
  5. data/lib/emissary.rb +105 -0
  6. data/lib/loggr.json +55 -0
  7. data/lib/loggr.rb +174 -0
  8. metadata +163 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 42928a4cf26e93718721e9d26b393e7613b76ccd2f95b8dec440c964f6d7d0a0
4
+ data.tar.gz: 2e7279d53f1301c3a9a2dfaa5950f019e04f9ba5c1590a74e9c1a0e78be420b1
5
+ SHA512:
6
+ metadata.gz: 1ca10786e85582c824f5d9b293678f7af222ee43117dc0cfdc5253826209c63b91e641b88e30846372ba6d92723c0da4355da28d99458bf9c6ac7ad47bc95c01
7
+ data.tar.gz: e901fa214fed00c8a27a8719a20aede77353fa2d95335a2a3e160e8f67fb9776ac12f1da73cfbce39b2929a9c19592fe7d33a8eaa97d34da2787fe6ec908d984
data/.gitignore ADDED
@@ -0,0 +1,10 @@
1
+ /runner.rb
2
+ /.bundle/
3
+ /.yardoc
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.gem
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2021 Simón
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,130 @@
1
+ # Emissary
2
+ Simple error catcher integrated with services like Discord and Trello, use chatbots to monitor your application and server.
3
+ Receive error catching reports to a Discord Server Channel, and use chatbots to send commands and fetch reports.
4
+
5
+ # Features
6
+ * This tools allows you to configurate the errors or lines you want to capture from any log file, in this example you will find a configuration for catching HTTP ERROR 500.
7
+ * You can configurate the timeframes in which the logs will be read, the conditions that triggers the errores, the lines to fetch from the files, the language to markup the error to discord, characters to ignore, how often the errors fetched would be clear, and how often you want a receive reports with error ocurrences.
8
+ * You can also use chatbots to fetch and generate reports any time outside the timeframes configurated.
9
+ * You can also configurate linux commands and receive in discord the outputs or results.
10
+
11
+ # Setup your Discord Server, Channel, Application and Bot
12
+ * 1. Go To [Discord Developers](https://discord.com/developers)
13
+ * 2. Create a new application and under the Bot option create a new bot
14
+ * 3. Add your new bot to your server Channel
15
+ * 4. Create a **webhook** in you server channel
16
+ * 5. Paste the **webhooks url** and chat bot token in the Emissary configuration file.
17
+
18
+ # Setup your Trello Board and List
19
+ * 1. Go To [Trello App Key Generator](https://trello.com/app-key)
20
+ * 2. Click in **Token** to create your member token *(be aware of expiration time)*
21
+ * 3. Copy both your **public_key** and **member_token** into the initializer file or runner
22
+ * 4. Find your Trello **ListID**, you can do this by openning the web tools in your browser, click on the navigation tab and watch for the navigation log when editing the name of your list, the ID will be visible under the **Preview Tab**
23
+ * 5. Use the Trello **ListID** in the loggr.json file under the configuration you want trello to work with.
24
+
25
+ # 2. Download / Clone the code
26
+ ```bash
27
+
28
+ git clone git@github.com:MakarovCode/Emissary.git
29
+
30
+ ```
31
+
32
+ # 3. Make it run
33
+ create runner.rb or config/initializer/emissary.rb file
34
+
35
+ ```ruby
36
+
37
+ require './emissary'
38
+
39
+ Emissary.configure do |config|
40
+ config.server_name = "A name for chat titles"
41
+ config.header_format = "__***{title}***__" #Any markup
42
+ config.webhooks_url = '{discord webhooks_url}'
43
+ config.bot_token = '{discord bot_token}'
44
+ config.trello_public_key = '{trello public_key}'
45
+ config.trello_member_token = '{trello member_token}'
46
+ end
47
+
48
+ emi = Emissary.new
49
+
50
+ ```
51
+
52
+ # 4. Configure your log readers and commands in the loggr.json file
53
+
54
+ See some examples
55
+
56
+ ```javascript
57
+ {
58
+ "rails": {
59
+ "name": "Rails Logger",
60
+ "path": "path/to/rails/log",
61
+ "condition": "Completed 500 Internal Server Error",
62
+ "lines": 10,
63
+ "fetch_each": 10,
64
+ "language": "ruby",
65
+ "ignore": ["", " ", " "],
66
+ "command": "rails",
67
+ "bash_command": "",
68
+ "clear_each": 48,
69
+ "report_each": 12,
70
+ "trello_list_id": "",
71
+ "color": "#FF0000",
72
+ "alias": "ror",
73
+ "format": ""
74
+ },
75
+ "disk": {
76
+ "name": "Disk Usage",
77
+ "path": "",
78
+ "condition": "",
79
+ "lines": 0,
80
+ "fetch_each": 0,
81
+ "language": "text",
82
+ "ignore": ["", " ", " "],
83
+ "command": "disk",
84
+ "bash_command": "df -h",
85
+ "clear_each": 0,
86
+ "report_each": 0,
87
+ "trello_list_id": "",
88
+ "color": "#00FF00",
89
+ "alias": "",
90
+ "format": {"from": " ", "to": "|"}
91
+ },
92
+ "cpu": {
93
+ "name": "CPU Usage",
94
+ "path": "",
95
+ "condition": "",
96
+ "lines": 0,
97
+ "fetch_each": 0,
98
+ "language": "text",
99
+ "ignore": ["", " ", " "],
100
+ "command": "cpu",
101
+ "bash_command": "mpstat",
102
+ "clear_each": 0,
103
+ "report_each": 0,
104
+ "trello_list_id": "",
105
+ "color": "#00FF00",
106
+ "alias": "",
107
+ "format": {"from": " ", "to": "|"}
108
+ }
109
+ }
110
+ ```
111
+
112
+ # 5. If everything goes right
113
+ You can type the next commands in your Discord Server Channel and the Chatbot will answer.
114
+
115
+ ```ruby
116
+ !emy rails fetch #This will read the log file for the setup with command rails
117
+
118
+ !emy rails report #this will send to the discord general reports of errors catched
119
+
120
+ !emy disk #This will send back to discord the usage of the server disk partitions
121
+
122
+ !emy rails {id} trello #Add message report to trello list
123
+ ```
124
+ # Roadmap
125
+ This tools is in the making
126
+ * Upload as Ruby Gem
127
+ * Regex conditioning
128
+ * Slack Integration
129
+ * Email reports Integration
130
+ * Convert the message HASH into a Ruby Class
data/lib/emissary.rb ADDED
@@ -0,0 +1,105 @@
1
+ require 'discordrb'
2
+
3
+ require "json"
4
+
5
+
6
+ require './lib/loggr';
7
+
8
+ class Emissary
9
+
10
+ class << self
11
+ attr_accessor :webhooks_url, :bot_token, :trello_public_key, :trello_member_token, :server_name, :header_format
12
+ def configure(&block)
13
+ block.call(self)
14
+ end
15
+
16
+ def header
17
+ header_format.gsub("{title}", server_name)
18
+ end
19
+ end
20
+
21
+ attr_accessor :loggrs
22
+
23
+ def configure(&block)
24
+ block.call(self)
25
+ end
26
+
27
+ def initialize
28
+ @loggrs = {}
29
+ read_loggrs
30
+ init_bot
31
+ end
32
+
33
+ def get_message
34
+ end
35
+
36
+ def respond
37
+ end
38
+
39
+ def read_loggrs
40
+
41
+ file = File.open "./lib/loggr.json"
42
+ raw_loggrs = JSON.load file
43
+ raw_loggrs.each do |k, v|
44
+ loggr = Loggr.new v
45
+ loggrs[loggr.command] = loggr
46
+ end
47
+ file.close
48
+ end
49
+
50
+ def init_bot
51
+
52
+
53
+ bot = Discordrb::Commands::CommandBot.new token: Emissary.bot_token, prefix: '!'
54
+
55
+ bot.command :emy do |event, *args|
56
+ puts "===> Receiving request bot"
57
+ if args.count > 0
58
+ command = args[0]
59
+ loggr = loggrs[command]
60
+ unless loggr.nil?
61
+ if loggr.bash_command == ""
62
+ if args.count > 1
63
+ if args[1] == "report"
64
+ loggr.report
65
+ "#{Emissary.header}\nGenerating Last Report"
66
+ elsif args[1] == "fetch"
67
+ loggr.fetch
68
+ "#{Emissary.header}\nFetching Report"
69
+ elsif args[1] == "clear"
70
+ loggr.clear
71
+ "#{Emissary.header}\nClearing Report"
72
+ elsif args[1] == "last"
73
+ loggr.message_to_chat loggr.last_message
74
+ elsif ![nil, ""].include?(args[1]) && args[1].include?(loggr.alias)
75
+ if args.count > 2
76
+ if args[2] == "trello"
77
+ card_url = loggr.create_trello_card loggr.message_by_id(args[1])
78
+ "#{Emissary.header}\n**Trello card added.**\n#{card_url}"
79
+ end
80
+ else
81
+ loggr.message_to_chat loggr.message_by_id(args[1])
82
+ end
83
+ else
84
+ "#{Emissary.header}\nWrong arguments for command #{command}:\n**last**: Last Message.\n**report**: Generate report before time.\n**{id}**: Message with ID"
85
+ end
86
+ else
87
+ "#{Emissary.header}\nYou didn't write an argument:\n**last**: Last Message.\n**report**: Generate report before time.\n**{id}**: Message with ID"
88
+ end
89
+ else
90
+ "#{Emissary.header}\n#{loggr.syscall}"
91
+ end
92
+ else
93
+ "#{Emissary.header}\nCommand not found: #{command}"
94
+ end
95
+ else
96
+ "#{Emissary.header}\nYou didn't write a command"
97
+ end
98
+ end
99
+
100
+ bot.run
101
+ end
102
+
103
+
104
+
105
+ end
data/lib/loggr.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "rails": {
3
+ "name": "Rails Logger",
4
+ "path": "../Zaiko/log/development.log",
5
+ "condition": "Completed 500 Internal Server Error",
6
+ "lines": 10,
7
+ "fetch_each": 10,
8
+ "language": "ruby",
9
+ "ignore": ["", " ", " "],
10
+ "command": "rails",
11
+ "bash_command": "",
12
+ "clear_each": 48,
13
+ "report_each": 12,
14
+ "trello_list_id": "60c54865ddeb95815a4b8993",
15
+ "trello_labels": "",
16
+ "trello_members_ids": "",
17
+ "color": "#FF0000",
18
+ "alias": "ror",
19
+ "format": ""
20
+ },
21
+ "disk": {
22
+ "name": "Disk Usage",
23
+ "path": "",
24
+ "condition": "",
25
+ "lines": 0,
26
+ "fetch_each": 0,
27
+ "language": "text",
28
+ "ignore": ["", " ", " "],
29
+ "command": "disk",
30
+ "bash_command": "df -h",
31
+ "clear_each": 0,
32
+ "report_each": 0,
33
+ "trello_list_id": "",
34
+ "color": "#00FF00",
35
+ "alias": "",
36
+ "format": {"from": "", "to": ""}
37
+ },
38
+ "cpu": {
39
+ "name": "CPU Usage",
40
+ "path": "",
41
+ "condition": "",
42
+ "lines": 0,
43
+ "fetch_each": 0,
44
+ "language": "text",
45
+ "ignore": ["", " ", " "],
46
+ "command": "cpu",
47
+ "bash_command": "mpstat",
48
+ "clear_each": 0,
49
+ "report_each": 0,
50
+ "trello_list_id": "",
51
+ "color": "#00FF00",
52
+ "alias": "",
53
+ "format": {"from": "", "to": ""}
54
+ }
55
+ }
data/lib/loggr.rb ADDED
@@ -0,0 +1,174 @@
1
+ require 'thread'
2
+ require 'discordrb/webhooks'
3
+ require 'trello'
4
+ require 'open3'
5
+
6
+ class Loggr
7
+
8
+ attr_accessor :messages, :path, :condition, :lines, :fetch_each, :language, :ignore, :command, :bash_command, :clear_each, :trello_list_id, :trello_labels, :trello_members_ids, :color, :name, :report_each, :timer, :config, :last_id, :alias, :format
9
+
10
+ def initialize(config={})
11
+ @config = config
12
+ init_config
13
+ if @bash_command == ""
14
+ start
15
+ end
16
+ end
17
+
18
+ def init_config
19
+ @timer = 0
20
+ @messages = {}
21
+ @name = config["name"]
22
+ @path = config["path"]
23
+ @condition = config["condition"]
24
+ @lines = config["lines"]
25
+ @language = config["language"]
26
+ @ignore = config["ignore"]
27
+ @command = config["command"]
28
+ @bash_command = config["bash_command"]
29
+ @fetch_each = config["fetch_each"]
30
+ @clear_each = config["clear_each"]
31
+ @report_each = config["report_each"]
32
+ @trello_list_id = config["trello_list_id"]
33
+ @trello_labels = config["trello_labels"].downcase.split(',').map(&:strip).map(&:to_sym) if config["trello_labels"]
34
+ @trello_members_ids = config["trello_members_ids"].split(',').map(&:strip) if config["trello_members_ids"]
35
+ @color = config["color"]
36
+ @alias = config["alias"]
37
+ @last_id = 0
38
+ @format = config["format"]
39
+ end
40
+
41
+ def start
42
+
43
+ one_at_a_time = Mutex.new
44
+
45
+ Thread.new do
46
+ loop do
47
+ one_at_a_time.synchronize do
48
+ if @timer % @fetch_each == 0
49
+ fetch
50
+ end
51
+ if @timer % @clear_each == 0
52
+ clear
53
+ end
54
+ if @timer % @report_each == 0
55
+ report
56
+ end
57
+ @timer += 1
58
+ sleep 1*60
59
+ end
60
+ end
61
+ end
62
+
63
+ end
64
+
65
+ def fetch
66
+ file = File.open(@path)
67
+ file_lines = file.readlines.map(&:chomp)
68
+ @ignore.each{|i| file_lines.delete(i) }
69
+
70
+ file_lines.each_with_index do |line, i|
71
+ if line.include? @condition
72
+ if @messages["#{file_lines[i+1]}"].nil?
73
+ @last_id += 1
74
+ @messages["#{file_lines[i+1]}"] = {
75
+ id: "#{@alias}-#{@last_id}",
76
+ trigger: "Completed 500 Internal Server Error",
77
+ lines: file_lines[i..(i+@lines)],
78
+ count: 1,
79
+ reported: false,
80
+ index: i
81
+ }
82
+ else
83
+ @messages["#{file_lines[i+1]}"][:count] += 1
84
+ end
85
+ end
86
+ end
87
+ end
88
+
89
+ def message_by_id(id)
90
+ @messages.each do |k, v|
91
+ return v if v[:id] == id
92
+ end
93
+ end
94
+
95
+ def last_message
96
+ message_by_id("#{@alias}-#{@last_id}")
97
+ end
98
+
99
+ def lines_to_code(message)
100
+ "#{message[:lines].join("\n")}"
101
+ end
102
+
103
+ def truncate_lines(lines, length)
104
+ lines.gsub(/^(.{50,}?).*/m,'\1...')
105
+ end
106
+
107
+ def report
108
+
109
+ client = Discordrb::Webhooks::Client.new(url: Emissary.webhooks_url)
110
+ client.execute do |builder|
111
+ builder.content = "__**#{Emissary.server_name}**__\n**Report Alert** from **#{@name}** at #{Time.now}"
112
+ builder.add_embed do |embed|
113
+ embed.title = "#{@condition}"
114
+ embed.description = "**Ocurrences: **\n#{@messages.count{|k,v| v[:reported] == false}}"
115
+ embed.color = @color
116
+ embed.timestamp = Time.now
117
+ embed.fields = []
118
+ @messages.each do |k, v|
119
+ unless v[:reported]
120
+ embed.fields.push({
121
+ "name": "**ID: #{v[:id]}**\n\nOcurrences: #{v[:count]}",
122
+ "value": formatted("```#{@language}\n#{v[:lines][0]}\n#{v[:lines][1]}```")
123
+ })
124
+ v[:reported] = true
125
+ end
126
+ end
127
+ end
128
+ end
129
+ end
130
+
131
+ def message_to_chat(message)
132
+ formatted("#{Emissary.header}\n**ID: #{message[:id]}**\nOcurrences: #{message[:count]}\n\n```#{@language}\n#{lines_to_code(message)}```")
133
+ end
134
+
135
+ def clear
136
+ init_config
137
+ end
138
+
139
+ def create_trello_card(message)
140
+ client = Trello::Client.new(
141
+ developer_public_key: Emissary.trello_public_key,
142
+ member_token: Emissary.trello_member_token
143
+ )
144
+
145
+ card = client.create(:card,
146
+ {
147
+ 'name' => message[:lines][1],
148
+ 'desc' => "Ocurrences: #{message[:count]}\n\n```#{@language}\n#{lines_to_code(message)}```",
149
+ 'idList' => @trello_list_id,
150
+ 'labels' => @trello_labels,
151
+ 'idMembers' => @trello_members_ids,
152
+ }
153
+ )
154
+
155
+ card.url
156
+ end
157
+
158
+ def formatted(text)
159
+ if @format != ""
160
+ text.gsub(@format["from"], @format["to"])
161
+ else
162
+ text
163
+ end
164
+ end
165
+
166
+ def syscall
167
+ begin
168
+ stdout, stderr, status = Open3.capture3(@bash_command)
169
+ status.success? && formatted(stdout.slice!(0..-(1 + $/.size)).gsub(/^(.{1500,}?).*/m,'\1...'))# strip trailing eol
170
+ rescue
171
+ "The command #{@bash_command} could not be executed"
172
+ end
173
+ end
174
+ end
metadata ADDED
@@ -0,0 +1,163 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: emissary-ruby
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - MakarovCode
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2021-06-13 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
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: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: discordrb
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 3.4.2
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 3.4.2
55
+ - !ruby/object:Gem::Dependency
56
+ name: ruby-trello
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 3.0.0
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 3.0.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: bundler
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '2.0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '2.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rake
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '10.0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '10.0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: discordrb
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: 3.4.2
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: 3.4.2
111
+ - !ruby/object:Gem::Dependency
112
+ name: ruby-trello
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: 3.0.0
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: 3.0.0
125
+ description:
126
+ email:
127
+ - simoncorreaocampo@gmail.com
128
+ executables: []
129
+ extensions: []
130
+ extra_rdoc_files: []
131
+ files:
132
+ - ".gitignore"
133
+ - LICENSE
134
+ - README.md
135
+ - lib/emissary.rb
136
+ - lib/loggr.json
137
+ - lib/loggr.rb
138
+ homepage: https://github.com/MakarovCode/Emissary
139
+ licenses:
140
+ - MIT
141
+ metadata: {}
142
+ post_install_message:
143
+ rdoc_options: []
144
+ require_paths:
145
+ - lib
146
+ required_ruby_version: !ruby/object:Gem::Requirement
147
+ requirements:
148
+ - - ">="
149
+ - !ruby/object:Gem::Version
150
+ version: '0'
151
+ required_rubygems_version: !ruby/object:Gem::Requirement
152
+ requirements:
153
+ - - ">="
154
+ - !ruby/object:Gem::Version
155
+ version: '0'
156
+ requirements: []
157
+ rubygems_version: 3.1.2
158
+ signing_key:
159
+ specification_version: 4
160
+ summary: Simple error catcher integrated with services like Discord and Trello, use
161
+ chatbots to monitor your application and server. Receive error catching reports
162
+ to a Discord Server Channel, and use chatbots to send commands and fetch reports.
163
+ test_files: []