pulse-meter 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.
- data/.gitignore +19 -0
- data/.rbenv-version +1 -0
- data/.rspec +1 -0
- data/.rvmrc +1 -0
- data/.travis.yml +4 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/Procfile +3 -0
- data/README.md +440 -0
- data/Rakefile +53 -0
- data/bin/pulse +6 -0
- data/examples/basic.ru +109 -0
- data/examples/basic_sensor_data.rb +38 -0
- data/examples/full/Procfile +2 -0
- data/examples/full/client.rb +82 -0
- data/examples/full/server.ru +114 -0
- data/examples/minimal/Procfile +2 -0
- data/examples/minimal/client.rb +16 -0
- data/examples/minimal/server.ru +20 -0
- data/examples/readme_client_example.rb +52 -0
- data/lib/cmd.rb +150 -0
- data/lib/pulse-meter.rb +17 -0
- data/lib/pulse-meter/mixins/dumper.rb +72 -0
- data/lib/pulse-meter/mixins/utils.rb +91 -0
- data/lib/pulse-meter/sensor.rb +44 -0
- data/lib/pulse-meter/sensor/base.rb +75 -0
- data/lib/pulse-meter/sensor/counter.rb +36 -0
- data/lib/pulse-meter/sensor/hashed_counter.rb +31 -0
- data/lib/pulse-meter/sensor/indicator.rb +33 -0
- data/lib/pulse-meter/sensor/timeline.rb +180 -0
- data/lib/pulse-meter/sensor/timelined/average.rb +26 -0
- data/lib/pulse-meter/sensor/timelined/counter.rb +16 -0
- data/lib/pulse-meter/sensor/timelined/hashed_counter.rb +22 -0
- data/lib/pulse-meter/sensor/timelined/max.rb +25 -0
- data/lib/pulse-meter/sensor/timelined/median.rb +14 -0
- data/lib/pulse-meter/sensor/timelined/min.rb +25 -0
- data/lib/pulse-meter/sensor/timelined/percentile.rb +31 -0
- data/lib/pulse-meter/version.rb +3 -0
- data/lib/pulse-meter/visualize/app.rb +43 -0
- data/lib/pulse-meter/visualize/dsl.rb +0 -0
- data/lib/pulse-meter/visualize/dsl/errors.rb +46 -0
- data/lib/pulse-meter/visualize/dsl/layout.rb +55 -0
- data/lib/pulse-meter/visualize/dsl/page.rb +50 -0
- data/lib/pulse-meter/visualize/dsl/sensor.rb +21 -0
- data/lib/pulse-meter/visualize/dsl/widget.rb +84 -0
- data/lib/pulse-meter/visualize/layout.rb +54 -0
- data/lib/pulse-meter/visualize/page.rb +30 -0
- data/lib/pulse-meter/visualize/public/css/application.css +19 -0
- data/lib/pulse-meter/visualize/public/css/bootstrap.css +4883 -0
- data/lib/pulse-meter/visualize/public/css/bootstrap.min.css +729 -0
- data/lib/pulse-meter/visualize/public/favicon.ico +0 -0
- data/lib/pulse-meter/visualize/public/img/glyphicons-halflings-white.png +0 -0
- data/lib/pulse-meter/visualize/public/img/glyphicons-halflings.png +0 -0
- data/lib/pulse-meter/visualize/public/js/application.coffee +262 -0
- data/lib/pulse-meter/visualize/public/js/application.js +279 -0
- data/lib/pulse-meter/visualize/public/js/backbone-min.js +38 -0
- data/lib/pulse-meter/visualize/public/js/bootstrap.js +1835 -0
- data/lib/pulse-meter/visualize/public/js/highcharts.js +203 -0
- data/lib/pulse-meter/visualize/public/js/jquery-1.7.2.min.js +4 -0
- data/lib/pulse-meter/visualize/public/js/json2.js +487 -0
- data/lib/pulse-meter/visualize/public/js/underscore-min.js +32 -0
- data/lib/pulse-meter/visualize/sensor.rb +60 -0
- data/lib/pulse-meter/visualize/views/main.haml +40 -0
- data/lib/pulse-meter/visualize/widget.rb +68 -0
- data/lib/pulse-meter/visualizer.rb +30 -0
- data/lib/test_helpers/matchers.rb +36 -0
- data/pulse-meter.gemspec +39 -0
- data/spec/pulse_meter/mixins/dumper_spec.rb +158 -0
- data/spec/pulse_meter/mixins/utils_spec.rb +134 -0
- data/spec/pulse_meter/sensor/base_spec.rb +97 -0
- data/spec/pulse_meter/sensor/counter_spec.rb +54 -0
- data/spec/pulse_meter/sensor/hashed_counter_spec.rb +39 -0
- data/spec/pulse_meter/sensor/indicator_spec.rb +43 -0
- data/spec/pulse_meter/sensor/timeline_spec.rb +58 -0
- data/spec/pulse_meter/sensor/timelined/average_spec.rb +6 -0
- data/spec/pulse_meter/sensor/timelined/counter_spec.rb +6 -0
- data/spec/pulse_meter/sensor/timelined/hashed_counter_spec.rb +8 -0
- data/spec/pulse_meter/sensor/timelined/max_spec.rb +7 -0
- data/spec/pulse_meter/sensor/timelined/median_spec.rb +7 -0
- data/spec/pulse_meter/sensor/timelined/min_spec.rb +7 -0
- data/spec/pulse_meter/sensor/timelined/percentile_spec.rb +17 -0
- data/spec/pulse_meter/visualize/app_spec.rb +27 -0
- data/spec/pulse_meter/visualize/dsl/layout_spec.rb +64 -0
- data/spec/pulse_meter/visualize/dsl/page_spec.rb +75 -0
- data/spec/pulse_meter/visualize/dsl/sensor_spec.rb +30 -0
- data/spec/pulse_meter/visualize/dsl/widget_spec.rb +127 -0
- data/spec/pulse_meter/visualize/layout_spec.rb +55 -0
- data/spec/pulse_meter/visualize/page_spec.rb +150 -0
- data/spec/pulse_meter/visualize/sensor_spec.rb +120 -0
- data/spec/pulse_meter/visualize/widget_spec.rb +113 -0
- data/spec/pulse_meter/visualizer_spec.rb +42 -0
- data/spec/pulse_meter_spec.rb +16 -0
- data/spec/shared_examples/timeline_sensor.rb +279 -0
- data/spec/shared_examples/timelined_subclass.rb +23 -0
- data/spec/spec_helper.rb +29 -0
- metadata +435 -0
data/.gitignore
ADDED
data/.rbenv-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.9.2-p290
|
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color -fd
|
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm use 1.9.2
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Ilya Averyanov
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Procfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,440 @@
|
|
1
|
+
[](http://travis-ci.org/savonarola/pulse-meter)
|
2
|
+
|
3
|
+
# PulseMeter
|
4
|
+
|
5
|
+
PulseMeter is a gem for fast and convenient realtime aggregating of software internal stats through Redis.
|
6
|
+
|
7
|
+
## Features
|
8
|
+
|
9
|
+
PulseMeter is designed to provide the following features:
|
10
|
+
|
11
|
+
* Simple deployment. The only infrastructure resource you are required to have is Redis.
|
12
|
+
|
13
|
+
* Low resource consumption. Since different kinds of events are aggregated in Redis,
|
14
|
+
you are as light and fast as Redis is.
|
15
|
+
Event data is stored in constant space and expires over time.
|
16
|
+
|
17
|
+
* Focus on the client. To start gathering some metrics, you should only modify your client: create a sensor object
|
18
|
+
and send events to it. All aggregated data can be accessed immediately without any
|
19
|
+
sort of "server reconfiguration"
|
20
|
+
|
21
|
+
## Concept
|
22
|
+
|
23
|
+
The fundamental concept of PulseMeter is *sensor*. Sensor is some named piece of data in Redis which
|
24
|
+
can be updated through client side objects associated with this data. The semantics of the data can be
|
25
|
+
different: some counter, value, series of values, etc. There is no need to care about explicit creation this data:
|
26
|
+
one just creates a client object and writes data to it, e.g.
|
27
|
+
|
28
|
+
PulseMeter.redis = Redis.new
|
29
|
+
sensor = PulseMeter::Sensor::Counter.new :my_counter
|
30
|
+
sensor.event(5)
|
31
|
+
...
|
32
|
+
sensor.event(3)
|
33
|
+
|
34
|
+
After that the value associated with the counter is immediately available (through CLI, for example). Any other
|
35
|
+
client can access the associated counter by creating object with the same redis db and sensor name.
|
36
|
+
|
37
|
+
Sensors can be divided into two large groups.
|
38
|
+
|
39
|
+
### Static sensors
|
40
|
+
|
41
|
+
These are just single values which can be read by CLI, e.g. some counter or some value
|
42
|
+
representing current state of a resource (current free memory amount, current la etc.). Currently, the
|
43
|
+
following static sensors are available:
|
44
|
+
|
45
|
+
* Counter
|
46
|
+
* Hashed Counter
|
47
|
+
* Indicator
|
48
|
+
|
49
|
+
They have no web visualisation interface and they are assumed to be used by external visualisation tools.
|
50
|
+
|
51
|
+
|
52
|
+
### Timeline sensors
|
53
|
+
|
54
|
+
These sensors are series of values, one value for each consequent time interval. They
|
55
|
+
are available by CLI and have web visualisation interface. Examples of such sensors include: count of
|
56
|
+
requests to some resource per hour, the longest request to a database per minute, etc.
|
57
|
+
|
58
|
+
The following timeline sensors are available:
|
59
|
+
|
60
|
+
* Average value
|
61
|
+
* Counter
|
62
|
+
* Hashed counter
|
63
|
+
* Max value
|
64
|
+
* Min value
|
65
|
+
* Median value
|
66
|
+
* Percentile
|
67
|
+
|
68
|
+
There are several caveats with timeline sensors:
|
69
|
+
|
70
|
+
* The value of a sensor for the last interval (which is not finished yet) is often not very useful.
|
71
|
+
When building a visualisation you may choose to display the last value or not.
|
72
|
+
* For some sensors (currently Median and Percentile) considerable amount of data should be stored for a
|
73
|
+
particular interval to obtain value for this interval. So it is a good idea to schedule
|
74
|
+
<tt>pulse reduce</tt>
|
75
|
+
command on a regular basis. This command reduces the stored data for passed intervals to single values,
|
76
|
+
so that they do not consume storage space.
|
77
|
+
|
78
|
+
## Client usage
|
79
|
+
|
80
|
+
Just create sensor objects and write data. Some examples below.
|
81
|
+
|
82
|
+
require 'pulse-meter'
|
83
|
+
PulseMeter.redis = Redis.new
|
84
|
+
|
85
|
+
# static sensor examples
|
86
|
+
|
87
|
+
counter = PulseMeter::Sensor::Counter.new :my_counter
|
88
|
+
counter.event(1)
|
89
|
+
counter.event(2)
|
90
|
+
puts counter.value
|
91
|
+
# prints
|
92
|
+
# 3
|
93
|
+
|
94
|
+
indicator = PulseMeter::Sensor::Indicator.new :my_value
|
95
|
+
indicator.event(3.14)
|
96
|
+
indicator.event(2.71)
|
97
|
+
puts indicator.value
|
98
|
+
# prints
|
99
|
+
# 2.71
|
100
|
+
|
101
|
+
hashed_counter = PulseMeter::Sensor::HashedCounter.new :my_h_counter
|
102
|
+
hashed_counter.event(:x => 1)
|
103
|
+
hashed_counter.event(:y => 5)
|
104
|
+
hashed_counter.event(:y => 1)
|
105
|
+
p hashed_counter.value
|
106
|
+
# prints
|
107
|
+
# {"x"=>1, "y"=>6}
|
108
|
+
|
109
|
+
# timeline sensor examples
|
110
|
+
|
111
|
+
requests_per_minute = PulseMeter::Sensor::Timelined::Counter.new(:my_t_counter,
|
112
|
+
:interval => 60, # count for each minute
|
113
|
+
:ttl => 24 * 60 * 60 # keep data one day
|
114
|
+
)
|
115
|
+
requests_per_minute.event(1)
|
116
|
+
requests_per_minute.event(1)
|
117
|
+
sleep(60)
|
118
|
+
requests_per_minute.event(1)
|
119
|
+
requests_per_minute.timeline(2 * 60).each do |v|
|
120
|
+
puts "#{v.start_time}: #{v.value}"
|
121
|
+
end
|
122
|
+
# prints somewhat like
|
123
|
+
# 2012-05-24 11:06:00 +0400: 2
|
124
|
+
# 2012-05-24 11:07:00 +0400: 1
|
125
|
+
|
126
|
+
max_per_minute = PulseMeter::Sensor::Timelined::Max.new(:my_t_max,
|
127
|
+
:interval => 60, # max for each minute
|
128
|
+
:ttl => 24 * 60 * 60 # keep data one day
|
129
|
+
)
|
130
|
+
max_per_minute.event(3)
|
131
|
+
max_per_minute.event(1)
|
132
|
+
max_per_minute.event(2)
|
133
|
+
sleep(60)
|
134
|
+
max_per_minute.event(5)
|
135
|
+
max_per_minute.event(7)
|
136
|
+
max_per_minute.event(6)
|
137
|
+
max_per_minute.timeline(2 * 60).each do |v|
|
138
|
+
puts "#{v.start_time}: #{v.value}"
|
139
|
+
end
|
140
|
+
# prints somewhat like
|
141
|
+
# 2012-05-24 11:07:00 +0400: 3.0
|
142
|
+
# 2012-05-24 11:08:00 +0400: 7.0
|
143
|
+
|
144
|
+
## Command line interface
|
145
|
+
|
146
|
+
Gem includes a tool <tt>pulse</tt>, which allows to send events to sensors, list them, etc.
|
147
|
+
You should pay attention to the command <tt>pulse reduce</tt>, which is generally should be
|
148
|
+
scheduled on a regular basis to keep data in Redis small.
|
149
|
+
|
150
|
+
To see available commands of this tool one can run the example above(see <tt>examples/readme\_client\_example.rb</tt>)
|
151
|
+
and run <tt>pulse help</tt>.
|
152
|
+
|
153
|
+
## Visualisation
|
154
|
+
|
155
|
+
PulseMeter comes with a simple DSL which allows to build a self-contained Rack application for
|
156
|
+
visualizing timeline sensor data.
|
157
|
+
|
158
|
+
The application is described by *Layout* which contains some general application options and a list of *Pages*.
|
159
|
+
Each page contain a list of *Widgets* (charts), and each widget is associated with several sensors, which produce
|
160
|
+
data series for the chart.
|
161
|
+
|
162
|
+
There is a minimal and a full example below.
|
163
|
+
|
164
|
+
### Minimal example
|
165
|
+
|
166
|
+
It can be found in <tt>examples/minimal</tt> folder. To run it, execute
|
167
|
+
<tt>bundle && cd examples/minimal && bundle exec foreman start</tt> (or just <tt>rake example:minimal</tt>)
|
168
|
+
at project root and visit
|
169
|
+
<tt>http://localhost:9292</tt> at your browser.
|
170
|
+
|
171
|
+
<tt>client.rb</tt> just creates a timelined counter an sends data to it in an infinite loop.
|
172
|
+
|
173
|
+
require "pulse-meter"
|
174
|
+
|
175
|
+
PulseMeter.redis = Redis.new
|
176
|
+
|
177
|
+
sensor = PulseMeter::Sensor::Timelined::Counter.new(:simple_sample_counter,
|
178
|
+
:interval => 5,
|
179
|
+
:ttl => 60 * 60
|
180
|
+
)
|
181
|
+
|
182
|
+
while true
|
183
|
+
STDERR.puts "tick"
|
184
|
+
sensor.event(1)
|
185
|
+
sleep(Random.rand)
|
186
|
+
end
|
187
|
+
|
188
|
+
<tt>server.ru</tt> is a Rackup file creating a simple layout with one page and one widget on it, which displays
|
189
|
+
the sensor's data. The layout is converted to a rack application and launched.
|
190
|
+
|
191
|
+
require "pulse-meter/visualizer"
|
192
|
+
|
193
|
+
PulseMeter.redis = Redis.new
|
194
|
+
|
195
|
+
layout = PulseMeter::Visualizer.draw do |l|
|
196
|
+
|
197
|
+
l.title "Minimal App"
|
198
|
+
|
199
|
+
l.page "Main Page" do |p|
|
200
|
+
p.area "Live Counter",
|
201
|
+
sensor: :simple_sample_counter,
|
202
|
+
timespan: 5 * 60,
|
203
|
+
redraw_interval: 1
|
204
|
+
end
|
205
|
+
|
206
|
+
end
|
207
|
+
|
208
|
+
run layout.to_app
|
209
|
+
|
210
|
+
<tt>Procfile</tt> allows to launch both "client" script and the web server with <tt>foreman</tt>.
|
211
|
+
|
212
|
+
web: bundle exec rackup server.ru
|
213
|
+
sensor_data_generator: bundle exec ruby client.rb
|
214
|
+
|
215
|
+
### Full example with DSL explanation
|
216
|
+
|
217
|
+
It can be found in <tt>examples/full</tt> folder. To run it, execute
|
218
|
+
<tt>bundle && cd examples/full && bundle exec foreman start</tt> (or just <tt>rake example:full</tt>)
|
219
|
+
at project root and visit
|
220
|
+
<tt>http://localhost:9292</tt> at your browser.
|
221
|
+
|
222
|
+
<tt>client.rb</tt> imitating users visiting some imaginary site
|
223
|
+
|
224
|
+
require "pulse-meter"
|
225
|
+
|
226
|
+
PulseMeter.redis = Redis.new
|
227
|
+
|
228
|
+
requests_per_minute = PulseMeter::Sensor::Timelined::Counter.new(:requests_per_minute,
|
229
|
+
:annotation => 'Requests per minute',
|
230
|
+
:interval => 60,
|
231
|
+
:ttl => 60 * 60 * 24 # keep data one day
|
232
|
+
)
|
233
|
+
|
234
|
+
requests_per_hour = PulseMeter::Sensor::Timelined::Counter.new(:requests_per_hour,
|
235
|
+
:annotation => 'Requests per hour',
|
236
|
+
:interval => 60 * 60,
|
237
|
+
:ttl => 60 * 60 * 24 * 30 # keep data 30 days
|
238
|
+
# when ActiveSupport extentions are loaded, a better way is to write just
|
239
|
+
# :interval => 1.hour,
|
240
|
+
# :ttl => 30.days
|
241
|
+
)
|
242
|
+
|
243
|
+
errors_per_minute = PulseMeter::Sensor::Timelined::Counter.new(:errors_per_minute,
|
244
|
+
:annotation => 'Errors per minute',
|
245
|
+
:interval => 60,
|
246
|
+
:ttl => 60 * 60 * 24
|
247
|
+
)
|
248
|
+
|
249
|
+
errors_per_hour = PulseMeter::Sensor::Timelined::Counter.new(:errors_per_hour,
|
250
|
+
:annotation => 'Errors per hour',
|
251
|
+
:interval => 60 * 60,
|
252
|
+
:ttl => 60 * 60 * 24 * 30
|
253
|
+
)
|
254
|
+
|
255
|
+
longest_minute_request = PulseMeter::Sensor::Timelined::Max.new(:longest_minute_request,
|
256
|
+
:annotation => 'Longest minute requests',
|
257
|
+
:interval => 60,
|
258
|
+
:ttl => 60 * 60 * 24
|
259
|
+
)
|
260
|
+
|
261
|
+
shortest_minute_request = PulseMeter::Sensor::Timelined::Min.new(:shortest_minute_request,
|
262
|
+
:annotation => 'Shortest minute requests',
|
263
|
+
:interval => 60,
|
264
|
+
:ttl => 60 * 60 * 24
|
265
|
+
)
|
266
|
+
|
267
|
+
perc90_minute_request = PulseMeter::Sensor::Timelined::Percentile.new(:perc90_minute_request,
|
268
|
+
:annotation => 'Minute request 90-percent percentile',
|
269
|
+
:interval => 60,
|
270
|
+
:ttl => 60 * 60 * 24,
|
271
|
+
:p => 0.9
|
272
|
+
)
|
273
|
+
|
274
|
+
agent_names = [:ie, :firefox, :chrome, :other]
|
275
|
+
hour_agents = agent_names.each_with_object({}) do |agent, h|
|
276
|
+
h[agent] = PulseMeter::Sensor::Timelined::Counter.new(agent,
|
277
|
+
:annotation => "Requests from #{agent} browser",
|
278
|
+
:interval => 60 * 60,
|
279
|
+
:ttl => 60 * 60 * 24 * 30
|
280
|
+
)
|
281
|
+
end
|
282
|
+
|
283
|
+
|
284
|
+
while true
|
285
|
+
requests_per_minute.event(1)
|
286
|
+
requests_per_hour.event(1)
|
287
|
+
|
288
|
+
if Random.rand(10) < 1 # let "errors" sometimes occur
|
289
|
+
errors_per_minute.event(1)
|
290
|
+
errors_per_hour.event(1)
|
291
|
+
end
|
292
|
+
|
293
|
+
request_time = 0.1 + Random.rand
|
294
|
+
|
295
|
+
longest_minute_request.event(request_time)
|
296
|
+
shortest_minute_request.event(request_time)
|
297
|
+
perc90_minute_request.event(request_time)
|
298
|
+
|
299
|
+
agent_counter = hour_agents[agent_names.shuffle.first]
|
300
|
+
agent_counter.event(1)
|
301
|
+
|
302
|
+
sleep(Random.rand / 10)
|
303
|
+
end
|
304
|
+
|
305
|
+
A more complicated visualization
|
306
|
+
|
307
|
+
require "pulse-meter/visualizer"
|
308
|
+
|
309
|
+
PulseMeter.redis = Redis.new
|
310
|
+
|
311
|
+
layout = PulseMeter::Visualizer.draw do |l|
|
312
|
+
|
313
|
+
# Application title
|
314
|
+
l.title "Full Example"
|
315
|
+
|
316
|
+
# Use local time for x-axis of charts
|
317
|
+
l.use_utc false
|
318
|
+
|
319
|
+
# Color for values cut off
|
320
|
+
l.outlier_color '#FF0000'
|
321
|
+
|
322
|
+
# Transfer some global parameters to Highcharts
|
323
|
+
l.highchart_options({
|
324
|
+
tooltip: {
|
325
|
+
value_decimals: 2
|
326
|
+
}
|
327
|
+
})
|
328
|
+
|
329
|
+
# Add some pages
|
330
|
+
l.page "Request count" do |p|
|
331
|
+
|
332
|
+
# Add chart (of Highcharts `area' style, `spline', `pie' and `line' are also available)
|
333
|
+
p.area "Requests per minute" do |w|
|
334
|
+
|
335
|
+
# Plot :requests_per_minute values on this chart with black color
|
336
|
+
w.sensor :requests_per_minute, color: '#000000'
|
337
|
+
|
338
|
+
# Plot :errors_per_minute values on this chart with red color
|
339
|
+
w.sensor :errors_per_minute, color: '#FF0000'
|
340
|
+
|
341
|
+
# Plot values for the last hour
|
342
|
+
w.timespan 60 * 60
|
343
|
+
|
344
|
+
# Redraw chart every 10 seconds
|
345
|
+
w.redraw_interval 10
|
346
|
+
|
347
|
+
# Plot incomplete data
|
348
|
+
w.show_last_point true
|
349
|
+
|
350
|
+
# Meaning of the y-axis
|
351
|
+
w.values_label "Request count"
|
352
|
+
|
353
|
+
# Occupy half (5/10) of the page (horizontally)
|
354
|
+
w.width 5
|
355
|
+
|
356
|
+
# Transfer page-wide (and page-specific) options to Highcharts
|
357
|
+
p.highchart_options({
|
358
|
+
chart: {
|
359
|
+
height: 300
|
360
|
+
}
|
361
|
+
})
|
362
|
+
end
|
363
|
+
|
364
|
+
p.area "Requests per hour" do |w|
|
365
|
+
|
366
|
+
w.sensor :requests_per_hour, color: '#555555'
|
367
|
+
w.sensor :errors_per_hour, color: '#FF0000'
|
368
|
+
|
369
|
+
w.timespan 24 * 60 * 60
|
370
|
+
w.redraw_interval 10
|
371
|
+
w.show_last_point true
|
372
|
+
w.values_label "Request count"
|
373
|
+
w.width 5
|
374
|
+
|
375
|
+
end
|
376
|
+
end
|
377
|
+
|
378
|
+
l.page "Request times" do |p|
|
379
|
+
p.area "Requests time" do |w|
|
380
|
+
|
381
|
+
w.sensor :longest_minute_request
|
382
|
+
w.sensor :shortest_minute_request
|
383
|
+
w.sensor :perc90_minute_request
|
384
|
+
|
385
|
+
w.timespan 60 * 60
|
386
|
+
w.redraw_interval 10
|
387
|
+
w.show_last_point true
|
388
|
+
w.values_label "Time in seconds"
|
389
|
+
w.width 10
|
390
|
+
|
391
|
+
end
|
392
|
+
end
|
393
|
+
|
394
|
+
l.page "Browsers" do |p|
|
395
|
+
p.pie "Requests from browser" do |w|
|
396
|
+
|
397
|
+
[:ie, :firefox, :chrome, :other].each do |sensor|
|
398
|
+
w.sensor sensor
|
399
|
+
end
|
400
|
+
|
401
|
+
w.timespan 24 * 60 * 60
|
402
|
+
w.redraw_interval 10
|
403
|
+
w.show_last_point true
|
404
|
+
w.values_label "Request count"
|
405
|
+
w.width 10
|
406
|
+
|
407
|
+
end
|
408
|
+
|
409
|
+
p.highchart_options({
|
410
|
+
chart: {
|
411
|
+
height: 500
|
412
|
+
}
|
413
|
+
})
|
414
|
+
end
|
415
|
+
|
416
|
+
end
|
417
|
+
|
418
|
+
run layout.to_app
|
419
|
+
|
420
|
+
## Installation
|
421
|
+
|
422
|
+
Add this line to your application's Gemfile:
|
423
|
+
|
424
|
+
gem 'pulse-meter'
|
425
|
+
|
426
|
+
And then execute:
|
427
|
+
|
428
|
+
$ bundle
|
429
|
+
|
430
|
+
Or install it yourself as:
|
431
|
+
|
432
|
+
$ gem install pulse-meter
|
433
|
+
|
434
|
+
## Contributing
|
435
|
+
|
436
|
+
1. Fork it
|
437
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
438
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
439
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
440
|
+
5. Create new Pull Request
|