pulse_meter_cli 0.4.12
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 +8 -0
- data/Gemfile +2 -0
- data/LICENSE +22 -0
- data/README.md +40 -0
- data/Rakefile +13 -0
- data/bin/pulse +6 -0
- data/lib/cmd.rb +171 -0
- data/lib/pulse_meter/extensions/enumerable.rb +24 -0
- data/lib/pulse_meter/mixins/cmd.rb +46 -0
- data/lib/pulse_meter_cli.rb +2 -0
- data/pulse_meter_cli.gemspec +33 -0
- data/spec/pulse_meter/extensions/enumerable_spec.rb +58 -0
- data/spec/pulse_meter/mixins/cmd_spec.rb +117 -0
- data/spec/spec_helper.rb +23 -0
- metadata +265 -0
data/.gitignore
ADDED
data/.rbenv-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.9.3-p125
|
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/README.md
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
[](http://badge.fury.io/rb/pulse_meter_cli)
|
2
|
+
[](http://travis-ci.org/savonarola/pulse_meter_cli)
|
3
|
+
[](https://gemnasium.com/savonarola/pulse_meter_cli)
|
4
|
+
[](https://codeclimate.com/github/savonarola/pulse_meter_cli)
|
5
|
+
|
6
|
+
# PulseMeter
|
7
|
+
|
8
|
+
PulseMeter is a gem for fast and convenient realtime aggregating of software internal stats through Redis.
|
9
|
+
|
10
|
+
## Live Demo
|
11
|
+
|
12
|
+
A small live demo of PulseMeter gem is located here: [rubybox.ru](http://rubybox.ru), its source code can be found here: [https://github.com/savonarola/pulse_meter_cli-demo](https://github.com/savonarola/pulse_meter_cli-demo)
|
13
|
+
|
14
|
+
## Features
|
15
|
+
|
16
|
+
The gem contains command line tool `pulse` for PulseMeter gem.
|
17
|
+
|
18
|
+
## Installation
|
19
|
+
|
20
|
+
Add this line to your application's Gemfile:
|
21
|
+
|
22
|
+
```ruby
|
23
|
+
gem 'pulse_meter_cli', require: false
|
24
|
+
```
|
25
|
+
|
26
|
+
And then execute:
|
27
|
+
|
28
|
+
$ bundle
|
29
|
+
|
30
|
+
Or install it yourself as:
|
31
|
+
|
32
|
+
$ gem install pulse_meter_cli
|
33
|
+
|
34
|
+
## Contributing
|
35
|
+
|
36
|
+
1. Fork it
|
37
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
38
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
39
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
40
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
require 'bundler/gem_tasks'
|
3
|
+
require 'rspec/core/rake_task'
|
4
|
+
require 'yard'
|
5
|
+
require 'yard/rake/yardoc_task'
|
6
|
+
|
7
|
+
RSpec::Core::RakeTask.new(:spec)
|
8
|
+
|
9
|
+
YARD::Rake::YardocTask.new(:yard)
|
10
|
+
|
11
|
+
ROOT = File.dirname(__FILE__)
|
12
|
+
|
13
|
+
task :default => :spec
|
data/bin/pulse
ADDED
data/lib/cmd.rb
ADDED
@@ -0,0 +1,171 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require 'terminal-table'
|
3
|
+
require 'time'
|
4
|
+
require 'json'
|
5
|
+
require 'csv'
|
6
|
+
|
7
|
+
module Cmd
|
8
|
+
class All < Thor
|
9
|
+
include PulseMeter::Mixins::Utils
|
10
|
+
include PulseMeter::Mixins::Cmd
|
11
|
+
no_tasks do
|
12
|
+
def create_redis
|
13
|
+
Redis.new :host => options[:host], :port => options[:port], :db => options[:db]
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.common_options
|
17
|
+
method_option :host, :default => '127.0.0.1', :desc => "Redis host"
|
18
|
+
method_option :port, :default => 6379, :desc => "Redis port"
|
19
|
+
method_option :db, :default => 0, :desc => "Redis db"
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.sensor_options(required = [])
|
23
|
+
[
|
24
|
+
[:interval, :numeric, "Rotation interval"],
|
25
|
+
[:ttl, :numeric, "How long summarized data will be stored"],
|
26
|
+
[:raw_data_ttl, :numeric, "How long unsummarized raw data will be stored"],
|
27
|
+
[:reduce_delay, :numeric, "Delay between end of interval and summarization"],
|
28
|
+
[:annotation, :string, "Sensor annotation"]
|
29
|
+
].each do |name, type, desc = data|
|
30
|
+
method_option name, :required => required.include?(name), :type => type, :desc => desc
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
desc "sensors", "List all sensors available"
|
36
|
+
common_options
|
37
|
+
method_option :format, :default => :table, :desc => "Output format: table or csv"
|
38
|
+
def sensors
|
39
|
+
with_redis {puts all_sensors_table(options[:format])}
|
40
|
+
end
|
41
|
+
|
42
|
+
desc "reduce", "Execute reduction for all sensors' raw data"
|
43
|
+
common_options
|
44
|
+
def reduce
|
45
|
+
with_redis do
|
46
|
+
puts 'Registered sensors to be reduced'
|
47
|
+
puts all_sensors_table
|
48
|
+
PulseMeter::Sensor::Timeline.reduce_all_raw
|
49
|
+
puts "DONE"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
desc "event NAME VALUE", "Send event VALUE to sensor NAME"
|
54
|
+
common_options
|
55
|
+
method_option :format, :default => :plain, :desc => "Event format: plain or json"
|
56
|
+
def event(name, value)
|
57
|
+
if "json" == options[:format]
|
58
|
+
value = JSON.parse(value)
|
59
|
+
end
|
60
|
+
with_safe_restore_of(name) {|sensor|
|
61
|
+
sensor.event(value)
|
62
|
+
}
|
63
|
+
PulseMeter.command_aggregator.wait_for_pending_events
|
64
|
+
end
|
65
|
+
|
66
|
+
desc "timeline NAME SECONDS", "Get sensor's NAME timeline for last SECONDS"
|
67
|
+
common_options
|
68
|
+
method_option :format, :default => :table, :desc => "Output format: table or csv"
|
69
|
+
def timeline(name, seconds)
|
70
|
+
with_safe_restore_of(name) do |sensor|
|
71
|
+
puts sensor.
|
72
|
+
timeline(seconds).
|
73
|
+
map {|data| [data.start_time, data.value || '']}.
|
74
|
+
to_table(options[:format])
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
desc "timeline_within NAME FROM TILL", "Get sensor's NAME timeline in interval. Time format: YYYY-MM-DD HH:MM:SS"
|
79
|
+
common_options
|
80
|
+
method_option :format, :default => :table, :desc => "Output format: table or csv"
|
81
|
+
def timeline_within(name, from, till)
|
82
|
+
with_safe_restore_of(name) do |sensor|
|
83
|
+
puts sensor.
|
84
|
+
timeline_within(Time.parse(from), Time.parse(till)).
|
85
|
+
map {|data| [data.start_time, data.value || '']}.
|
86
|
+
to_table(options[:format])
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
desc "delete NAME", "Delete sensor by name"
|
91
|
+
common_options
|
92
|
+
def delete(name)
|
93
|
+
with_safe_restore_of(name) {|sensor| sensor.cleanup}
|
94
|
+
puts "Sensor #{name} deleted"
|
95
|
+
end
|
96
|
+
|
97
|
+
desc "create NAME TYPE", "Create sensor of given type"
|
98
|
+
common_options
|
99
|
+
sensor_options([:ttl, :interval])
|
100
|
+
def create(name, type)
|
101
|
+
with_redis do
|
102
|
+
klass = constantize("PulseMeter::Sensor::Timelined::#{type}")
|
103
|
+
puts "PulseMeter::Sensor::Timelined::#{type}"
|
104
|
+
fail! "Unknown sensor type #{type}" unless klass
|
105
|
+
sensor = klass.new(name, options.dup)
|
106
|
+
puts "Sensor created"
|
107
|
+
puts all_sensors_table
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
desc "update NAME", "Update given sensor"
|
112
|
+
common_options
|
113
|
+
sensor_options
|
114
|
+
def update(name)
|
115
|
+
with_safe_restore_of(name) do |sensor|
|
116
|
+
opts = options.dup
|
117
|
+
[:ttl, :interval, :reduce_delay, :raw_data_ttl, :annotation].each do |attr|
|
118
|
+
opts[attr] ||= sensor.send(attr)
|
119
|
+
end
|
120
|
+
klass = sensor.class
|
121
|
+
new_sensor = klass.new(name, opts)
|
122
|
+
new_sensor.dump!(false)
|
123
|
+
puts "Sensor updated"
|
124
|
+
puts all_sensors_table
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
desc "create_simple NAME TYPE", "Create simple non-timelined sensor of given type"
|
129
|
+
common_options
|
130
|
+
method_option :annotation, :type => :string, :desc => "Sensor annotation"
|
131
|
+
def create_simple(name, type)
|
132
|
+
with_redis do
|
133
|
+
klass = constantize("PulseMeter::Sensor::#{type}")
|
134
|
+
fail! "Unknown sensor type #{type}" unless klass
|
135
|
+
sensor = klass.new(name, options.dup)
|
136
|
+
puts "Sensor created"
|
137
|
+
puts all_sensors_table
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
desc "value NAME", "Get value of non-timelined sensor"
|
142
|
+
def value(name)
|
143
|
+
with_safe_restore_of(name) do |sensor|
|
144
|
+
fail! "Sensor #{name} has no value method" unless sensor.respond_to?(:value)
|
145
|
+
puts "Value: #{sensor.value}"
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
desc "drop NAME DATE_FROM(YYYYmmddHHMMSS) DATE_TO(YYYYmmddHHMMSS)", "Drop timeline data of a particular sensor"
|
150
|
+
common_options
|
151
|
+
def drop(name, from, to)
|
152
|
+
time_from = parse_time(from)
|
153
|
+
time_to = parse_time(to)
|
154
|
+
with_safe_restore_of(name) do |sensor|
|
155
|
+
fail! "Sensor #{name} has no drop_within method" unless sensor.respond_to?(:drop_within)
|
156
|
+
sensor.drop_within(time_from, time_to)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
desc "udp_proxy HOST PORT", "Start UDP proxy for sensor data"
|
161
|
+
common_options
|
162
|
+
def udp_proxy(host, port)
|
163
|
+
with_redis do
|
164
|
+
puts 'Starting UDP server'
|
165
|
+
server = PulseMeter::UDPServer.new(host, port)
|
166
|
+
server.start
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
end
|
171
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Enumerable
|
2
|
+
require 'csv'
|
3
|
+
require 'terminal-table'
|
4
|
+
|
5
|
+
def convert_time
|
6
|
+
map {|el| el.is_a?(Time) ? el.to_i : el}
|
7
|
+
end
|
8
|
+
|
9
|
+
def to_table(format = nil)
|
10
|
+
if "csv" == format.to_s
|
11
|
+
CSV.generate(:col_sep => ';') do |csv|
|
12
|
+
self.each {|row| csv << row.convert_time}
|
13
|
+
end
|
14
|
+
else
|
15
|
+
self.each_with_object(Terminal::Table.new) do |row, table|
|
16
|
+
table << if row.respond_to?(:map)
|
17
|
+
row.map(&:to_s)
|
18
|
+
else
|
19
|
+
row
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'pulse_meter/extensions/enumerable'
|
2
|
+
|
3
|
+
module PulseMeter
|
4
|
+
module Mixins
|
5
|
+
# Mixin with command-line utilities
|
6
|
+
module Cmd
|
7
|
+
def with_redis
|
8
|
+
PulseMeter.redis = create_redis
|
9
|
+
yield
|
10
|
+
end
|
11
|
+
|
12
|
+
def with_safe_restore_of(name, &block)
|
13
|
+
with_redis do
|
14
|
+
sensor = PulseMeter::Sensor::Base.restore(name)
|
15
|
+
block.call(sensor)
|
16
|
+
end
|
17
|
+
rescue PulseMeter::RestoreError
|
18
|
+
fail! "Sensor #{name} is unknown or cannot be restored"
|
19
|
+
end
|
20
|
+
|
21
|
+
def all_sensors
|
22
|
+
PulseMeter::Sensor::Timeline.list_objects
|
23
|
+
end
|
24
|
+
|
25
|
+
def all_sensors_table(format = nil)
|
26
|
+
data = [
|
27
|
+
["Name", "Class", "ttl", "raw data ttl", "interval", "reduce delay"],
|
28
|
+
]
|
29
|
+
data << :separator unless 'csv' == format.to_s
|
30
|
+
all_sensors.each do |s|
|
31
|
+
if s.kind_of? PulseMeter::Sensor::Timeline
|
32
|
+
data << [s.name, s.class, s.ttl, s.raw_data_ttl, s.interval, s.reduce_delay]
|
33
|
+
else
|
34
|
+
data << [s.name, s.class] + [''] * 4
|
35
|
+
end
|
36
|
+
end
|
37
|
+
data.to_table(format)
|
38
|
+
end
|
39
|
+
|
40
|
+
def fail!(description = nil)
|
41
|
+
puts description if description
|
42
|
+
exit 1
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
Gem::Specification.new do |gem|
|
3
|
+
gem.authors = ["Ilya Averyanov", "Sergey Averyanov"]
|
4
|
+
gem.email = ["av@fun-box.ru", "averyanov@gmail.com"]
|
5
|
+
gem.description = %q{CLI for pulse-meter metrics processor}
|
6
|
+
gem.summary = %q{
|
7
|
+
CLI for lightweight Redis-based metrics aggregator and processor PulseMeter
|
8
|
+
}
|
9
|
+
gem.homepage = "https://github.com/savonarola/pulse_meter_cli"
|
10
|
+
|
11
|
+
gem.required_ruby_version = '>= 1.9.2'
|
12
|
+
gem.files = `git ls-files`.split($\)
|
13
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
14
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
15
|
+
gem.name = "pulse_meter_cli"
|
16
|
+
gem.require_paths = ["lib"]
|
17
|
+
gem.version = "0.4.12"
|
18
|
+
|
19
|
+
gem.add_runtime_dependency('pulse_meter_core')
|
20
|
+
gem.add_runtime_dependency('terminal-table')
|
21
|
+
gem.add_runtime_dependency('thor')
|
22
|
+
|
23
|
+
gem.add_development_dependency('aquarium')
|
24
|
+
gem.add_development_dependency('hashie')
|
25
|
+
gem.add_development_dependency('mock_redis')
|
26
|
+
gem.add_development_dependency('rake')
|
27
|
+
gem.add_development_dependency('redcarpet')
|
28
|
+
gem.add_development_dependency('rspec')
|
29
|
+
gem.add_development_dependency('simplecov')
|
30
|
+
gem.add_development_dependency('timecop')
|
31
|
+
gem.add_development_dependency('yard')
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'pulse_meter/extensions/enumerable'
|
3
|
+
|
4
|
+
describe Enumerable do
|
5
|
+
let!(:time) {Time.new}
|
6
|
+
describe "#convert_time" do
|
7
|
+
it "converts Time objects to unixtime" do
|
8
|
+
[time].convert_time.should == [time.to_i]
|
9
|
+
end
|
10
|
+
|
11
|
+
it "does not change other members" do
|
12
|
+
[1, 2, 3].convert_time.should == [1, 2 ,3]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "#to_table" do
|
17
|
+
context "when format is csv" do
|
18
|
+
it "returns csv as string" do
|
19
|
+
[].to_table(:csv).should be_instance_of(String)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "returns csv containing each subarray as a row" do
|
23
|
+
[[:a, :b], [:c, :d]].to_table(:csv).should == "a;b\nc;d\n"
|
24
|
+
end
|
25
|
+
|
26
|
+
it "converts Time objects to unixtime" do
|
27
|
+
[[time]].to_table(:csv).should == "#{time.to_i}\n"
|
28
|
+
end
|
29
|
+
|
30
|
+
it "takes format argument both as string and as symbol" do
|
31
|
+
[[:foo]].to_table("csv").should == "foo\n"
|
32
|
+
[[:foo]].to_table(:csv).should == "foo\n"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context "when format is table" do
|
37
|
+
it "return Terminal::Table instance" do
|
38
|
+
[].to_table.should be_instance_of(Terminal::Table)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "returns table containing each subarray as a row" do
|
42
|
+
data = [[:a, :b], [:c, :d]]
|
43
|
+
table = [[:a, :b], [:c, :d]].to_table
|
44
|
+
table.rows.map do |row|
|
45
|
+
row.cells.map(&:to_s).map(&:strip).map(&:to_sym)
|
46
|
+
end.should == data
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
it "uses table format as default" do
|
51
|
+
[].to_table.should be_instance_of(Terminal::Table)
|
52
|
+
end
|
53
|
+
|
54
|
+
it "uses table format unless it is :csv or 'csv'" do
|
55
|
+
[].to_table(:unknown_format).should be_instance_of(Terminal::Table)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe PulseMeter::Mixins::Cmd do
|
4
|
+
class CmdDummy
|
5
|
+
include PulseMeter::Mixins::Cmd
|
6
|
+
|
7
|
+
def initialize(redis)
|
8
|
+
@redis = redis
|
9
|
+
end
|
10
|
+
|
11
|
+
def create_redis
|
12
|
+
@redis
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
let(:redis){ MockRedis.new }
|
17
|
+
let(:dummy){ CmdDummy.new(redis) }
|
18
|
+
before{ PulseMeter.redis = redis }
|
19
|
+
|
20
|
+
describe "#fail!" do
|
21
|
+
it "prints given message and exits" do
|
22
|
+
STDOUT.should_receive(:puts).with(:msg)
|
23
|
+
lambda {dummy.fail!(:msg)}.should raise_error(SystemExit)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe '#with_redis' do
|
28
|
+
it "initializes redies and yields a block" do
|
29
|
+
PulseMeter.redis = nil
|
30
|
+
dummy.with_redis do
|
31
|
+
PulseMeter.redis.should_not be_nil
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe "#with_safe_restore_of" do
|
37
|
+
it "restores sensor by name and passes it to block" do
|
38
|
+
sensor = PulseMeter::Sensor::Counter.new(:foo)
|
39
|
+
dummy.with_safe_restore_of(:foo) do |s|
|
40
|
+
s.should be_instance_of(sensor.class)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
it "prints error and exits if sensor cannot be restored" do
|
45
|
+
STDOUT.should_receive(:puts).with("Sensor nonexistant is unknown or cannot be restored")
|
46
|
+
lambda {dummy.with_safe_restore_of(:nonexistant) {|s| s}}.should raise_error(SystemExit)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "#all_sensors" do
|
51
|
+
it "is just an alias to PulseMeter::Sensor::Timeline.list_objects" do
|
52
|
+
PulseMeter::Sensor::Timeline.should_receive(:list_objects)
|
53
|
+
dummy.all_sensors
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe "#all_sensors_table" do
|
58
|
+
before {PulseMeter.redis.flushall}
|
59
|
+
let(:init_values){ {:ttl => 1, :raw_data_ttl => 2, :interval => 3, :reduce_delay => 4} }
|
60
|
+
let!(:s1) {PulseMeter::Sensor::Counter.new(:s1)}
|
61
|
+
let!(:s2) {PulseMeter::Sensor::Timelined::Counter.new(:s2, init_values)}
|
62
|
+
let!(:table) {dummy.all_sensors_table}
|
63
|
+
let!(:csv) {dummy.all_sensors_table(:csv)}
|
64
|
+
let!(:parsed_csv) {CSV.parse(csv, col_sep: ";")}
|
65
|
+
|
66
|
+
def rows(format)
|
67
|
+
if "csv" == format.to_s
|
68
|
+
parsed_csv
|
69
|
+
else
|
70
|
+
table.rows.map do |row|
|
71
|
+
row.cells.map(&:to_s).map(&:strip)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def sensor_row(name, format)
|
77
|
+
rows(format).select {|row| row[0] == name}.first
|
78
|
+
end
|
79
|
+
|
80
|
+
[:csv, :table].each do |format|
|
81
|
+
context "when format is #{format}" do
|
82
|
+
|
83
|
+
if "csv" == format.to_s
|
84
|
+
it "returns csv as string" do
|
85
|
+
csv.should be_instance_of(String)
|
86
|
+
end
|
87
|
+
else
|
88
|
+
it "returns Terminal::Table instance" do
|
89
|
+
table.should be_instance_of(Terminal::Table)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
it "has title row" do
|
94
|
+
rows(format)[0].should == ["Name", "Class", "ttl", "raw data ttl", "interval", "reduce delay"]
|
95
|
+
end
|
96
|
+
|
97
|
+
it "has one row for each sensor (and a title)" do
|
98
|
+
rows(format).count.should == 3
|
99
|
+
end
|
100
|
+
|
101
|
+
it "can display timelined sensors" do
|
102
|
+
sensor_row("s2", format).should == [
|
103
|
+
s2.name, s2.class, s2.ttl, s2.raw_data_ttl, s2.interval, s2.reduce_delay
|
104
|
+
].map(&:to_s)
|
105
|
+
end
|
106
|
+
|
107
|
+
it "can display static sensors" do
|
108
|
+
sensor_row("s1", format).should == [
|
109
|
+
s1.name, s1.class, "", "", "", ""
|
110
|
+
].map(&:to_s)
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler/setup'
|
3
|
+
$:.unshift File.expand_path('../../lib/', __FILE__)
|
4
|
+
|
5
|
+
ROOT = File.expand_path('../..', __FILE__)
|
6
|
+
|
7
|
+
Bundler.require(:development)
|
8
|
+
|
9
|
+
SimpleCov.start
|
10
|
+
|
11
|
+
require 'pulse_meter_cli'
|
12
|
+
PulseMeter.redis = MockRedis.new
|
13
|
+
|
14
|
+
RSpec.configure do |config|
|
15
|
+
config.before(:each) do
|
16
|
+
PulseMeter.redis = MockRedis.new
|
17
|
+
Timecop.return
|
18
|
+
PulseMeter.logger = Logger.new("/dev/null")
|
19
|
+
end
|
20
|
+
config.filter_run :focus => true
|
21
|
+
config.run_all_when_everything_filtered = true
|
22
|
+
end
|
23
|
+
|
metadata
ADDED
@@ -0,0 +1,265 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pulse_meter_cli
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.4.12
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Ilya Averyanov
|
9
|
+
- Sergey Averyanov
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
date: 2013-06-16 00:00:00.000000000 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: pulse_meter_core
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ! '>='
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '0'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
27
|
+
requirements:
|
28
|
+
- - ! '>='
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
version: '0'
|
31
|
+
- !ruby/object:Gem::Dependency
|
32
|
+
name: terminal-table
|
33
|
+
requirement: !ruby/object:Gem::Requirement
|
34
|
+
none: false
|
35
|
+
requirements:
|
36
|
+
- - ! '>='
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: '0'
|
39
|
+
type: :runtime
|
40
|
+
prerelease: false
|
41
|
+
version_requirements: !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ! '>='
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: thor
|
49
|
+
requirement: !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: !ruby/object:Gem::Requirement
|
58
|
+
none: false
|
59
|
+
requirements:
|
60
|
+
- - ! '>='
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
- !ruby/object:Gem::Dependency
|
64
|
+
name: aquarium
|
65
|
+
requirement: !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
67
|
+
requirements:
|
68
|
+
- - ! '>='
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '0'
|
71
|
+
type: :development
|
72
|
+
prerelease: false
|
73
|
+
version_requirements: !ruby/object:Gem::Requirement
|
74
|
+
none: false
|
75
|
+
requirements:
|
76
|
+
- - ! '>='
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: '0'
|
79
|
+
- !ruby/object:Gem::Dependency
|
80
|
+
name: hashie
|
81
|
+
requirement: !ruby/object:Gem::Requirement
|
82
|
+
none: false
|
83
|
+
requirements:
|
84
|
+
- - ! '>='
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
version: '0'
|
87
|
+
type: :development
|
88
|
+
prerelease: false
|
89
|
+
version_requirements: !ruby/object:Gem::Requirement
|
90
|
+
none: false
|
91
|
+
requirements:
|
92
|
+
- - ! '>='
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '0'
|
95
|
+
- !ruby/object:Gem::Dependency
|
96
|
+
name: mock_redis
|
97
|
+
requirement: !ruby/object:Gem::Requirement
|
98
|
+
none: false
|
99
|
+
requirements:
|
100
|
+
- - ! '>='
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '0'
|
103
|
+
type: :development
|
104
|
+
prerelease: false
|
105
|
+
version_requirements: !ruby/object:Gem::Requirement
|
106
|
+
none: false
|
107
|
+
requirements:
|
108
|
+
- - ! '>='
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: rake
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
none: false
|
115
|
+
requirements:
|
116
|
+
- - ! '>='
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: '0'
|
119
|
+
type: :development
|
120
|
+
prerelease: false
|
121
|
+
version_requirements: !ruby/object:Gem::Requirement
|
122
|
+
none: false
|
123
|
+
requirements:
|
124
|
+
- - ! '>='
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
version: '0'
|
127
|
+
- !ruby/object:Gem::Dependency
|
128
|
+
name: redcarpet
|
129
|
+
requirement: !ruby/object:Gem::Requirement
|
130
|
+
none: false
|
131
|
+
requirements:
|
132
|
+
- - ! '>='
|
133
|
+
- !ruby/object:Gem::Version
|
134
|
+
version: '0'
|
135
|
+
type: :development
|
136
|
+
prerelease: false
|
137
|
+
version_requirements: !ruby/object:Gem::Requirement
|
138
|
+
none: false
|
139
|
+
requirements:
|
140
|
+
- - ! '>='
|
141
|
+
- !ruby/object:Gem::Version
|
142
|
+
version: '0'
|
143
|
+
- !ruby/object:Gem::Dependency
|
144
|
+
name: rspec
|
145
|
+
requirement: !ruby/object:Gem::Requirement
|
146
|
+
none: false
|
147
|
+
requirements:
|
148
|
+
- - ! '>='
|
149
|
+
- !ruby/object:Gem::Version
|
150
|
+
version: '0'
|
151
|
+
type: :development
|
152
|
+
prerelease: false
|
153
|
+
version_requirements: !ruby/object:Gem::Requirement
|
154
|
+
none: false
|
155
|
+
requirements:
|
156
|
+
- - ! '>='
|
157
|
+
- !ruby/object:Gem::Version
|
158
|
+
version: '0'
|
159
|
+
- !ruby/object:Gem::Dependency
|
160
|
+
name: simplecov
|
161
|
+
requirement: !ruby/object:Gem::Requirement
|
162
|
+
none: false
|
163
|
+
requirements:
|
164
|
+
- - ! '>='
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '0'
|
167
|
+
type: :development
|
168
|
+
prerelease: false
|
169
|
+
version_requirements: !ruby/object:Gem::Requirement
|
170
|
+
none: false
|
171
|
+
requirements:
|
172
|
+
- - ! '>='
|
173
|
+
- !ruby/object:Gem::Version
|
174
|
+
version: '0'
|
175
|
+
- !ruby/object:Gem::Dependency
|
176
|
+
name: timecop
|
177
|
+
requirement: !ruby/object:Gem::Requirement
|
178
|
+
none: false
|
179
|
+
requirements:
|
180
|
+
- - ! '>='
|
181
|
+
- !ruby/object:Gem::Version
|
182
|
+
version: '0'
|
183
|
+
type: :development
|
184
|
+
prerelease: false
|
185
|
+
version_requirements: !ruby/object:Gem::Requirement
|
186
|
+
none: false
|
187
|
+
requirements:
|
188
|
+
- - ! '>='
|
189
|
+
- !ruby/object:Gem::Version
|
190
|
+
version: '0'
|
191
|
+
- !ruby/object:Gem::Dependency
|
192
|
+
name: yard
|
193
|
+
requirement: !ruby/object:Gem::Requirement
|
194
|
+
none: false
|
195
|
+
requirements:
|
196
|
+
- - ! '>='
|
197
|
+
- !ruby/object:Gem::Version
|
198
|
+
version: '0'
|
199
|
+
type: :development
|
200
|
+
prerelease: false
|
201
|
+
version_requirements: !ruby/object:Gem::Requirement
|
202
|
+
none: false
|
203
|
+
requirements:
|
204
|
+
- - ! '>='
|
205
|
+
- !ruby/object:Gem::Version
|
206
|
+
version: '0'
|
207
|
+
description: CLI for pulse-meter metrics processor
|
208
|
+
email:
|
209
|
+
- av@fun-box.ru
|
210
|
+
- averyanov@gmail.com
|
211
|
+
executables:
|
212
|
+
- pulse
|
213
|
+
extensions: []
|
214
|
+
extra_rdoc_files: []
|
215
|
+
files:
|
216
|
+
- .gitignore
|
217
|
+
- .rbenv-version
|
218
|
+
- .rspec
|
219
|
+
- .rvmrc
|
220
|
+
- .travis.yml
|
221
|
+
- Gemfile
|
222
|
+
- LICENSE
|
223
|
+
- README.md
|
224
|
+
- Rakefile
|
225
|
+
- bin/pulse
|
226
|
+
- lib/cmd.rb
|
227
|
+
- lib/pulse_meter/extensions/enumerable.rb
|
228
|
+
- lib/pulse_meter/mixins/cmd.rb
|
229
|
+
- lib/pulse_meter_cli.rb
|
230
|
+
- pulse_meter_cli.gemspec
|
231
|
+
- spec/pulse_meter/extensions/enumerable_spec.rb
|
232
|
+
- spec/pulse_meter/mixins/cmd_spec.rb
|
233
|
+
- spec/spec_helper.rb
|
234
|
+
homepage: https://github.com/savonarola/pulse_meter_cli
|
235
|
+
licenses: []
|
236
|
+
post_install_message:
|
237
|
+
rdoc_options: []
|
238
|
+
require_paths:
|
239
|
+
- lib
|
240
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
241
|
+
none: false
|
242
|
+
requirements:
|
243
|
+
- - ! '>='
|
244
|
+
- !ruby/object:Gem::Version
|
245
|
+
version: 1.9.2
|
246
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
247
|
+
none: false
|
248
|
+
requirements:
|
249
|
+
- - ! '>='
|
250
|
+
- !ruby/object:Gem::Version
|
251
|
+
version: '0'
|
252
|
+
segments:
|
253
|
+
- 0
|
254
|
+
hash: -3626993509759145837
|
255
|
+
requirements: []
|
256
|
+
rubyforge_project:
|
257
|
+
rubygems_version: 1.8.23
|
258
|
+
signing_key:
|
259
|
+
specification_version: 3
|
260
|
+
summary: CLI for lightweight Redis-based metrics aggregator and processor PulseMeter
|
261
|
+
test_files:
|
262
|
+
- spec/pulse_meter/extensions/enumerable_spec.rb
|
263
|
+
- spec/pulse_meter/mixins/cmd_spec.rb
|
264
|
+
- spec/spec_helper.rb
|
265
|
+
has_rdoc:
|