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 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: