heroku_mongo_watcher 0.0.4.beta → 0.1.0.beta

Sign up to get free protection for your applications and to get access to all the features.
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 ------------------------------------------------------------>|<----mongo stats ------------------------------------------------------->|
21
- dyno reqs art max r_err w_err wait queue slowest | insert query update faults locked qr|qw netIn netOut time |
22
- 20 76 27 586 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 /assets/companions/5009ab| 17 2 32 0 1.2 0|0 14k 26k 15:04:19
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 0 /crossdomain.xml| 307 0 618 1 21.6 0|0 260k 221k 15:05:19
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>netIn</td><td>size on mongo net in</td></tr>
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
@@ -2,4 +2,4 @@
2
2
  # encoding: UTF-8
3
3
 
4
4
  require "heroku_mongo_watcher/cli"
5
- HerokuMongoWatcher::CLI.watch(*ARGV)
5
+ HerokuMongoWatcher::CLI.watch
@@ -23,4 +23,5 @@ Gem::Specification.new do |s|
23
23
  s.add_runtime_dependency "term-ansicolor"
24
24
  s.add_runtime_dependency "tlsmail"
25
25
  s.add_runtime_dependency "heroku"
26
+ s.add_runtime_dependency "trollop"
26
27
  end
@@ -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(*args)
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
- check_and_notify_locks
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.total_router_errors > 100
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.total_router_errors > 10 || @current_row.total_requests > 30_000
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
- "Dynos: #{@last_row.dynos}"
146
- ].join("\r\n")
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 ------------------------------------------------------------>|<----mongo stats ------------------------------------------------------->|"
121
- puts "dyno reqs art max r_err w_err wait queue slowest | insert query update faults locked qr|qw netIn netOut time |"
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, critical: 27_000
131
- color_print @total_router_errors, warning: 1, critical: 10
132
- color_print @total_web_errors, warning: 1, critical: 10
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 @net_out
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 = Integer(string)
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) && Integer(field) > options[:critical]
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) && Integer(field) > options[:warning]
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
@@ -1,3 +1,3 @@
1
1
  module HerokuMongoWatcher
2
- VERSION = "0.0.4.beta"
2
+ VERSION = "0.1.0.beta"
3
3
  end
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.beta
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: &2157942700 !ruby/object:Gem::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: *2157942700
24
+ version_requirements: *2156288100
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: tlsmail
27
- requirement: &2157942040 !ruby/object:Gem::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: *2157942040
35
+ version_requirements: *2156279920
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: heroku
38
- requirement: &2157941260 !ruby/object:Gem::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: *2157941260
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: