simple_metrics 0.4.0 → 0.4.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +3 -0
- data/README.markdown +7 -59
- data/Rakefile +17 -0
- data/bin/populate +25 -12
- data/bin/populate_for_demo +65 -0
- data/bin/simple_metrics_server +4 -3
- data/config.ru +13 -0
- data/default_config.yml +34 -0
- data/lib/simple_metrics/bucket.rb +43 -106
- data/lib/simple_metrics/configuration.rb +82 -0
- data/lib/simple_metrics/dashboard.rb +29 -0
- data/lib/simple_metrics/dashboard_repository.rb +59 -0
- data/lib/simple_metrics/data_point/base.rb +59 -0
- data/lib/simple_metrics/data_point/counter.rb +20 -0
- data/lib/simple_metrics/data_point/event.rb +16 -0
- data/lib/simple_metrics/data_point/gauge.rb +19 -0
- data/lib/simple_metrics/data_point/timing.rb +15 -0
- data/lib/simple_metrics/data_point.rb +45 -137
- data/lib/simple_metrics/data_point_repository.rb +115 -0
- data/lib/simple_metrics/functions.rb +5 -5
- data/lib/simple_metrics/graph.rb +69 -32
- data/lib/simple_metrics/importer.rb +64 -0
- data/lib/simple_metrics/instrument.rb +28 -0
- data/lib/simple_metrics/instrument_repository.rb +64 -0
- data/lib/simple_metrics/metric.rb +29 -0
- data/lib/simple_metrics/metric_repository.rb +54 -0
- data/lib/simple_metrics/repository.rb +34 -0
- data/lib/simple_metrics/udp_server.rb +81 -0
- data/lib/simple_metrics/version.rb +1 -1
- data/lib/simple_metrics.rb +21 -76
- data/simple_metrics.gemspec +4 -0
- data/spec/bucket_spec.rb +17 -152
- data/spec/dashboard_repository_spec.rb +52 -0
- data/spec/data_point_repository_spec.rb +77 -0
- data/spec/data_point_spec.rb +14 -64
- data/spec/graph_spec.rb +30 -19
- data/spec/importer_spec.rb +126 -0
- data/spec/instrument_repository_spec.rb +52 -0
- data/spec/metric_repository_spec.rb +53 -0
- data/spec/spec_helper.rb +4 -3
- metadata +93 -23
- data/bin/simple_metrics_client +0 -64
- data/lib/simple_metrics/client.rb +0 -83
- data/lib/simple_metrics/mongo.rb +0 -48
- data/lib/simple_metrics/server.rb +0 -66
data/.travis.yml
ADDED
data/README.markdown
CHANGED
@@ -9,78 +9,26 @@ Technically speaking it provides a simple UDP interface to send data to an Event
|
|
9
9
|
|
10
10
|
SimpleMetrics is written in Ruby and packaged as a gem.
|
11
11
|
|
12
|
-
The current version is considered ALPHA.
|
12
|
+
The current version is considered ALPHA.
|
13
13
|
|
14
|
-
|
15
|
-
--------------------
|
16
|
-
|
17
|
-
Commandline client:
|
18
|
-
|
19
|
-
Send a count of 5 for data point "module.test1":
|
20
|
-
|
21
|
-
simple_metrics_client module.test1 -counter 5
|
22
|
-
|
23
|
-
Send a timing of 100ms:
|
24
|
-
|
25
|
-
simple_metrics_client module.test1 -timing 100
|
26
|
-
|
27
|
-
doing the same, but since we expect a lot of calls we sample the data (10%):
|
28
|
-
|
29
|
-
simple_metrics_client module.test1 -timing 100 --sample_rate 0.1
|
30
|
-
|
31
|
-
more info:
|
32
|
-
|
33
|
-
simple_metrics_client --help
|
34
|
-
|
35
|
-
Ruby client API
|
36
|
-
---------------
|
37
|
-
|
38
|
-
Initialize client:
|
39
|
-
|
40
|
-
client = SimpleMetrics::Client.new("localhost")
|
41
|
-
|
42
|
-
sends "com.example.test1:1|c" via UDP:
|
43
|
-
|
44
|
-
client.increment("com.example.test1")
|
45
|
-
|
46
|
-
sends "com.example.test1:-1|c":
|
47
|
-
|
48
|
-
client.decrement("com.example.test1")
|
49
|
-
|
50
|
-
sends "com.example.test1:5|c" (a counter with a relative value of 5):
|
51
|
-
|
52
|
-
client.count("com.example.test1", 5)
|
53
|
-
|
54
|
-
sends "com.example.test1:5|c|@0.1" with a sample rate of 10%:
|
55
|
-
|
56
|
-
client.count("com.example.test1", 5, 0.1)
|
57
|
-
|
58
|
-
sends "com.example.test1:5|g" (meaning gauge, an absolute value of 5):
|
59
|
-
|
60
|
-
client.count("com.example.test1", 5)
|
61
|
-
|
62
|
-
sends "com.example.test1:100|ms":
|
63
|
-
|
64
|
-
client.timing("com.example.test1")
|
65
|
-
|
66
|
-
More examples in the examples/ directory.
|
14
|
+
There is a rails app provided to visualize the graphs in dashboards.
|
67
15
|
|
68
16
|
SimpleMetrics Server
|
69
17
|
--------------------
|
70
18
|
|
71
19
|
We provide a simple commandline wrapper using daemons gem (http://daemons.rubyforge.org/).
|
72
20
|
|
73
|
-
Start Server as background
|
21
|
+
Start Server as background daemon:
|
74
22
|
|
75
|
-
|
23
|
+
simple_metrics_server start
|
76
24
|
|
77
25
|
Start in foreground:
|
78
26
|
|
79
|
-
|
27
|
+
simple_metrics_server start -t
|
80
28
|
|
81
29
|
Show Help:
|
82
30
|
|
83
|
-
|
31
|
+
simple_metrics_server --help
|
84
32
|
|
85
33
|
Round Robin Database Principles in MongoDB
|
86
34
|
------------------------------------------
|
@@ -91,7 +39,7 @@ We use 4 collections in MongoDB each with more coarse timestamp buckets:
|
|
91
39
|
* 10 min
|
92
40
|
* 1 day
|
93
41
|
|
94
|
-
The
|
42
|
+
The 10sec and 1min collections are capped collections and have a fixed size. The others will store the data as long as there is sufficient disc space.
|
95
43
|
|
96
44
|
How can we map these times to graphs?
|
97
45
|
|
data/Rakefile
CHANGED
@@ -2,7 +2,24 @@ require "bundler/gem_tasks"
|
|
2
2
|
require 'rake'
|
3
3
|
require 'rspec/core/rake_task'
|
4
4
|
|
5
|
+
require 'simple_metrics'
|
6
|
+
|
5
7
|
RSpec::Core::RakeTask.new
|
6
8
|
task :default => :spec
|
7
9
|
task :test => :spec
|
8
10
|
|
11
|
+
namespace :simple_metrics do
|
12
|
+
|
13
|
+
desc "Ensure collections and index exist"
|
14
|
+
task :ensure_collections_exist do
|
15
|
+
SimpleMetrics.logger = Logger.new($stdout)
|
16
|
+
SimpleMetrics::DataPointRepository.ensure_collections_exist
|
17
|
+
end
|
18
|
+
|
19
|
+
desc "Truncate all collections"
|
20
|
+
task :truncate_collections do
|
21
|
+
SimpleMetrics.logger = Logger.new($stdout)
|
22
|
+
SimpleMetrics::DataPointRepository.truncate_collections
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
data/bin/populate
CHANGED
@@ -6,20 +6,33 @@ require "bundler/setup"
|
|
6
6
|
require 'optparse'
|
7
7
|
require "simple_metrics"
|
8
8
|
|
9
|
-
|
9
|
+
SimpleMetrics.logger = Logger.new("/dev/null")
|
10
|
+
SimpleMetrics::DataPointRepository.truncate_collections
|
11
|
+
SimpleMetrics::DataPointRepository.ensure_collections_exist
|
10
12
|
|
11
|
-
|
13
|
+
bucket = SimpleMetrics::Bucket.first
|
12
14
|
|
13
|
-
|
15
|
+
name = ENV['NAME'] || "test.page.visits.1"
|
16
|
+
now = Time.now.to_i
|
17
|
+
minute = 60
|
18
|
+
hour = minute * 60
|
14
19
|
|
15
|
-
|
16
|
-
|
20
|
+
def create_dps(name)
|
21
|
+
previous_value = 20
|
22
|
+
(1..1).inject([]) do |result, index|
|
23
|
+
value = previous_value+rand(20)
|
24
|
+
result << SimpleMetrics::DataPoint::Counter.new(:name => name, :value => value)
|
25
|
+
previous_value = value
|
26
|
+
result
|
27
|
+
end
|
28
|
+
end
|
17
29
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
30
|
+
counter = 1
|
31
|
+
current = now - 1 * hour
|
32
|
+
while (current < now)
|
33
|
+
dps = create_dps(name)
|
34
|
+
puts "flush data for #{Time.at(current)}, #{counter}"
|
35
|
+
SimpleMetrics::Importer.flush_data_points(dps, current)
|
36
|
+
current += 10
|
37
|
+
counter += 1
|
25
38
|
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "rubygems"
|
4
|
+
require "bundler/setup"
|
5
|
+
|
6
|
+
require 'optparse'
|
7
|
+
require "simple_metrics"
|
8
|
+
|
9
|
+
SimpleMetrics.logger = Logger.new("/dev/null")
|
10
|
+
SimpleMetrics::DataPointRepository.truncate_collections
|
11
|
+
SimpleMetrics::DataPointRepository.ensure_collections_exist
|
12
|
+
SimpleMetrics::MetricRepository.truncate_collections
|
13
|
+
|
14
|
+
def create_dps(name)
|
15
|
+
previous_value = 20
|
16
|
+
(1..1).inject([]) do |result, index|
|
17
|
+
value = previous_value+rand(20)
|
18
|
+
result << SimpleMetrics::DataPoint::Counter.new(:name => name, :value => value)
|
19
|
+
previous_value = value
|
20
|
+
result
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def flush_data_points(name)
|
25
|
+
#bucket = SimpleMetrics::Bucket.first
|
26
|
+
now = Time.now.to_i
|
27
|
+
minute = 60
|
28
|
+
hour = minute * 60
|
29
|
+
|
30
|
+
counter = 1
|
31
|
+
current = now - 1 * hour
|
32
|
+
while (current < now)
|
33
|
+
dps = create_dps(name)
|
34
|
+
puts "flush data for #{Time.at(current)}, #{counter}"
|
35
|
+
SimpleMetrics::Importer.flush_data_points(dps, current)
|
36
|
+
current += 10
|
37
|
+
counter += 1
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
name1 = "test.page.visits"
|
43
|
+
flush_data_points(name1)
|
44
|
+
name2 = "test.invoices.send"
|
45
|
+
flush_data_points(name2)
|
46
|
+
|
47
|
+
metric1 = SimpleMetrics::MetricRepository.find_one_by_name(name1)
|
48
|
+
metric2 = SimpleMetrics::MetricRepository.find_one_by_name(name2)
|
49
|
+
|
50
|
+
SimpleMetrics::InstrumentRepository.truncate_collections
|
51
|
+
instrument1 = SimpleMetrics::Instrument.new(:name => "Example Instrument 1", :metrics => [{ :name => metric1.name }, { :name => metric2.name}])
|
52
|
+
instrument2 = SimpleMetrics::Instrument.new(:name => "Example Instrument 2", :metrics => [{ :name => metric1.name} ])
|
53
|
+
instrument1.id = SimpleMetrics::InstrumentRepository.save(instrument1)
|
54
|
+
instrument2.id = SimpleMetrics::InstrumentRepository.save(instrument2)
|
55
|
+
|
56
|
+
puts instrument1.inspect
|
57
|
+
puts instrument2.inspect
|
58
|
+
10.times do |i|
|
59
|
+
instrument = SimpleMetrics::Instrument.new(:name => "Example Instrument Randmon #{i}", :metrics => [{ :name => metric1.name}])
|
60
|
+
SimpleMetrics::InstrumentRepository.save(instrument)
|
61
|
+
end
|
62
|
+
|
63
|
+
SimpleMetrics::DashboardRepository.truncate_collections
|
64
|
+
SimpleMetrics::DashboardRepository.save(SimpleMetrics::Dashboard.new(:name => "Example Dashboard 1", :instruments => [instrument1.id.to_s, instrument2.id.to_s]))
|
65
|
+
SimpleMetrics::DashboardRepository.save(SimpleMetrics::Dashboard.new(:name => "Example Dashboard 2", :instruments => [instrument1.id.to_s]))
|
data/bin/simple_metrics_server
CHANGED
@@ -1,18 +1,19 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
+
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
|
4
|
+
|
3
5
|
require "rubygems"
|
4
|
-
require "bundler/setup"
|
5
6
|
require "simple_metrics"
|
6
7
|
require "daemons"
|
7
8
|
|
8
9
|
options = {
|
9
10
|
:backtrace => true,
|
10
11
|
:log_output => true,
|
11
|
-
:dir_mode => :script
|
12
|
+
:dir_mode => :script,
|
12
13
|
}
|
13
14
|
|
14
15
|
Daemons.run_proc("simple_metrics", options) do
|
15
|
-
SimpleMetrics::
|
16
|
+
SimpleMetrics::UDPServer.new.start
|
16
17
|
end
|
17
18
|
|
18
19
|
|
data/config.ru
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
$LOAD_PATH.unshift ::File.expand_path(::File.dirname(__FILE__) + '/lib')
|
2
|
+
|
3
|
+
require "rubygems"
|
4
|
+
require "simple_metrics"
|
5
|
+
require "simple_metrics/app"
|
6
|
+
|
7
|
+
map "/assets" do
|
8
|
+
run SimpleMetrics::App.sprockets
|
9
|
+
end
|
10
|
+
|
11
|
+
map "/" do
|
12
|
+
run SimpleMetrics::App
|
13
|
+
end
|
data/default_config.yml
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
server:
|
2
|
+
host: 'localhost'
|
3
|
+
port: 8125
|
4
|
+
flush_interval: 10
|
5
|
+
|
6
|
+
db:
|
7
|
+
host: 'localhost'
|
8
|
+
port: 27017
|
9
|
+
prefix: 'development'
|
10
|
+
options:
|
11
|
+
pool_size: 5
|
12
|
+
timeout: 5
|
13
|
+
|
14
|
+
web:
|
15
|
+
host: 'localhost'
|
16
|
+
port: 5678
|
17
|
+
|
18
|
+
buckets:
|
19
|
+
- name: 'stats_per_10s'
|
20
|
+
seconds: 10
|
21
|
+
capped: true
|
22
|
+
size: 180_000 # 6*30 = 180 (30 min ttl), 180 * 100 = 18.000 (100 data points), 18.000 * 10 (bytes each) = 180.000
|
23
|
+
- name: 'stats_per_1min'
|
24
|
+
seconds: 60
|
25
|
+
capped: true
|
26
|
+
size: 120_000 # 60*3 = 180 (3h ttl), 120 * 100 = 18.000 (100 data points), 18.000 * 10 (bytes each) = 180.000
|
27
|
+
- name: 'stats_per_10min'
|
28
|
+
seconds: 600
|
29
|
+
size: 0
|
30
|
+
capped: false
|
31
|
+
- name: 'stats_per_day'
|
32
|
+
seconds: 86400 # 600*6*24
|
33
|
+
size: 0
|
34
|
+
capped: false
|
@@ -5,68 +5,39 @@ module SimpleMetrics
|
|
5
5
|
class << self
|
6
6
|
|
7
7
|
def all
|
8
|
-
@@all ||= SimpleMetrics.
|
8
|
+
@@all ||= SimpleMetrics.config.buckets.map { |r| Bucket.new(r) }
|
9
9
|
end
|
10
10
|
|
11
11
|
def first
|
12
12
|
all.first
|
13
13
|
end
|
14
|
-
alias :finest :first
|
15
14
|
|
16
15
|
def [](index)
|
17
16
|
all[index]
|
18
17
|
end
|
19
18
|
|
20
|
-
def
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
data_points.group_by { |data| data.name }.each_pair do |name,dps|
|
31
|
-
data = DataPoint.aggregate(dps)
|
32
|
-
bucket.save(data, ts)
|
33
|
-
end
|
34
|
-
|
35
|
-
self.aggregate_all(ts)
|
36
|
-
end
|
37
|
-
|
38
|
-
def aggregate_all(ts)
|
39
|
-
ts_bucket = self.first.ts_bucket(ts)
|
40
|
-
|
41
|
-
coarse_buckets.each do |bucket|
|
42
|
-
current_ts = bucket.ts_bucket(ts_bucket)
|
43
|
-
previous_ts = bucket.previous_ts_bucket(ts_bucket)
|
44
|
-
SimpleMetrics.logger.debug "Aggregating #{bucket.name} #{previous_ts}....#{current_ts} (#{humanized_timestamp(previous_ts)}..#{humanized_timestamp(current_ts)})"
|
45
|
-
|
46
|
-
unless bucket.stats_exist_in_previous_ts?(previous_ts)
|
47
|
-
data_points = self.first.find_all_in_ts_range(previous_ts, current_ts)
|
48
|
-
data_points.group_by { |data| data.name }.each_pair do |name,dps|
|
49
|
-
data = DataPoint.aggregate(dps)
|
50
|
-
bucket.save(data, previous_ts)
|
51
|
-
end
|
52
|
-
end
|
19
|
+
def for_time(time)
|
20
|
+
case time
|
21
|
+
when 'minute'
|
22
|
+
self[0]
|
23
|
+
when 'hour'
|
24
|
+
self[1]
|
25
|
+
when 'day'
|
26
|
+
self[2]
|
27
|
+
when 'week'
|
28
|
+
self[3]
|
53
29
|
end
|
54
30
|
end
|
55
31
|
|
56
|
-
private
|
57
|
-
|
58
|
-
def humanized_timestamp(ts)
|
59
|
-
Time.at(ts).utc
|
60
|
-
end
|
61
32
|
end
|
62
33
|
|
63
34
|
attr_reader :name, :capped
|
64
35
|
|
65
36
|
def initialize(attributes)
|
66
|
-
@name = attributes
|
67
|
-
@seconds = attributes
|
68
|
-
@capped = attributes
|
69
|
-
@size = attributes
|
37
|
+
@name = attributes.fetch(:name)
|
38
|
+
@seconds = attributes.fetch(:seconds)
|
39
|
+
@capped = attributes.fetch(:capped)
|
40
|
+
@size = attributes.fetch(:size)
|
70
41
|
end
|
71
42
|
|
72
43
|
def seconds
|
@@ -78,7 +49,7 @@ module SimpleMetrics
|
|
78
49
|
end
|
79
50
|
|
80
51
|
def ts_bucket(ts)
|
81
|
-
ts / seconds * seconds
|
52
|
+
(ts / seconds) * seconds
|
82
53
|
end
|
83
54
|
|
84
55
|
def next_ts_bucket(ts)
|
@@ -89,64 +60,33 @@ module SimpleMetrics
|
|
89
60
|
ts_bucket(ts) - seconds
|
90
61
|
end
|
91
62
|
|
92
|
-
|
93
|
-
|
94
|
-
|
63
|
+
# TODO: only used in tests, do we need it?
|
64
|
+
def find_all_at_ts(ts)
|
65
|
+
repository.find_all_at_ts(ts_bucket(ts))
|
95
66
|
end
|
96
67
|
|
97
|
-
def
|
98
|
-
|
99
|
-
mongo_result.inject([]) { |result, a| result << DataPoint.create_from_db(a) }
|
100
|
-
end
|
101
|
-
|
102
|
-
def find_all_in_ts(ts)
|
103
|
-
mongo_result = mongo_coll.find({ :ts => ts_bucket(ts) }).to_a
|
104
|
-
mongo_result.inject([]) { |result, a| result << DataPoint.create_from_db(a) }
|
105
|
-
end
|
106
|
-
|
107
|
-
def find_all_in_ts_by_name(ts, name)
|
108
|
-
mongo_result = mongo_coll.find({ :ts => ts_bucket(ts), :name => name }).to_a
|
109
|
-
mongo_result.inject([]) { |result, a| result << DataPoint.create_from_db(a) }
|
110
|
-
end
|
111
|
-
|
112
|
-
def find_all_in_ts_range(from, to)
|
113
|
-
mongo_result = mongo_coll.find({ :ts => { "$gte" => from, "$lte" => to }}).to_a
|
114
|
-
mongo_result.inject([]) { |result, a| result << DataPoint.create_from_db(a) }
|
68
|
+
def find_data_point_at_ts(ts, name)
|
69
|
+
repository.find_data_point_at_ts(ts_bucket(ts), name)
|
115
70
|
end
|
116
71
|
|
117
72
|
def find_all_in_ts_range_by_name(from, to, name)
|
118
|
-
|
119
|
-
mongo_result.inject([]) { |result, a| result << DataPoint.create_from_db(a) }
|
73
|
+
repository.find_all_in_ts_range_by_name(from, to, name)
|
120
74
|
end
|
121
75
|
|
122
76
|
def find_all_in_ts_range_by_wildcard(from, to, target)
|
123
|
-
|
124
|
-
target = target.gsub('*', '.*')
|
125
|
-
mongo_result = mongo_coll.find({ :name => /#{target}/, :ts => { "$gte" => from, "$lte" => to } }).to_a
|
126
|
-
mongo_result.inject([]) { |result, a| result << DataPoint.create_from_db(a) }
|
77
|
+
repository.find_all_in_ts_range_by_wildcard(from, to, target)
|
127
78
|
end
|
128
79
|
|
129
|
-
def
|
130
|
-
|
131
|
-
|
80
|
+
def save(dp, ts)
|
81
|
+
dp.ts = ts_bucket(ts)
|
82
|
+
dp.sum = dp.value
|
83
|
+
dp.total = 1
|
84
|
+
repository.save(dp)
|
132
85
|
end
|
133
86
|
|
134
|
-
def
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
def find_all_distinct_names
|
139
|
-
mongo_coll.distinct(:name).to_a
|
140
|
-
end
|
141
|
-
|
142
|
-
def save(stats, ts)
|
143
|
-
stats.ts = ts_bucket(ts)
|
144
|
-
result = mongo_coll.insert(stats.attributes)
|
145
|
-
SimpleMetrics.logger.debug "SERVER: MongoDB - insert in #{name}: #{stats.inspect}, result: #{result}"
|
146
|
-
end
|
147
|
-
|
148
|
-
def mongo_coll
|
149
|
-
Mongo.collection(name)
|
87
|
+
def update(dp, ts)
|
88
|
+
dp.ts = ts_bucket(ts)
|
89
|
+
repository.update(dp, ts)
|
150
90
|
end
|
151
91
|
|
152
92
|
def capped?
|
@@ -156,31 +96,28 @@ module SimpleMetrics
|
|
156
96
|
def fill_gaps(from, to, query_result)
|
157
97
|
return query_result if query_result.nil? || query_result.size == 0
|
158
98
|
|
159
|
-
|
99
|
+
existing_ts_entries = query_result.inject({}) { |result, dp| result[dp.ts] = dp; result }
|
160
100
|
dp_template = query_result.first
|
161
101
|
|
162
102
|
result = []
|
163
|
-
each_ts(from, to) do |
|
164
|
-
|
165
|
-
|
166
|
-
tmp_hash[current_bucket_ts]
|
167
|
-
else
|
168
|
-
dp = dp_template.dup
|
169
|
-
dp.value = nil
|
170
|
-
dp.ts = current_bucket_ts
|
171
|
-
dp
|
172
|
-
end
|
103
|
+
each_ts(from, to) do |ts_bucket|
|
104
|
+
dp = existing_ts_entries[ts_bucket] || DataPoint::Base.new(:name => dp_template.name, :ts => ts_bucket)
|
105
|
+
result << dp
|
173
106
|
end
|
174
107
|
result
|
175
108
|
end
|
176
109
|
|
177
110
|
private
|
178
111
|
|
112
|
+
def repository
|
113
|
+
DataPointRepository.for_retention(name)
|
114
|
+
end
|
115
|
+
|
179
116
|
def each_ts(from, to)
|
180
|
-
|
181
|
-
while (
|
182
|
-
yield(
|
183
|
-
|
117
|
+
ts_bucket = ts_bucket(from)
|
118
|
+
while (ts_bucket <= ts_bucket(to))
|
119
|
+
yield(ts_bucket)
|
120
|
+
ts_bucket = ts_bucket + seconds
|
184
121
|
end
|
185
122
|
end
|
186
123
|
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module SimpleMetrics
|
4
|
+
class Configuration
|
5
|
+
|
6
|
+
attr_reader :config
|
7
|
+
|
8
|
+
def initialize(hash = {}, &block)
|
9
|
+
@config = load_defaults.merge(hash.symbolize_keys)
|
10
|
+
end
|
11
|
+
|
12
|
+
def configure(hash = {}, &block)
|
13
|
+
yield self if block_given?
|
14
|
+
self
|
15
|
+
end
|
16
|
+
|
17
|
+
def db
|
18
|
+
@db ||= config.fetch(:db).symbolize_keys
|
19
|
+
end
|
20
|
+
|
21
|
+
def db=(db)
|
22
|
+
@db = db
|
23
|
+
end
|
24
|
+
|
25
|
+
def buckets
|
26
|
+
@buckets ||= begin
|
27
|
+
tmp = config.fetch(:buckets)
|
28
|
+
tmp.map { |b| b.symbolize_keys }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def buckets=(buckets)
|
33
|
+
@buckets = buckets
|
34
|
+
end
|
35
|
+
|
36
|
+
def server
|
37
|
+
@server ||= config.fetch(:server).symbolize_keys
|
38
|
+
end
|
39
|
+
|
40
|
+
def server=(server)
|
41
|
+
@server = server
|
42
|
+
end
|
43
|
+
|
44
|
+
def web
|
45
|
+
@web ||= config.fetch(:web).symbolize_keys
|
46
|
+
end
|
47
|
+
|
48
|
+
def web=(web)
|
49
|
+
@web = web
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def load_defaults
|
55
|
+
@config = load_config
|
56
|
+
rescue Errno::ENOENT # not found error
|
57
|
+
logger.info "Creating initial config file: #{config_file}"
|
58
|
+
FileUtils.cp(default_config_file, config_file)
|
59
|
+
@config = load_config
|
60
|
+
end
|
61
|
+
|
62
|
+
def config_file
|
63
|
+
File.expand_path('~/.simple_metrics.conf')
|
64
|
+
end
|
65
|
+
|
66
|
+
def default_config_file
|
67
|
+
File.expand_path('../../../default_config.yml', __FILE__)
|
68
|
+
end
|
69
|
+
|
70
|
+
def load_config
|
71
|
+
YAML.load_file(config_file).symbolize_keys
|
72
|
+
rescue ArgumentError => e
|
73
|
+
logger.error "Error parsing config file: #{e}"
|
74
|
+
rescue IOError => e
|
75
|
+
logger.error "Error reading config file: #{e}"
|
76
|
+
end
|
77
|
+
|
78
|
+
def logger
|
79
|
+
SimpleMetrics.logger
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module SimpleMetrics
|
2
|
+
class Dashboard
|
3
|
+
|
4
|
+
attr_reader :id, :created_at, :updated_at
|
5
|
+
attr_accessor :name, :instruments
|
6
|
+
|
7
|
+
def initialize(attributes)
|
8
|
+
@id = attributes[:id]
|
9
|
+
@name = attributes[:name]
|
10
|
+
@created_at = attributes[:created_at]
|
11
|
+
@updated_at = attributes[:updated_at]
|
12
|
+
@instruments = attributes[:instruments] || []
|
13
|
+
end
|
14
|
+
|
15
|
+
def attributes
|
16
|
+
{
|
17
|
+
:id => @id.to_s, # convert bson id to str
|
18
|
+
:name => @name,
|
19
|
+
:instruments => @instruments,
|
20
|
+
:created_at => @created_at,
|
21
|
+
:updated_at => @updated_at
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_s
|
26
|
+
attributes.to_s
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|