doctor-strange 0.1.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.
- checksums.yaml +7 -0
- data/README.md +315 -0
- data/Rakefile +11 -0
- data/app/controllers/doctor_strange/health_controller.rb +47 -0
- data/app/views/doctor_strange/health/check.html.erb +54 -0
- data/config/routes.rb +5 -0
- data/lib/doctor-strange.rb +8 -0
- data/lib/doctor_strange/configuration.rb +44 -0
- data/lib/doctor_strange/engine.rb +5 -0
- data/lib/doctor_strange/monitor.rb +51 -0
- data/lib/doctor_strange/providers/base.rb +39 -0
- data/lib/doctor_strange/providers/cache.rb +26 -0
- data/lib/doctor_strange/providers/database.rb +16 -0
- data/lib/doctor_strange/providers/email.rb +49 -0
- data/lib/doctor_strange/providers/payment.rb +48 -0
- data/lib/doctor_strange/providers/redis.rb +77 -0
- data/lib/doctor_strange/providers/resque.rb +16 -0
- data/lib/doctor_strange/providers/sidekiq.rb +81 -0
- data/lib/doctor_strange/version.rb +5 -0
- metadata +402 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 782f2977af71550ceaaf9c022cb0ebe2a64c848a
|
|
4
|
+
data.tar.gz: 026347d2385308caf7fc6e94783c8cbcaa673622
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 38e0ca7bef140169251ad1ca321f8abdc286f6285e361582b10aa1158b551c6c1a170bd3ed7131d236335c0612a8dfb13a599b3b1e5e38dabeda867775fe4146
|
|
7
|
+
data.tar.gz: 4e263004f6940811be98d4d8cccf45121121d33b74cb933bff102cc3783592062c1a3bc5b54e77573e92078a563b2912c7f05257e2cad38c3195b37c3e8f31cf
|
data/README.md
ADDED
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
# Doctor Strange
|
|
2
|
+
|
|
3
|
+
[](https://circleci.com/gh/SiliconJungles/doctor-strange)
|
|
4
|
+
|
|
5
|
+
Monitoring various services (db, cache, sidekiq/resque, email, redis, payment, etc).
|
|
6
|
+
|
|
7
|
+
## Examples
|
|
8
|
+
|
|
9
|
+
### HTML Status Page
|
|
10
|
+
|
|
11
|
+

|
|
12
|
+
|
|
13
|
+
### JSON Response
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
>> curl -s http://localhost:3000/check.json | json_pp
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
```json
|
|
20
|
+
{
|
|
21
|
+
"results": [{
|
|
22
|
+
"name": "Database",
|
|
23
|
+
"message": "",
|
|
24
|
+
"status": "OK"
|
|
25
|
+
}, {
|
|
26
|
+
"name": "Redis",
|
|
27
|
+
"message": "",
|
|
28
|
+
"status": "OK"
|
|
29
|
+
}, {
|
|
30
|
+
"name": "Sidekiq",
|
|
31
|
+
"message": "",
|
|
32
|
+
"status": "OK"
|
|
33
|
+
}, {
|
|
34
|
+
"name": "Email",
|
|
35
|
+
"message": "",
|
|
36
|
+
"status": "OK"
|
|
37
|
+
}, {
|
|
38
|
+
"name": "Payment",
|
|
39
|
+
"message": "",
|
|
40
|
+
"status": "OK"
|
|
41
|
+
}],
|
|
42
|
+
"status": "ok",
|
|
43
|
+
"timestamp": "2018-03-12 16:36:55 +0800"
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### XML Response
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
>> curl -s http://localhost:3000/check.xml
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
```xml
|
|
54
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
55
|
+
<hash>
|
|
56
|
+
<results type="array">
|
|
57
|
+
<result>
|
|
58
|
+
<name>Database</name>
|
|
59
|
+
<message />
|
|
60
|
+
<status>OK</status>
|
|
61
|
+
</result>
|
|
62
|
+
<result>
|
|
63
|
+
<name>Redis</name>
|
|
64
|
+
<message />
|
|
65
|
+
<status>OK</status>
|
|
66
|
+
</result>
|
|
67
|
+
<result>
|
|
68
|
+
<name>Sidekiq</name>
|
|
69
|
+
<message />
|
|
70
|
+
<status>OK</status>
|
|
71
|
+
</result>
|
|
72
|
+
<result>
|
|
73
|
+
<name>Email</name>
|
|
74
|
+
<message />
|
|
75
|
+
<status>OK</status>
|
|
76
|
+
</result>
|
|
77
|
+
<result>
|
|
78
|
+
<name>Payment</name>
|
|
79
|
+
<message />
|
|
80
|
+
<status>OK</status>
|
|
81
|
+
</result>
|
|
82
|
+
</results>
|
|
83
|
+
<status type="symbol">ok</status>
|
|
84
|
+
<timestamp>2018-03-12 16:38:31 +0800</timestamp>
|
|
85
|
+
</hash>
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Setup
|
|
89
|
+
|
|
90
|
+
If you are using bundler add doctor-strange to your Gemfile:
|
|
91
|
+
|
|
92
|
+
```ruby
|
|
93
|
+
gem 'doctor-strange'
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Then run:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
$ bundle install
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Otherwise install the gem:
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
$ gem install doctor-strange
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Usage
|
|
109
|
+
You can mount this inside your app routes by adding this to config/routes.rb:
|
|
110
|
+
|
|
111
|
+
```ruby
|
|
112
|
+
mount DoctorStrange::Engine, at: '/'
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Supported Service Providers
|
|
116
|
+
The following services are currently supported:
|
|
117
|
+
|
|
118
|
+
* DB
|
|
119
|
+
* Cache
|
|
120
|
+
* Redis
|
|
121
|
+
* Sidekiq
|
|
122
|
+
* Resque
|
|
123
|
+
* Stripe
|
|
124
|
+
* MailGun
|
|
125
|
+
|
|
126
|
+
## Configuration
|
|
127
|
+
|
|
128
|
+
### Adding AppName
|
|
129
|
+
|
|
130
|
+
The app name is `SiliconJungles` by default. You can change to your app name.
|
|
131
|
+
|
|
132
|
+
```ruby
|
|
133
|
+
DoctorStrange.configure do |config|
|
|
134
|
+
config.app_name = "YOUR_APP_NAME"
|
|
135
|
+
end
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Adding Providers
|
|
139
|
+
By default, only the database check is enabled. You can add more service providers by explicitly enabling them via an initializer:
|
|
140
|
+
|
|
141
|
+
```ruby
|
|
142
|
+
DoctorStrange.configure do |config|
|
|
143
|
+
config.cache
|
|
144
|
+
config.redis
|
|
145
|
+
config.sidekiq
|
|
146
|
+
# etc
|
|
147
|
+
end
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
We believe that having the database check enabled by default is very important, but if you still want to disable it
|
|
151
|
+
(e.g., if you use a database that isn't covered by the check) - you can do that by calling the `no_database` method:
|
|
152
|
+
|
|
153
|
+
```ruby
|
|
154
|
+
DoctorStrange.configure do |config|
|
|
155
|
+
config.no_database
|
|
156
|
+
end
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Provider Configuration
|
|
160
|
+
|
|
161
|
+
Some of the providers can also accept additional configuration:
|
|
162
|
+
|
|
163
|
+
```ruby
|
|
164
|
+
# Sidekiq
|
|
165
|
+
DoctorStrange.configure do |config|
|
|
166
|
+
config.sidekiq.configure do |sidekiq_config|
|
|
167
|
+
sidekiq_config.latency = 3.hours
|
|
168
|
+
sidekiq_config.queue_size = 50
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
```ruby
|
|
174
|
+
# Redis
|
|
175
|
+
DoctorStrange.configure do |config|
|
|
176
|
+
config.redis.configure do |redis_config|
|
|
177
|
+
redis_config.connection = Redis.current # use your custom redis connection
|
|
178
|
+
redis_config.url = 'redis://user:pass@example.redis.com:90210/' # or URL
|
|
179
|
+
redis_config.max_used_memory = 200 # Megabytes
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
```ruby
|
|
185
|
+
# Email - MailGun by default
|
|
186
|
+
DoctorStrange.configure do |config|
|
|
187
|
+
config.email.configure do |email_config|
|
|
188
|
+
email_config.api_key = "abcd"
|
|
189
|
+
email_config.domain = "foo.bar"
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
```ruby
|
|
195
|
+
# Payment - Stripe by default
|
|
196
|
+
DoctorStrange.configure do |config|
|
|
197
|
+
config.payment.configure do |payment_config|
|
|
198
|
+
payment_config.api_key = "sk_live_xxxxx"
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
The currently supported settings are:
|
|
204
|
+
|
|
205
|
+
#### Sidekiq
|
|
206
|
+
|
|
207
|
+
* `latency`: the latency (in seconds) of a queue (now - when the oldest job was enqueued) which is considered unhealthy (the default is 30 seconds, but larger processing queue should have a larger latency value).
|
|
208
|
+
* `queue_size`: the size (maximim) of a queue which is considered unhealthy (the default is 100).
|
|
209
|
+
|
|
210
|
+
#### Redis
|
|
211
|
+
|
|
212
|
+
* `url`: the url used to connect to your Redis instance - note, this is an optional configuration and will use the default connection if not specified
|
|
213
|
+
* `connection`: Use custom redis connection (e.g., `Redis.current`).
|
|
214
|
+
* `max_used_memory`: Set maximum expected memory usage of Redis in megabytes. Prevent memory leaks and keys overstore.
|
|
215
|
+
|
|
216
|
+
#### Email
|
|
217
|
+
|
|
218
|
+
- Default transaction email service for now is `MailGun`.
|
|
219
|
+
|
|
220
|
+
* `api_key`: the mail service api_key - this is a required value and will return unhealthy if not specified
|
|
221
|
+
* `domain`: the mail service domain value - this is a required value and will return unhealthy if not specified.
|
|
222
|
+
|
|
223
|
+
#### Payment
|
|
224
|
+
|
|
225
|
+
- Default payment service for now is `Stripe`.
|
|
226
|
+
|
|
227
|
+
* `api_key`: The Payment service's api_key - returns unhealthy if not specified or invalid.
|
|
228
|
+
|
|
229
|
+
### Adding a Custom Provider
|
|
230
|
+
It's also possible to add custom health check providers suited for your needs (of course, it's highly appreciated and encouraged if you'd contribute useful providers to the project).
|
|
231
|
+
|
|
232
|
+
In order to add a custom provider, you'd need to:
|
|
233
|
+
|
|
234
|
+
* Implement the `DoctorStrange::Providers::Base` class and its `check!` method (a check is considered as failed if it raises an exception):
|
|
235
|
+
|
|
236
|
+
```ruby
|
|
237
|
+
class CustomProvider < DoctorStrange::Providers::Base
|
|
238
|
+
def check!
|
|
239
|
+
raise 'Oh oh!'
|
|
240
|
+
end
|
|
241
|
+
end
|
|
242
|
+
```
|
|
243
|
+
* Add its class to the configuration:
|
|
244
|
+
|
|
245
|
+
```ruby
|
|
246
|
+
DoctorStrange.configure do |config|
|
|
247
|
+
config.add_custom_provider(CustomProvider)
|
|
248
|
+
end
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
### Adding a Custom Error Callback
|
|
252
|
+
If you need to perform any additional error handling (for example, for additional error reporting), you can configure a custom error callback:
|
|
253
|
+
|
|
254
|
+
```ruby
|
|
255
|
+
DoctorStrange.configure do |config|
|
|
256
|
+
config.error_callback = proc do |e|
|
|
257
|
+
logger.error "Health check failed with: #{e.message}"
|
|
258
|
+
|
|
259
|
+
Raven.capture_exception(e)
|
|
260
|
+
end
|
|
261
|
+
end
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### Adding Authentication Credentials
|
|
265
|
+
By default, the `/check` endpoint is not authenticated and is available to any user. You can authenticate using HTTP Basic Auth by providing authentication credentials:
|
|
266
|
+
|
|
267
|
+
```ruby
|
|
268
|
+
DoctorStrange.configure do |config|
|
|
269
|
+
config.basic_auth_credentials = {
|
|
270
|
+
username: 'SECRET_NAME',
|
|
271
|
+
password: 'Shhhhh!!!'
|
|
272
|
+
}
|
|
273
|
+
end
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### Adding Environment Variables
|
|
277
|
+
By default, environment variables is `nil`, so if you'd want to include additional parameters in the results JSON, all you need is to provide a `Hash` with your custom environment variables:
|
|
278
|
+
|
|
279
|
+
```ruby
|
|
280
|
+
DoctorStrange.configure do |config|
|
|
281
|
+
config.environment_variables = {
|
|
282
|
+
build_number: 'BUILD_NUMBER',
|
|
283
|
+
git_sha: 'GIT_SHA'
|
|
284
|
+
}
|
|
285
|
+
end
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
## TODO
|
|
289
|
+
|
|
290
|
+
- [ ] Support another transaction Email services such as: SES, Mandrill by MailChimp, SendGird, AliCloud's DirectMail, etc.
|
|
291
|
+
|
|
292
|
+
- [ ] Support another payment services such as: Adyen, Braintree, etc.
|
|
293
|
+
|
|
294
|
+
## License
|
|
295
|
+
|
|
296
|
+
The MIT License (MIT)
|
|
297
|
+
|
|
298
|
+
Copyright (c) 2018
|
|
299
|
+
|
|
300
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
301
|
+
this software and associated documentation files (the "Software"), to deal in
|
|
302
|
+
the Software without restriction, including without limitation the rights to
|
|
303
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
304
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
|
305
|
+
subject to the following conditions:
|
|
306
|
+
|
|
307
|
+
The above copyright notice and this permission notice shall be included in all
|
|
308
|
+
copies or substantial portions of the Software.
|
|
309
|
+
|
|
310
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
311
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
312
|
+
FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
313
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
314
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
315
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
module DoctorStrange
|
|
2
|
+
class HealthController < ActionController::Base
|
|
3
|
+
protect_from_forgery with: :exception
|
|
4
|
+
|
|
5
|
+
if Rails.version.starts_with? '3'
|
|
6
|
+
before_filter :authenticate_with_basic_auth
|
|
7
|
+
else
|
|
8
|
+
before_action :authenticate_with_basic_auth
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def check
|
|
12
|
+
@statuses = statuses
|
|
13
|
+
@app_name = DoctorStrange.configuration.app_name
|
|
14
|
+
|
|
15
|
+
respond_to do |format|
|
|
16
|
+
format.html
|
|
17
|
+
format.json do
|
|
18
|
+
render json: statuses.to_json
|
|
19
|
+
end
|
|
20
|
+
format.xml do
|
|
21
|
+
render xml: statuses.to_xml
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
def statuses
|
|
29
|
+
res = DoctorStrange.check(request: request)
|
|
30
|
+
res.merge(env_vars)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def env_vars
|
|
34
|
+
v = DoctorStrange.configuration.environment_variables || {}
|
|
35
|
+
v.empty? ? {} : { environment_variables: v }
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def authenticate_with_basic_auth
|
|
39
|
+
return true unless DoctorStrange.configuration.basic_auth_credentials
|
|
40
|
+
|
|
41
|
+
credentials = DoctorStrange.configuration.basic_auth_credentials
|
|
42
|
+
authenticate_or_request_with_http_basic do |name, password|
|
|
43
|
+
name == credentials[:username] && password == credentials[:password]
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<title><%= @app_name %>Status</title>
|
|
5
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
7
|
+
<meta name="description" content="<%= @app_name %> Status">
|
|
8
|
+
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/css/bootstrap.min.css">
|
|
9
|
+
</head>
|
|
10
|
+
|
|
11
|
+
<body>
|
|
12
|
+
<div class="container">
|
|
13
|
+
<h1 class="text-center"><%= @app_name %> Status Page</h1>
|
|
14
|
+
<table class="table table-hover table-bordered">
|
|
15
|
+
<thead>
|
|
16
|
+
<tr>
|
|
17
|
+
<th scope="col">#</th>
|
|
18
|
+
<th scope="col">Service</th>
|
|
19
|
+
<th scope="col">Status</th>
|
|
20
|
+
</tr>
|
|
21
|
+
</thead>
|
|
22
|
+
<tbody>
|
|
23
|
+
<% @statuses[:results].each_with_index do |status, index| %>
|
|
24
|
+
<% class_name = status[:status].downcase == 'error' ? 'text-danger' : 'text-success' %>
|
|
25
|
+
<tr>
|
|
26
|
+
<th scope="row"><%= index + 1 %></th>
|
|
27
|
+
<td> <%= status[:name] %></td>
|
|
28
|
+
<td class="<%= class_name %>">
|
|
29
|
+
<p><%= status[:status] %></p>
|
|
30
|
+
<%= status[:message] %>
|
|
31
|
+
</td>
|
|
32
|
+
</tr>
|
|
33
|
+
<% end %>
|
|
34
|
+
</tbody>
|
|
35
|
+
</table>
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
<!-- <div class="statuses">
|
|
39
|
+
<h1><%= @app_name %> Status Page</h1>
|
|
40
|
+
<% @statuses[:results].each do |status| %>
|
|
41
|
+
<div class="status status-<%= status[:status].downcase %>">
|
|
42
|
+
<div class="status-heading">
|
|
43
|
+
<span class="name"><%= status[:name] %></span>
|
|
44
|
+
<span class="state"><%= status[:status] %></span>
|
|
45
|
+
</div>
|
|
46
|
+
<div class="message"><%= status[:message] %></div>
|
|
47
|
+
</div>
|
|
48
|
+
<% end %>
|
|
49
|
+
</div> -->
|
|
50
|
+
<div class="text-center">
|
|
51
|
+
Powered by <a href="https://github.com/SiliconJungles/doctor-strange.git" target="_blank">Doctor Strange - SiliconJungles Team</a>
|
|
52
|
+
</div>
|
|
53
|
+
</div>
|
|
54
|
+
</body>
|
data/config/routes.rb
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
module DoctorStrange
|
|
2
|
+
class Configuration
|
|
3
|
+
PROVIDERS = %i[cache database redis resque sidekiq email payment].freeze
|
|
4
|
+
|
|
5
|
+
DEFAULT_APP_NAME = "SiliconJungles".freeze
|
|
6
|
+
|
|
7
|
+
attr_accessor :error_callback, :basic_auth_credentials, :environment_variables, :app_name
|
|
8
|
+
attr_reader :providers
|
|
9
|
+
|
|
10
|
+
def initialize
|
|
11
|
+
database
|
|
12
|
+
@app_name = DEFAULT_APP_NAME
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def no_database
|
|
16
|
+
@providers.delete(DoctorStrange::Providers::Database)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
PROVIDERS.each do |provider_name|
|
|
20
|
+
define_method provider_name do |&_block|
|
|
21
|
+
require "doctor_strange/providers/#{provider_name}"
|
|
22
|
+
|
|
23
|
+
add_provider("DoctorStrange::Providers::#{provider_name.capitalize}".constantize)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def add_custom_provider(custom_provider_class)
|
|
28
|
+
unless custom_provider_class < DoctorStrange::Providers::Base
|
|
29
|
+
raise ArgumentError, 'custom provider class must implement '\
|
|
30
|
+
'DoctorStrange::Providers::Base'
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
add_provider(custom_provider_class)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
def add_provider(provider_class)
|
|
39
|
+
(@providers ||= Set.new) << provider_class
|
|
40
|
+
|
|
41
|
+
provider_class
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
require 'doctor_strange/configuration'
|
|
2
|
+
|
|
3
|
+
module DoctorStrange
|
|
4
|
+
STATUSES = {
|
|
5
|
+
ok: 'OK',
|
|
6
|
+
error: 'ERROR'
|
|
7
|
+
}.freeze
|
|
8
|
+
|
|
9
|
+
extend self
|
|
10
|
+
|
|
11
|
+
attr_accessor :configuration
|
|
12
|
+
|
|
13
|
+
def configure
|
|
14
|
+
self.configuration ||= Configuration.new
|
|
15
|
+
|
|
16
|
+
yield configuration if block_given?
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def check(request: nil)
|
|
20
|
+
results = configuration.providers.map { |provider| provider_result(provider, request) }
|
|
21
|
+
|
|
22
|
+
{
|
|
23
|
+
results: results,
|
|
24
|
+
status: results.all? { |res| res[:status] == STATUSES[:ok] } ? :ok : :service_unavailable,
|
|
25
|
+
timestamp: Time.now.to_s(:rfc2822)
|
|
26
|
+
}
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
def provider_result(provider, request)
|
|
32
|
+
monitor = provider.new(request: request)
|
|
33
|
+
monitor.check!
|
|
34
|
+
|
|
35
|
+
{
|
|
36
|
+
name: provider.provider_name,
|
|
37
|
+
message: '',
|
|
38
|
+
status: STATUSES[:ok]
|
|
39
|
+
}
|
|
40
|
+
rescue StandardError => e
|
|
41
|
+
configuration.error_callback.call(e) if configuration.error_callback
|
|
42
|
+
|
|
43
|
+
{
|
|
44
|
+
name: provider.provider_name,
|
|
45
|
+
message: e.message,
|
|
46
|
+
status: STATUSES[:error]
|
|
47
|
+
}
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
DoctorStrange.configure
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
module DoctorStrange
|
|
2
|
+
module Providers
|
|
3
|
+
class Base
|
|
4
|
+
attr_reader :request
|
|
5
|
+
attr_accessor :configuration
|
|
6
|
+
|
|
7
|
+
def self.provider_name
|
|
8
|
+
@name ||= name.demodulize
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.configure
|
|
12
|
+
return unless configurable?
|
|
13
|
+
|
|
14
|
+
@global_configuration = configuration_class.new
|
|
15
|
+
|
|
16
|
+
yield @global_configuration if block_given?
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def initialize(request: nil)
|
|
20
|
+
@request = request
|
|
21
|
+
|
|
22
|
+
return unless self.class.configurable?
|
|
23
|
+
self.configuration = self.class.instance_variable_get('@global_configuration')
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# @abstract
|
|
27
|
+
def check!
|
|
28
|
+
raise NotImplementedError
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def self.configurable?
|
|
32
|
+
configuration_class
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# @abstract
|
|
36
|
+
def self.configuration_class; end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
require 'doctor_strange/providers/base'
|
|
2
|
+
|
|
3
|
+
module DoctorStrange
|
|
4
|
+
module Providers
|
|
5
|
+
class CacheException < StandardError; end
|
|
6
|
+
|
|
7
|
+
class Cache < Base
|
|
8
|
+
def check!
|
|
9
|
+
time = Time.now.to_s
|
|
10
|
+
|
|
11
|
+
Rails.cache.write(key, time)
|
|
12
|
+
fetched = Rails.cache.read(key)
|
|
13
|
+
|
|
14
|
+
raise "different values (now: #{time}, fetched: #{fetched})" if fetched != time
|
|
15
|
+
rescue StandardError => e
|
|
16
|
+
raise CacheException, e.message
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
def key
|
|
22
|
+
@key ||= ['health', request.try(:remote_ip)].join(':')
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
require 'doctor_strange/providers/base'
|
|
2
|
+
|
|
3
|
+
module DoctorStrange
|
|
4
|
+
module Providers
|
|
5
|
+
class DatabaseException < StandardError; end
|
|
6
|
+
|
|
7
|
+
class Database < Base
|
|
8
|
+
def check!
|
|
9
|
+
# Check connection to the DB:
|
|
10
|
+
ActiveRecord::Base.establish_connection # Establishes connection
|
|
11
|
+
ActiveRecord::Base.connection # Calls connection object
|
|
12
|
+
raise DatabaseException.new("Your database is not connected") unless ActiveRecord::Base.connected?
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
require 'doctor_strange/providers/base'
|
|
2
|
+
require 'mailgun'
|
|
3
|
+
|
|
4
|
+
module DoctorStrange
|
|
5
|
+
module Providers
|
|
6
|
+
class EmailException < StandardError; end
|
|
7
|
+
|
|
8
|
+
class Email < Base
|
|
9
|
+
class Configuration
|
|
10
|
+
DEFAULT_SERVICE_NAME = "MailGun".freeze
|
|
11
|
+
|
|
12
|
+
attr_accessor :api_key, :domain, :service_name
|
|
13
|
+
|
|
14
|
+
def initialize
|
|
15
|
+
@service_name = DEFAULT_SERVICE_NAME
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
class << self
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def configuration_class
|
|
23
|
+
::DoctorStrange::Providers::Email::Configuration
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def check!
|
|
28
|
+
check_required_values!
|
|
29
|
+
check_communication!
|
|
30
|
+
rescue StandardError => e
|
|
31
|
+
raise EmailException, e.message
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def check_required_values!
|
|
37
|
+
raise "The api_key and domain are required" if configuration.api_key.empty? || configuration.domain.empty?
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def check_communication!
|
|
41
|
+
mg_client = Mailgun::Client.new(configuration.api_key)
|
|
42
|
+
domainer = Mailgun::Domains.new(mg_client)
|
|
43
|
+
domainer.list.pluck("name").include? configuration.domain
|
|
44
|
+
rescue Mailgun::CommunicationError
|
|
45
|
+
raise "Cannot communicate to Mailgun"
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
require 'doctor_strange/providers/base'
|
|
2
|
+
require 'stripe'
|
|
3
|
+
|
|
4
|
+
module DoctorStrange
|
|
5
|
+
module Providers
|
|
6
|
+
class PaymentException < StandardError; end
|
|
7
|
+
|
|
8
|
+
class Payment < Base
|
|
9
|
+
class Configuration
|
|
10
|
+
DEFAULT_SERVICE_NAME = "Stripe".freeze
|
|
11
|
+
|
|
12
|
+
attr_accessor :api_key, :service_name
|
|
13
|
+
|
|
14
|
+
def initialize
|
|
15
|
+
@service_name = DEFAULT_SERVICE_NAME
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
class << self
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def configuration_class
|
|
23
|
+
::DoctorStrange::Providers::Payment::Configuration
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def check!
|
|
28
|
+
check_required_values!
|
|
29
|
+
check_communication!
|
|
30
|
+
rescue Exception => e
|
|
31
|
+
raise PaymentException.new(e.message)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def check_required_values!
|
|
37
|
+
raise "The api_key is required" if configuration.api_key.empty?
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def check_communication!
|
|
41
|
+
Stripe.api_key = configuration.api_key
|
|
42
|
+
Stripe::Customer.list(limit: 1)
|
|
43
|
+
rescue Stripe::AuthenticationError
|
|
44
|
+
raise "Invalid API Key provided"
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
require 'doctor_strange/providers/base'
|
|
2
|
+
|
|
3
|
+
module DoctorStrange
|
|
4
|
+
module Providers
|
|
5
|
+
class RedisException < StandardError; end
|
|
6
|
+
|
|
7
|
+
class Redis < Base
|
|
8
|
+
class Configuration
|
|
9
|
+
DEFAULT_URL = nil
|
|
10
|
+
|
|
11
|
+
attr_accessor :url, :connection, :max_used_memory
|
|
12
|
+
|
|
13
|
+
def initialize
|
|
14
|
+
@url = DEFAULT_URL
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
class << self
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
def configuration_class
|
|
22
|
+
::DoctorStrange::Providers::Redis::Configuration
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def check!
|
|
27
|
+
check_values!
|
|
28
|
+
check_max_used_memory!
|
|
29
|
+
rescue Exception => e
|
|
30
|
+
raise RedisException.new(e.message)
|
|
31
|
+
ensure
|
|
32
|
+
redis.close
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
def check_values!
|
|
38
|
+
time = Time.now.to_s(:rfc2822)
|
|
39
|
+
|
|
40
|
+
redis.set(key, time)
|
|
41
|
+
fetched = redis.get(key)
|
|
42
|
+
|
|
43
|
+
raise "different values (now: #{time}, fetched: #{fetched})" if fetched != time
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def check_max_used_memory!
|
|
47
|
+
return unless configuration.max_used_memory
|
|
48
|
+
return if used_memory_mb <= configuration.max_used_memory
|
|
49
|
+
|
|
50
|
+
raise "#{used_memory_mb}Mb memory using is higher than #{configuration.max_used_memory}Mb maximum expected"
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def key
|
|
54
|
+
@key ||= ['health', request.try(:remote_ip)].join(':')
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def redis
|
|
58
|
+
@redis =
|
|
59
|
+
if configuration.connection
|
|
60
|
+
configuration.connection
|
|
61
|
+
elsif configuration.url
|
|
62
|
+
::Redis.new(url: configuration.url)
|
|
63
|
+
else
|
|
64
|
+
::Redis.new
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def bytes_to_megabytes(bytes)
|
|
69
|
+
(bytes.to_f / 1024 / 1024).round
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def used_memory_mb
|
|
73
|
+
bytes_to_megabytes(redis.info['used_memory'])
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
require 'doctor_strange/providers/base'
|
|
2
|
+
require 'resque'
|
|
3
|
+
|
|
4
|
+
module DoctorStrange
|
|
5
|
+
module Providers
|
|
6
|
+
class ResqueException < StandardError; end
|
|
7
|
+
|
|
8
|
+
class Resque < Base
|
|
9
|
+
def check!
|
|
10
|
+
::Resque.info
|
|
11
|
+
rescue Exception => e
|
|
12
|
+
raise ResqueException.new(e.message)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
require 'doctor_strange/providers/base'
|
|
2
|
+
require 'sidekiq/api'
|
|
3
|
+
|
|
4
|
+
module DoctorStrange
|
|
5
|
+
module Providers
|
|
6
|
+
class SidekiqException < StandardError; end
|
|
7
|
+
|
|
8
|
+
class Sidekiq < Base
|
|
9
|
+
class Configuration
|
|
10
|
+
DEFAULT_LATENCY_TIMEOUT = 30
|
|
11
|
+
DEFAULT_QUEUES_SIZE = 100
|
|
12
|
+
|
|
13
|
+
attr_accessor :latency, :queue_size
|
|
14
|
+
|
|
15
|
+
def initialize
|
|
16
|
+
@latency = DEFAULT_LATENCY_TIMEOUT
|
|
17
|
+
@queue_size = DEFAULT_QUEUES_SIZE
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def check!
|
|
22
|
+
check_workers!
|
|
23
|
+
check_processes!
|
|
24
|
+
check_latency!
|
|
25
|
+
check_queue_size!
|
|
26
|
+
check_redis!
|
|
27
|
+
rescue Exception => e
|
|
28
|
+
raise SidekiqException, e.message
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
class << self
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def configuration_class
|
|
37
|
+
::DoctorStrange::Providers::Sidekiq::Configuration
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def check_workers!
|
|
42
|
+
::Sidekiq::Workers.new.size
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def check_processes!
|
|
46
|
+
sidekiq_stats = ::Sidekiq::Stats.new
|
|
47
|
+
return unless sidekiq_stats.processes_size.zero?
|
|
48
|
+
|
|
49
|
+
raise 'Sidekiq alive processes number is 0!'
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def check_latency!
|
|
53
|
+
latency = queue.latency
|
|
54
|
+
|
|
55
|
+
return unless latency > configuration.latency
|
|
56
|
+
|
|
57
|
+
raise "latency #{latency} is greater than #{configuration.latency}"
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def check_queue_size!
|
|
61
|
+
size = queue.size
|
|
62
|
+
|
|
63
|
+
return unless size > configuration.queue_size
|
|
64
|
+
|
|
65
|
+
raise "queue size #{size} is greater than #{configuration.queue_size}"
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def check_redis!
|
|
69
|
+
if ::Sidekiq.respond_to?(:redis_info)
|
|
70
|
+
::Sidekiq.redis_info
|
|
71
|
+
else
|
|
72
|
+
::Sidekiq.redis(&:info)
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
private def queue
|
|
77
|
+
@queue ||= ::Sidekiq::Queue.new
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,402 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: doctor-strange
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- SiliconJungles
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2018-03-12 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: rails
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '4.0'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '4.0'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: appraisal
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '2.2'
|
|
34
|
+
- - ">="
|
|
35
|
+
- !ruby/object:Gem::Version
|
|
36
|
+
version: 2.2.0
|
|
37
|
+
type: :development
|
|
38
|
+
prerelease: false
|
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
40
|
+
requirements:
|
|
41
|
+
- - "~>"
|
|
42
|
+
- !ruby/object:Gem::Version
|
|
43
|
+
version: '2.2'
|
|
44
|
+
- - ">="
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: 2.2.0
|
|
47
|
+
- !ruby/object:Gem::Dependency
|
|
48
|
+
name: capybara
|
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - "~>"
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '2.18'
|
|
54
|
+
- - ">="
|
|
55
|
+
- !ruby/object:Gem::Version
|
|
56
|
+
version: 2.18.0
|
|
57
|
+
type: :development
|
|
58
|
+
prerelease: false
|
|
59
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
60
|
+
requirements:
|
|
61
|
+
- - "~>"
|
|
62
|
+
- !ruby/object:Gem::Version
|
|
63
|
+
version: '2.18'
|
|
64
|
+
- - ">="
|
|
65
|
+
- !ruby/object:Gem::Version
|
|
66
|
+
version: 2.18.0
|
|
67
|
+
- !ruby/object:Gem::Dependency
|
|
68
|
+
name: capybara-screenshot
|
|
69
|
+
requirement: !ruby/object:Gem::Requirement
|
|
70
|
+
requirements:
|
|
71
|
+
- - "~>"
|
|
72
|
+
- !ruby/object:Gem::Version
|
|
73
|
+
version: '1.0'
|
|
74
|
+
- - ">="
|
|
75
|
+
- !ruby/object:Gem::Version
|
|
76
|
+
version: 1.0.18
|
|
77
|
+
type: :development
|
|
78
|
+
prerelease: false
|
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
80
|
+
requirements:
|
|
81
|
+
- - "~>"
|
|
82
|
+
- !ruby/object:Gem::Version
|
|
83
|
+
version: '1.0'
|
|
84
|
+
- - ">="
|
|
85
|
+
- !ruby/object:Gem::Version
|
|
86
|
+
version: 1.0.18
|
|
87
|
+
- !ruby/object:Gem::Dependency
|
|
88
|
+
name: coveralls
|
|
89
|
+
requirement: !ruby/object:Gem::Requirement
|
|
90
|
+
requirements:
|
|
91
|
+
- - "~>"
|
|
92
|
+
- !ruby/object:Gem::Version
|
|
93
|
+
version: '0.8'
|
|
94
|
+
- - ">="
|
|
95
|
+
- !ruby/object:Gem::Version
|
|
96
|
+
version: 0.8.21
|
|
97
|
+
type: :development
|
|
98
|
+
prerelease: false
|
|
99
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
100
|
+
requirements:
|
|
101
|
+
- - "~>"
|
|
102
|
+
- !ruby/object:Gem::Version
|
|
103
|
+
version: '0.8'
|
|
104
|
+
- - ">="
|
|
105
|
+
- !ruby/object:Gem::Version
|
|
106
|
+
version: 0.8.21
|
|
107
|
+
- !ruby/object:Gem::Dependency
|
|
108
|
+
name: database_cleaner
|
|
109
|
+
requirement: !ruby/object:Gem::Requirement
|
|
110
|
+
requirements:
|
|
111
|
+
- - "~>"
|
|
112
|
+
- !ruby/object:Gem::Version
|
|
113
|
+
version: '1.6'
|
|
114
|
+
- - ">="
|
|
115
|
+
- !ruby/object:Gem::Version
|
|
116
|
+
version: 1.6.2
|
|
117
|
+
type: :development
|
|
118
|
+
prerelease: false
|
|
119
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
120
|
+
requirements:
|
|
121
|
+
- - "~>"
|
|
122
|
+
- !ruby/object:Gem::Version
|
|
123
|
+
version: '1.6'
|
|
124
|
+
- - ">="
|
|
125
|
+
- !ruby/object:Gem::Version
|
|
126
|
+
version: 1.6.2
|
|
127
|
+
- !ruby/object:Gem::Dependency
|
|
128
|
+
name: mailgun-ruby
|
|
129
|
+
requirement: !ruby/object:Gem::Requirement
|
|
130
|
+
requirements:
|
|
131
|
+
- - "~>"
|
|
132
|
+
- !ruby/object:Gem::Version
|
|
133
|
+
version: '1.1'
|
|
134
|
+
- - ">="
|
|
135
|
+
- !ruby/object:Gem::Version
|
|
136
|
+
version: 1.1.9
|
|
137
|
+
type: :development
|
|
138
|
+
prerelease: false
|
|
139
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
140
|
+
requirements:
|
|
141
|
+
- - "~>"
|
|
142
|
+
- !ruby/object:Gem::Version
|
|
143
|
+
version: '1.1'
|
|
144
|
+
- - ">="
|
|
145
|
+
- !ruby/object:Gem::Version
|
|
146
|
+
version: 1.1.9
|
|
147
|
+
- !ruby/object:Gem::Dependency
|
|
148
|
+
name: pry
|
|
149
|
+
requirement: !ruby/object:Gem::Requirement
|
|
150
|
+
requirements:
|
|
151
|
+
- - "~>"
|
|
152
|
+
- !ruby/object:Gem::Version
|
|
153
|
+
version: 0.11.3
|
|
154
|
+
type: :development
|
|
155
|
+
prerelease: false
|
|
156
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
157
|
+
requirements:
|
|
158
|
+
- - "~>"
|
|
159
|
+
- !ruby/object:Gem::Version
|
|
160
|
+
version: 0.11.3
|
|
161
|
+
- !ruby/object:Gem::Dependency
|
|
162
|
+
name: rake
|
|
163
|
+
requirement: !ruby/object:Gem::Requirement
|
|
164
|
+
requirements:
|
|
165
|
+
- - "~>"
|
|
166
|
+
- !ruby/object:Gem::Version
|
|
167
|
+
version: '0.8'
|
|
168
|
+
- - ">="
|
|
169
|
+
- !ruby/object:Gem::Version
|
|
170
|
+
version: 0.8.7
|
|
171
|
+
type: :development
|
|
172
|
+
prerelease: false
|
|
173
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
174
|
+
requirements:
|
|
175
|
+
- - "~>"
|
|
176
|
+
- !ruby/object:Gem::Version
|
|
177
|
+
version: '0.8'
|
|
178
|
+
- - ">="
|
|
179
|
+
- !ruby/object:Gem::Version
|
|
180
|
+
version: 0.8.7
|
|
181
|
+
- !ruby/object:Gem::Dependency
|
|
182
|
+
name: rediska
|
|
183
|
+
requirement: !ruby/object:Gem::Requirement
|
|
184
|
+
requirements:
|
|
185
|
+
- - "~>"
|
|
186
|
+
- !ruby/object:Gem::Version
|
|
187
|
+
version: '0.5'
|
|
188
|
+
- - ">="
|
|
189
|
+
- !ruby/object:Gem::Version
|
|
190
|
+
version: 0.5.0
|
|
191
|
+
type: :development
|
|
192
|
+
prerelease: false
|
|
193
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
194
|
+
requirements:
|
|
195
|
+
- - "~>"
|
|
196
|
+
- !ruby/object:Gem::Version
|
|
197
|
+
version: '0.5'
|
|
198
|
+
- - ">="
|
|
199
|
+
- !ruby/object:Gem::Version
|
|
200
|
+
version: 0.5.0
|
|
201
|
+
- !ruby/object:Gem::Dependency
|
|
202
|
+
name: resque
|
|
203
|
+
requirement: !ruby/object:Gem::Requirement
|
|
204
|
+
requirements:
|
|
205
|
+
- - "~>"
|
|
206
|
+
- !ruby/object:Gem::Version
|
|
207
|
+
version: '1.27'
|
|
208
|
+
- - ">="
|
|
209
|
+
- !ruby/object:Gem::Version
|
|
210
|
+
version: 1.27.4
|
|
211
|
+
type: :development
|
|
212
|
+
prerelease: false
|
|
213
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
214
|
+
requirements:
|
|
215
|
+
- - "~>"
|
|
216
|
+
- !ruby/object:Gem::Version
|
|
217
|
+
version: '1.27'
|
|
218
|
+
- - ">="
|
|
219
|
+
- !ruby/object:Gem::Version
|
|
220
|
+
version: 1.27.4
|
|
221
|
+
- !ruby/object:Gem::Dependency
|
|
222
|
+
name: rspec-rails
|
|
223
|
+
requirement: !ruby/object:Gem::Requirement
|
|
224
|
+
requirements:
|
|
225
|
+
- - "~>"
|
|
226
|
+
- !ruby/object:Gem::Version
|
|
227
|
+
version: '3.7'
|
|
228
|
+
- - ">="
|
|
229
|
+
- !ruby/object:Gem::Version
|
|
230
|
+
version: 3.7.2
|
|
231
|
+
type: :development
|
|
232
|
+
prerelease: false
|
|
233
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
234
|
+
requirements:
|
|
235
|
+
- - "~>"
|
|
236
|
+
- !ruby/object:Gem::Version
|
|
237
|
+
version: '3.7'
|
|
238
|
+
- - ">="
|
|
239
|
+
- !ruby/object:Gem::Version
|
|
240
|
+
version: 3.7.2
|
|
241
|
+
- !ruby/object:Gem::Dependency
|
|
242
|
+
name: rspec_junit_formatter
|
|
243
|
+
requirement: !ruby/object:Gem::Requirement
|
|
244
|
+
requirements:
|
|
245
|
+
- - "~>"
|
|
246
|
+
- !ruby/object:Gem::Version
|
|
247
|
+
version: 0.3.0
|
|
248
|
+
type: :development
|
|
249
|
+
prerelease: false
|
|
250
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
251
|
+
requirements:
|
|
252
|
+
- - "~>"
|
|
253
|
+
- !ruby/object:Gem::Version
|
|
254
|
+
version: 0.3.0
|
|
255
|
+
- !ruby/object:Gem::Dependency
|
|
256
|
+
name: rubocop
|
|
257
|
+
requirement: !ruby/object:Gem::Requirement
|
|
258
|
+
requirements:
|
|
259
|
+
- - "~>"
|
|
260
|
+
- !ruby/object:Gem::Version
|
|
261
|
+
version: '0.5'
|
|
262
|
+
type: :development
|
|
263
|
+
prerelease: false
|
|
264
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
265
|
+
requirements:
|
|
266
|
+
- - "~>"
|
|
267
|
+
- !ruby/object:Gem::Version
|
|
268
|
+
version: '0.5'
|
|
269
|
+
- !ruby/object:Gem::Dependency
|
|
270
|
+
name: sidekiq
|
|
271
|
+
requirement: !ruby/object:Gem::Requirement
|
|
272
|
+
requirements:
|
|
273
|
+
- - "~>"
|
|
274
|
+
- !ruby/object:Gem::Version
|
|
275
|
+
version: '3.0'
|
|
276
|
+
type: :development
|
|
277
|
+
prerelease: false
|
|
278
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
279
|
+
requirements:
|
|
280
|
+
- - "~>"
|
|
281
|
+
- !ruby/object:Gem::Version
|
|
282
|
+
version: '3.0'
|
|
283
|
+
- !ruby/object:Gem::Dependency
|
|
284
|
+
name: spork
|
|
285
|
+
requirement: !ruby/object:Gem::Requirement
|
|
286
|
+
requirements:
|
|
287
|
+
- - "~>"
|
|
288
|
+
- !ruby/object:Gem::Version
|
|
289
|
+
version: 0.9.2
|
|
290
|
+
type: :development
|
|
291
|
+
prerelease: false
|
|
292
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
293
|
+
requirements:
|
|
294
|
+
- - "~>"
|
|
295
|
+
- !ruby/object:Gem::Version
|
|
296
|
+
version: 0.9.2
|
|
297
|
+
- !ruby/object:Gem::Dependency
|
|
298
|
+
name: sqlite3
|
|
299
|
+
requirement: !ruby/object:Gem::Requirement
|
|
300
|
+
requirements:
|
|
301
|
+
- - "~>"
|
|
302
|
+
- !ruby/object:Gem::Version
|
|
303
|
+
version: '1.3'
|
|
304
|
+
- - ">="
|
|
305
|
+
- !ruby/object:Gem::Version
|
|
306
|
+
version: 1.3.13
|
|
307
|
+
type: :development
|
|
308
|
+
prerelease: false
|
|
309
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
310
|
+
requirements:
|
|
311
|
+
- - "~>"
|
|
312
|
+
- !ruby/object:Gem::Version
|
|
313
|
+
version: '1.3'
|
|
314
|
+
- - ">="
|
|
315
|
+
- !ruby/object:Gem::Version
|
|
316
|
+
version: 1.3.13
|
|
317
|
+
- !ruby/object:Gem::Dependency
|
|
318
|
+
name: stripe
|
|
319
|
+
requirement: !ruby/object:Gem::Requirement
|
|
320
|
+
requirements:
|
|
321
|
+
- - "~>"
|
|
322
|
+
- !ruby/object:Gem::Version
|
|
323
|
+
version: '3.11'
|
|
324
|
+
- - ">="
|
|
325
|
+
- !ruby/object:Gem::Version
|
|
326
|
+
version: 3.11.0
|
|
327
|
+
type: :development
|
|
328
|
+
prerelease: false
|
|
329
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
330
|
+
requirements:
|
|
331
|
+
- - "~>"
|
|
332
|
+
- !ruby/object:Gem::Version
|
|
333
|
+
version: '3.11'
|
|
334
|
+
- - ">="
|
|
335
|
+
- !ruby/object:Gem::Version
|
|
336
|
+
version: 3.11.0
|
|
337
|
+
- !ruby/object:Gem::Dependency
|
|
338
|
+
name: timecop
|
|
339
|
+
requirement: !ruby/object:Gem::Requirement
|
|
340
|
+
requirements:
|
|
341
|
+
- - "~>"
|
|
342
|
+
- !ruby/object:Gem::Version
|
|
343
|
+
version: 0.9.1
|
|
344
|
+
type: :development
|
|
345
|
+
prerelease: false
|
|
346
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
347
|
+
requirements:
|
|
348
|
+
- - "~>"
|
|
349
|
+
- !ruby/object:Gem::Version
|
|
350
|
+
version: 0.9.1
|
|
351
|
+
description: A Rails plug-in, which checks various services (db, cache, sidekiq, redis,
|
|
352
|
+
stripe, mailgun, etc.).
|
|
353
|
+
email:
|
|
354
|
+
- developers@siliconjungles.com
|
|
355
|
+
executables: []
|
|
356
|
+
extensions: []
|
|
357
|
+
extra_rdoc_files: []
|
|
358
|
+
files:
|
|
359
|
+
- README.md
|
|
360
|
+
- Rakefile
|
|
361
|
+
- app/controllers/doctor_strange/health_controller.rb
|
|
362
|
+
- app/views/doctor_strange/health/check.html.erb
|
|
363
|
+
- config/routes.rb
|
|
364
|
+
- lib/doctor-strange.rb
|
|
365
|
+
- lib/doctor_strange/configuration.rb
|
|
366
|
+
- lib/doctor_strange/engine.rb
|
|
367
|
+
- lib/doctor_strange/monitor.rb
|
|
368
|
+
- lib/doctor_strange/providers/base.rb
|
|
369
|
+
- lib/doctor_strange/providers/cache.rb
|
|
370
|
+
- lib/doctor_strange/providers/database.rb
|
|
371
|
+
- lib/doctor_strange/providers/email.rb
|
|
372
|
+
- lib/doctor_strange/providers/payment.rb
|
|
373
|
+
- lib/doctor_strange/providers/redis.rb
|
|
374
|
+
- lib/doctor_strange/providers/resque.rb
|
|
375
|
+
- lib/doctor_strange/providers/sidekiq.rb
|
|
376
|
+
- lib/doctor_strange/version.rb
|
|
377
|
+
homepage: https://github.com/SiliconJungles/doctor-strange
|
|
378
|
+
licenses:
|
|
379
|
+
- MIT
|
|
380
|
+
metadata: {}
|
|
381
|
+
post_install_message:
|
|
382
|
+
rdoc_options: []
|
|
383
|
+
require_paths:
|
|
384
|
+
- lib
|
|
385
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
386
|
+
requirements:
|
|
387
|
+
- - ">="
|
|
388
|
+
- !ruby/object:Gem::Version
|
|
389
|
+
version: '0'
|
|
390
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
391
|
+
requirements:
|
|
392
|
+
- - ">="
|
|
393
|
+
- !ruby/object:Gem::Version
|
|
394
|
+
version: '0'
|
|
395
|
+
requirements: []
|
|
396
|
+
rubyforge_project:
|
|
397
|
+
rubygems_version: 2.6.13
|
|
398
|
+
signing_key:
|
|
399
|
+
specification_version: 4
|
|
400
|
+
summary: A Rails plug-in, which checks various services (db, cache, sidekiq, redis,
|
|
401
|
+
stripe, mailgun, etc.)
|
|
402
|
+
test_files: []
|