heroku_mongo_watcher 0.0.4.beta → 0.1.0.beta
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.
- data/README.md +6 -7
- data/bin/watcher +1 -1
- data/heroku_mongo_watcher.gemspec +1 -0
- data/lib/heroku_mongo_watcher/cli.rb +23 -8
- data/lib/heroku_mongo_watcher/configuration.rb +8 -0
- data/lib/heroku_mongo_watcher/data_row.rb +27 -11
- data/lib/heroku_mongo_watcher/version.rb +1 -1
- metadata +18 -7
data/README.md
CHANGED
@@ -17,14 +17,14 @@ It needed to accomplish the following:
|
|
17
17
|
|
18
18
|
The output looks like the following ...
|
19
19
|
|
20
|
-
|<---- heroku stats
|
21
|
-
dyno reqs art max r_err w_err wait queue slowest
|
22
|
-
20 76 27 586 0 0
|
23
|
-
20 1592 62 1292 0 0
|
20
|
+
|<---- heroku stats ----------------------------------------------------------------------->|<----mongo stats ------------------------------------------------------->|
|
21
|
+
dyno reqs art max r_err w_err %err wait queue slowest | insert query update faults locked qr|qw netI/O time |
|
22
|
+
20 76 27 586 0 0 0.0% 0 0 /pxl/4fdbc97dc6b36c003000| 0 0 0 0 0 0|0 305b/257b 15:03:19
|
23
|
+
20 1592 62 1292 0 0 0.0% 0 0 /assets/companions/5009ab| 17 2 32 0 1.2 0|0 14k/26k 15:04:19
|
24
24
|
[4] VAST Error
|
25
25
|
[28] Timeout::Error
|
26
26
|
[11] Cannot find impression when looking for asset
|
27
|
-
20 23935 190 7144 0 43 0
|
27
|
+
20 23935 190 7144 0 43 0.0% 0 0 /crossdomain.xml| 307 0 618 1 21.6 0|0 260k/221k 15:05:19
|
28
28
|
|
29
29
|
### Legend
|
30
30
|
<table>
|
@@ -42,8 +42,7 @@ The output looks like the following ...
|
|
42
42
|
<tr><td>update</td><td>number of mongo updates</td></tr>
|
43
43
|
<tr><td>faults</td><td>number of mongo page faults</td></tr>
|
44
44
|
<tr><td>qr|qw</td><td>number of mongo's queued read and writes</td></tr>
|
45
|
-
<tr><td>
|
46
|
-
<tr><td>netOut</td><td>size on mongo net out</td></tr>
|
45
|
+
<tr><td>netIO</td><td>size on mongo net in/ net out</td></tr>
|
47
46
|
<tr><td>time</td><td>the time sampled</td></tr>
|
48
47
|
</table>
|
49
48
|
|
data/bin/watcher
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'heroku_mongo_watcher/configuration'
|
2
2
|
require 'heroku_mongo_watcher/data_row'
|
3
|
+
require 'trollop'
|
3
4
|
|
4
5
|
#http://stackoverflow.com/a/9117903/192791
|
5
6
|
require 'net/smtp'
|
@@ -20,7 +21,7 @@ class HerokuMongoWatcher::CLI
|
|
20
21
|
HerokuMongoWatcher::Configuration.instance.config
|
21
22
|
end
|
22
23
|
|
23
|
-
def self.watch
|
24
|
+
def self.watch
|
24
25
|
|
25
26
|
notify("Mongo Watcher enabled!")
|
26
27
|
|
@@ -74,8 +75,7 @@ class HerokuMongoWatcher::CLI
|
|
74
75
|
|
75
76
|
@current_row.print_row
|
76
77
|
|
77
|
-
|
78
|
-
check_and_notify_response_time
|
78
|
+
check_and_notify
|
79
79
|
|
80
80
|
@last_row = @current_row
|
81
81
|
@current_row = HerokuMongoWatcher::DataRow.new
|
@@ -90,6 +90,11 @@ class HerokuMongoWatcher::CLI
|
|
90
90
|
|
91
91
|
end
|
92
92
|
|
93
|
+
def self.check_and_notify
|
94
|
+
check_and_notify_locks
|
95
|
+
check_and_notify_response_time
|
96
|
+
end
|
97
|
+
|
93
98
|
protected
|
94
99
|
|
95
100
|
def self.check_and_notify_locks
|
@@ -110,10 +115,10 @@ class HerokuMongoWatcher::CLI
|
|
110
115
|
|
111
116
|
def self.check_and_notify_response_time
|
112
117
|
return unless @current_row.total_requests > 200
|
113
|
-
if @current_row.average_response_time > 10_000 || @current_row.
|
118
|
+
if @current_row.average_response_time > 10_000 || @current_row.error_rate > 1
|
114
119
|
notify "[SEVERE WARNING] Application not healthy | [#{@current_row.total_requests} rpm,#{@current_row.average_response_time} art]" unless @art_critical_notified
|
115
120
|
# @art_critical_notified = true
|
116
|
-
elsif @current_row.average_response_time > 500 || @current_row.
|
121
|
+
elsif @current_row.average_response_time > 500 || @current_row.error_rate > 0.3 || @current_row.total_requests > 30_000
|
117
122
|
notify "[WARNING] Application heating up | [#{@current_row.total_requests} rpm,#{@current_row.average_response_time} art]" unless @art_warning_notified
|
118
123
|
# @art_warning_notified = true
|
119
124
|
elsif @current_row.average_response_time < 300
|
@@ -142,9 +147,19 @@ class HerokuMongoWatcher::CLI
|
|
142
147
|
"Average Reponse Time: #{@last_row.average_response_time}",
|
143
148
|
"Application Errors: #{@last_row.total_web_errors}",
|
144
149
|
"Router Errors (timeouts): #{@last_row.total_router_errors}",
|
145
|
-
"
|
146
|
-
|
147
|
-
|
150
|
+
"Error Rate: #{@last_row.error_rate}%",
|
151
|
+
"Dynos: #{@last_row.dynos}",
|
152
|
+
"",
|
153
|
+
"Locks: #{@last_row.lock}",
|
154
|
+
"Queries: #{@last_row.queries}",
|
155
|
+
"Inserts: #{@last_row.inserts}",
|
156
|
+
"Updates: #{@last_row.updates}",
|
157
|
+
"Faults: #{@last_row.faults}",
|
158
|
+
"NetI/O: #{@last_row.net_in}/#{@last_row.net_out}",
|
159
|
+
]
|
160
|
+
content = content + @last_row.error_content_for_email
|
161
|
+
|
162
|
+
content = content.join("\r\n")
|
148
163
|
Net::SMTP.enable_tls(OpenSSL::SSL::VERIFY_NONE)
|
149
164
|
Net::SMTP.start('smtp.gmail.com', 587, 'gmail.com', config[:gmail_username], config[:gmail_password], :login) do |smtp|
|
150
165
|
smtp.send_message(content, config[:gmail_username], to)
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'singleton'
|
2
|
+
require 'trollop'
|
2
3
|
|
3
4
|
class HerokuMongoWatcher::Configuration
|
4
5
|
include Singleton
|
@@ -22,6 +23,13 @@ class HerokuMongoWatcher::Configuration
|
|
22
23
|
def initialize
|
23
24
|
f = File.join(File.expand_path('~'),'.watcher')
|
24
25
|
configure_with(f)
|
26
|
+
|
27
|
+
opts = Trollop::options do
|
28
|
+
opt :print_errors, "show aggregate error summaries", default: true
|
29
|
+
end
|
30
|
+
|
31
|
+
@@config.merge!(opts)
|
32
|
+
|
25
33
|
end
|
26
34
|
|
27
35
|
def config
|
@@ -35,6 +35,10 @@ class HerokuMongoWatcher::DataRow
|
|
35
35
|
total_requests > 0 ? total_queue / total_requests : 'N/A'
|
36
36
|
end
|
37
37
|
|
38
|
+
def error_rate
|
39
|
+
total_requests > 0 ? (((total_web_errors + total_router_errors)*(1.0)) / total_requests).round(2) : 'N/A'
|
40
|
+
end
|
41
|
+
|
38
42
|
def process_heroku_router_line(line)
|
39
43
|
items = line.split
|
40
44
|
|
@@ -117,8 +121,8 @@ class HerokuMongoWatcher::DataRow
|
|
117
121
|
|
118
122
|
def self.print_header
|
119
123
|
puts
|
120
|
-
puts "|<---- heroku stats
|
121
|
-
puts "dyno reqs
|
124
|
+
puts "|<---- heroku stats ------------------------------------------------------------------->|<----mongo stats ------------------------------------------------>|"
|
125
|
+
puts "| dyno reqs art max r_err w_err %err wait queue slowest | insert query update faults locked qr|qw netI/O time |"
|
122
126
|
end
|
123
127
|
|
124
128
|
def print_row
|
@@ -127,9 +131,10 @@ class HerokuMongoWatcher::DataRow
|
|
127
131
|
color_print @dynos, length: 4
|
128
132
|
color_print @total_requests, warning: 30_000, critical: 50_000
|
129
133
|
color_print average_response_time, warning: 1000, critical: 10_000, bold: true
|
130
|
-
color_print @max_service, warning: 20_000
|
131
|
-
color_print @total_router_errors, warning: 1
|
132
|
-
color_print @total_web_errors, warning: 1
|
134
|
+
color_print @max_service, warning: 20_000
|
135
|
+
color_print @total_router_errors, warning: 1
|
136
|
+
color_print @total_web_errors, warning: 1
|
137
|
+
color_print error_rate, warning: 0.1, critical: 1, percent: true
|
133
138
|
color_print average_wait, warning: 10, critical: 100
|
134
139
|
color_print average_queue, warning: 10, critical: 100
|
135
140
|
color_print @slowest_request, length: 28, slice: 25
|
@@ -140,9 +145,8 @@ class HerokuMongoWatcher::DataRow
|
|
140
145
|
color_print @faults
|
141
146
|
color_print @locked, bold: true, warning: 40, critical: 70
|
142
147
|
color_print @qrw
|
143
|
-
color_print @net_in
|
144
|
-
color_print @
|
145
|
-
color_print @mongo_time, length: 10
|
148
|
+
color_print "#{@net_in}/#{@net_out}", length: 10
|
149
|
+
color_print @mongo_time, length: 9
|
146
150
|
printf "\n"
|
147
151
|
end
|
148
152
|
|
@@ -154,12 +158,23 @@ class HerokuMongoWatcher::DataRow
|
|
154
158
|
end
|
155
159
|
end
|
156
160
|
|
161
|
+
def error_content_for_email
|
162
|
+
content = []
|
163
|
+
if @errors && @errors.keys && @errors.keys.length > 0
|
164
|
+
content << "Errors"
|
165
|
+
@errors.each do |error,count|
|
166
|
+
content << "\t\t[#{count}] #{error}"
|
167
|
+
end
|
168
|
+
end
|
169
|
+
content
|
170
|
+
end
|
171
|
+
|
157
172
|
private
|
158
173
|
|
159
174
|
def is_number?(string)
|
160
175
|
_is_number = true
|
161
176
|
begin
|
162
|
-
num =
|
177
|
+
num = Float(string)
|
163
178
|
rescue
|
164
179
|
_is_number = false
|
165
180
|
end
|
@@ -169,16 +184,17 @@ class HerokuMongoWatcher::DataRow
|
|
169
184
|
def color_print(field, options ={})
|
170
185
|
options[:length] = 7 unless options[:length]
|
171
186
|
print Term::ANSIColor.bold if options[:bold] == true
|
172
|
-
if options[:critical] && is_number?(field) &&
|
187
|
+
if options[:critical] && is_number?(field) && Float(field) > options[:critical]
|
173
188
|
print "\a" #beep
|
174
189
|
print Term::ANSIColor.red
|
175
190
|
print Term::ANSIColor.bold
|
176
|
-
elsif options[:warning] && is_number?(field) &&
|
191
|
+
elsif options[:warning] && is_number?(field) && Float(field) > options[:warning]
|
177
192
|
print Term::ANSIColor.yellow
|
178
193
|
end
|
179
194
|
|
180
195
|
str = field.to_s
|
181
196
|
str = str.slice(0, options[:slice]) if options[:slice] && str && str.length > 0
|
197
|
+
str = str + "\%" if options[:percent]
|
182
198
|
|
183
199
|
printf "%#{options[:length]}s", str
|
184
200
|
print Term::ANSIColor.clear
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: heroku_mongo_watcher
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.1.0.beta
|
5
5
|
prerelease: 6
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -13,7 +13,7 @@ date: 2012-07-23 00:00:00.000000000Z
|
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: term-ansicolor
|
16
|
-
requirement: &
|
16
|
+
requirement: &2156288100 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *2156288100
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: tlsmail
|
27
|
-
requirement: &
|
27
|
+
requirement: &2156279920 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *2156279920
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: heroku
|
38
|
-
requirement: &
|
38
|
+
requirement: &2156263940 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,7 +43,18 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *2156263940
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: trollop
|
49
|
+
requirement: &2156245840 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :runtime
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *2156245840
|
47
58
|
description: Also notifies you when certain thresholds are hit. I have found this
|
48
59
|
much more accurate than New Relic
|
49
60
|
email:
|