simple_metrics 0.3.6 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. data/README.markdown +53 -16
  2. data/Rakefile +0 -17
  3. data/bin/populate +13 -26
  4. data/bin/simple_metrics_client +64 -0
  5. data/bin/simple_metrics_server +3 -4
  6. data/lib/simple_metrics.rb +76 -17
  7. data/lib/simple_metrics/bucket.rb +106 -43
  8. data/lib/simple_metrics/client.rb +83 -0
  9. data/lib/simple_metrics/data_point.rb +137 -45
  10. data/lib/simple_metrics/functions.rb +5 -5
  11. data/lib/simple_metrics/graph.rb +32 -69
  12. data/lib/simple_metrics/mongo.rb +48 -0
  13. data/lib/simple_metrics/server.rb +66 -0
  14. data/lib/simple_metrics/version.rb +1 -1
  15. data/simple_metrics.gemspec +0 -6
  16. data/spec/bucket_spec.rb +152 -17
  17. data/spec/data_point_spec.rb +64 -14
  18. data/spec/graph_spec.rb +19 -30
  19. data/spec/spec_helper.rb +3 -3
  20. metadata +24 -139
  21. data/.travis.yml +0 -3
  22. data/bin/simple_metrics_web +0 -11
  23. data/config.ru +0 -6
  24. data/default_config.yml +0 -34
  25. data/lib/simple_metrics/app.rb +0 -52
  26. data/lib/simple_metrics/configuration.rb +0 -97
  27. data/lib/simple_metrics/data_point/base.rb +0 -59
  28. data/lib/simple_metrics/data_point/counter.rb +0 -20
  29. data/lib/simple_metrics/data_point/event.rb +0 -16
  30. data/lib/simple_metrics/data_point/gauge.rb +0 -19
  31. data/lib/simple_metrics/data_point/timing.rb +0 -15
  32. data/lib/simple_metrics/data_point_repository.rb +0 -114
  33. data/lib/simple_metrics/importer.rb +0 -64
  34. data/lib/simple_metrics/metric.rb +0 -29
  35. data/lib/simple_metrics/metric_repository.rb +0 -54
  36. data/lib/simple_metrics/public/css/bootstrap-responsive.min.css +0 -12
  37. data/lib/simple_metrics/public/css/bootstrap.min.css +0 -689
  38. data/lib/simple_metrics/public/css/graph.css +0 -45
  39. data/lib/simple_metrics/public/css/rickshaw.min.css +0 -1
  40. data/lib/simple_metrics/public/img/glyphicons-halflings-white.png +0 -0
  41. data/lib/simple_metrics/public/img/glyphicons-halflings.png +0 -0
  42. data/lib/simple_metrics/public/js/app.js +0 -20
  43. data/lib/simple_metrics/public/js/collections/graph.js +0 -16
  44. data/lib/simple_metrics/public/js/collections/metric.js +0 -9
  45. data/lib/simple_metrics/public/js/helpers.js +0 -23
  46. data/lib/simple_metrics/public/js/lib/backbone-0.9.2.min.js +0 -38
  47. data/lib/simple_metrics/public/js/lib/bootstrap.min.js +0 -6
  48. data/lib/simple_metrics/public/js/lib/d3.v2.min.js +0 -4
  49. data/lib/simple_metrics/public/js/lib/handlebars-1.0.0.beta.6.js +0 -1550
  50. data/lib/simple_metrics/public/js/lib/jquery-1.7.1.min.js +0 -4
  51. data/lib/simple_metrics/public/js/lib/moment.min.js +0 -6
  52. data/lib/simple_metrics/public/js/lib/rickshaw.min.js +0 -1
  53. data/lib/simple_metrics/public/js/lib/underscore-1.3.1.min.js +0 -31
  54. data/lib/simple_metrics/public/js/models/graph.js +0 -6
  55. data/lib/simple_metrics/public/js/models/metric.js +0 -7
  56. data/lib/simple_metrics/public/js/router.js +0 -42
  57. data/lib/simple_metrics/public/js/views/app.js +0 -18
  58. data/lib/simple_metrics/public/js/views/dashboard.js +0 -10
  59. data/lib/simple_metrics/public/js/views/graph.js +0 -101
  60. data/lib/simple_metrics/public/js/views/metric.js +0 -82
  61. data/lib/simple_metrics/public/js/views/metrics.js +0 -10
  62. data/lib/simple_metrics/repository.rb +0 -34
  63. data/lib/simple_metrics/udp_server.rb +0 -81
  64. data/lib/simple_metrics/views/graph.erb +0 -93
  65. data/lib/simple_metrics/views/index.erb +0 -0
  66. data/lib/simple_metrics/views/layout.erb +0 -138
  67. data/lib/simple_metrics/views/show.erb +0 -31
  68. data/spec/data_point_repository_spec.rb +0 -77
  69. data/spec/importer_spec.rb +0 -126
  70. data/spec/metric_repository_spec.rb +0 -53
data/README.markdown CHANGED
@@ -11,39 +11,76 @@ SimpleMetrics is written in Ruby and packaged as a gem.
11
11
 
12
12
  The current version is considered ALPHA.
13
13
 
14
- SimpleMetrics Server
14
+ SimpleMetrics Client
15
15
  --------------------
16
16
 
17
- We provide a simple commandline wrapper using daemons gem (http://daemons.rubyforge.org/).
17
+ Commandline client:
18
18
 
19
- Start Server as background daemon:
19
+ Send a count of 5 for data point "module.test1":
20
20
 
21
- simple_metrics_server start
21
+ simple_metrics_client module.test1 -counter 5
22
22
 
23
- Start in foreground:
23
+ Send a timing of 100ms:
24
24
 
25
- simple_metrics_server start -t
25
+ simple_metrics_client module.test1 -timing 100
26
26
 
27
- Show Help:
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":
28
47
 
29
- simple_metrics_server --help
48
+ client.decrement("com.example.test1")
30
49
 
31
- SimpleMetrics Web App
32
- -----------------
50
+ sends "com.example.test1:5|c" (a counter with a relative value of 5):
33
51
 
34
- A small Sinatra app is provided using the vegas gem (https://github.com/quirkey/vegas).
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.
67
+
68
+ SimpleMetrics Server
69
+ --------------------
70
+
71
+ We provide a simple commandline wrapper using daemons gem (http://daemons.rubyforge.org/).
35
72
 
36
- Start web app as background daemon:
73
+ Start Server as background daemond:
37
74
 
38
- simple_metrics_web
75
+ simple_metrics_server start
39
76
 
40
77
  Start in foreground:
41
78
 
42
- simple_metrics_web -F
79
+ simple_metrics_server start -t
43
80
 
44
81
  Show Help:
45
82
 
46
- simple_metrics_web --help
83
+ simple_metrics_server --help
47
84
 
48
85
  Round Robin Database Principles in MongoDB
49
86
  ------------------------------------------
@@ -54,7 +91,7 @@ We use 4 collections in MongoDB each with more coarse timestamp buckets:
54
91
  * 10 min
55
92
  * 1 day
56
93
 
57
- 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.
94
+ The 10s and 1m collections are capped collections and have a fixed size. The other will store the data as long as we have sufficient disc space.
58
95
 
59
96
  How can we map these times to graphs?
60
97
 
data/Rakefile CHANGED
@@ -2,24 +2,7 @@ require "bundler/gem_tasks"
2
2
  require 'rake'
3
3
  require 'rspec/core/rake_task'
4
4
 
5
- require 'simple_metrics'
6
-
7
5
  RSpec::Core::RakeTask.new
8
6
  task :default => :spec
9
7
  task :test => :spec
10
8
 
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,33 +6,20 @@ require "bundler/setup"
6
6
  require 'optparse'
7
7
  require "simple_metrics"
8
8
 
9
- SimpleMetrics.logger = Logger.new("/dev/null")
10
- SimpleMetrics::DataPointRepository.truncate_collections
11
- SimpleMetrics::DataPointRepository.ensure_collections_exist
9
+ ts = Time.now.to_i
12
10
 
13
- bucket = SimpleMetrics::Bucket.first
11
+ name = "test.post.clicks2"
14
12
 
15
- name = ENV['NAME'] || "test.page.visits.1"
16
- now = Time.now.to_i
17
- minute = 60
18
- hour = minute * 60
13
+ SimpleMetrics::Mongo.ensure_collections_exist
19
14
 
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
15
+ SimpleMetrics::Bucket.all.each do |bucket|
16
+ ts_bucket = bucket.ts_bucket(ts)
29
17
 
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
18
+ previous_value = rand(300)
19
+ (1..100).each do |index|
20
+ ts = ts_bucket - (bucket.seconds*index)
21
+ value = previous_value+rand(20)
22
+ data_point = SimpleMetrics::DataPoint.create_counter(:name => name, :value => value)
23
+ bucket.save(data_point, ts)
24
+ end
25
+ end
@@ -0,0 +1,64 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "rubygems"
4
+ require "bundler/setup"
5
+
6
+ require 'optparse'
7
+ require "simple_metrics"
8
+
9
+ options = {
10
+ :host => 'localhost',
11
+ :port => 8125,
12
+ :sample_rate => 1
13
+ }
14
+
15
+ parser ||= OptionParser.new do |opts|
16
+ opts.banner = "Usage Example: simple_metrics_send com.test.mymetric -c5"
17
+
18
+ opts.separator ""
19
+ opts.separator "Client options:"
20
+
21
+ opts.on("-c", "--counter VALUE", "Counter, a relative value") do |value|
22
+ options[:type] = 'c'
23
+ options[:stat] = value.to_i
24
+ end
25
+ opts.on("-g", "--gauge VALUE", "Gauge, an absolute value ") do |value|
26
+ options[:type] = 'g'
27
+ options[:stat] = value.to_i
28
+ end
29
+ opts.on("-t", "--timing VALUE", "A timing in ms") do |value|
30
+ options[:type] = 'ms'
31
+ options[:stat] = value.to_i
32
+ end
33
+ opts.on("-s", "--sample_rate VALUE", "An optional sample rate between 0 and 1 (example: 0.2)") do |value|
34
+ options[:sample_rate] = value.to_f || 1
35
+ end
36
+
37
+ opts.separator ""
38
+
39
+ opts.on("-a", "--address HOST", "bind to HOST address (default: #{options[:host]})") do |host|
40
+ options[:host] = host
41
+ end
42
+
43
+ opts.on("-p", "--port PORT", "use PORT (default: #{options[:port]})") do |port|
44
+ options[:port] = port.to_i
45
+ end
46
+
47
+ opts.separator ""
48
+ opts.on_tail("-h", "--help", "Show this message") { puts opts; exit }
49
+ opts.on_tail('-v', '--version', "Show version") { puts SimpleMetrics::VERSION; exit }
50
+
51
+ end.parse!(ARGV)
52
+
53
+ command = ARGV.shift
54
+ arguments = ARGV
55
+ client = SimpleMetrics::Client.new(options[:host])
56
+
57
+ case options[:type]
58
+ when'c'
59
+ client.count(command, options[:stat], options[:sample_rate])
60
+ when 'g'
61
+ client.gauge(command, options[:stat], options[:sample_rate])
62
+ when 'ms'
63
+ client.timing(command, options[:stat], options[:sample_rate])
64
+ end
@@ -1,19 +1,18 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
4
-
5
3
  require "rubygems"
4
+ require "bundler/setup"
6
5
  require "simple_metrics"
7
6
  require "daemons"
8
7
 
9
8
  options = {
10
9
  :backtrace => true,
11
10
  :log_output => true,
12
- :dir_mode => :script,
11
+ :dir_mode => :script
13
12
  }
14
13
 
15
14
  Daemons.run_proc("simple_metrics", options) do
16
- SimpleMetrics::UDPServer.new.start
15
+ SimpleMetrics::Server.new.start
17
16
  end
18
17
 
19
18
 
@@ -2,23 +2,13 @@
2
2
  require "logger"
3
3
 
4
4
  require "simple_metrics/version"
5
- require "simple_metrics/configuration"
6
- require "simple_metrics/udp_server"
7
- require "simple_metrics/repository"
8
- require "simple_metrics/data_point_repository"
5
+ require "simple_metrics/client"
6
+ require "simple_metrics/server"
9
7
  require "simple_metrics/data_point"
10
- require "simple_metrics/data_point/base"
11
- require "simple_metrics/data_point/counter"
12
- require "simple_metrics/data_point/event"
13
- require "simple_metrics/data_point/gauge"
14
- require "simple_metrics/data_point/timing"
15
- require "simple_metrics/importer"
16
8
  require "simple_metrics/bucket"
17
9
  require "simple_metrics/graph"
18
10
  require "simple_metrics/functions"
19
- require "simple_metrics/metric"
20
- require "simple_metrics/metric_repository"
21
- require "simple_metrics/app"
11
+ require "simple_metrics/mongo"
22
12
 
23
13
  module SimpleMetrics
24
14
  extend self
@@ -31,12 +21,81 @@ module SimpleMetrics
31
21
  @@logger = logger
32
22
  end
33
23
 
24
+ CONFIG_DEFAULTS = {
25
+ :host => 'localhost',
26
+ :port => 8125,
27
+ :flush_interval => 10
28
+ }.freeze
29
+
34
30
  def config
35
- @@config ||= Configuration.new
31
+ @@config ||= CONFIG_DEFAULTS
32
+ end
33
+
34
+ def config=(options)
35
+ @@config = CONFIG_DEFAULTS.merge(options)
36
+ end
37
+
38
+ BUCKETS_DEFAULTS = [
39
+ {
40
+ :name => 'stats_per_10s',
41
+ :seconds => 10,
42
+ :capped => true,
43
+ :size => 100_100_100
44
+ },
45
+ {
46
+ :name => 'stats_per_1min',
47
+ :seconds => 60,
48
+ :capped => true,
49
+ :size => 1_100_100_100
50
+ },
51
+ {
52
+ :name => 'stats_per_10min',
53
+ :seconds => 600,
54
+ :size => 0 ,
55
+ :capped => false
56
+ },
57
+ {
58
+ :name => 'stats_per_day',
59
+ :seconds => 86400,
60
+ :size => 0,
61
+ :capped => false
62
+ }
63
+ ].freeze
64
+
65
+ def buckets_config
66
+ @@buckets ||= BUCKETS_DEFAULTS
67
+ end
68
+
69
+ def buckets_config=(buckets)
70
+ @@buckets = buckets
71
+ end
72
+
73
+ MONGODB_DEFAULTS = {
74
+ :pool_size => 5,
75
+ :timeout => 5,
76
+ :strict => true
77
+ }.freeze
78
+
79
+ DB_CONFIG_DEFAULTS = {
80
+ :host => 'localhost',
81
+ :port => 27017,
82
+ :prefix => 'development'
83
+ }.freeze
84
+
85
+ def db_config=(options)
86
+ @@db_config = {
87
+ :host => options.delete(:host) || 'localhost',
88
+ :port => options.delete(:port) || 27017,
89
+ :db_name => "simple_metrics_#{options.delete(:prefix)}",
90
+ :options => MONGODB_DEFAULTS.merge(options)
91
+ }
36
92
  end
37
93
 
38
- def configure(hash = {}, &block)
39
- config.configure(hash, &block)
94
+ def db_config
95
+ @@db_config ||= DB_CONFIG_DEFAULTS.merge(
96
+ :db_name => "simple_metrics_#{DB_CONFIG_DEFAULTS[:prefix]}",
97
+ :options => MONGODB_DEFAULTS
98
+ )
40
99
  end
41
100
 
42
- end
101
+ end
@@ -5,39 +5,68 @@ module SimpleMetrics
5
5
  class << self
6
6
 
7
7
  def all
8
- @@all ||= SimpleMetrics.config.buckets.map { |r| Bucket.new(r) }
8
+ @@all ||= SimpleMetrics.buckets_config.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
14
15
 
15
16
  def [](index)
16
17
  all[index]
17
18
  end
18
19
 
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]
20
+ def coarse_buckets
21
+ Bucket.all.sort_by! { |r| r.seconds }[1..-1]
22
+ end
23
+
24
+ def flush_data_points(data_points)
25
+ return if data_points.empty?
26
+ SimpleMetrics.logger.info "#{Time.now} Flushing #{data_points.count} counters to MongoDB"
27
+
28
+ ts = Time.now.utc.to_i
29
+ bucket = Bucket.first
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
29
53
  end
30
54
  end
31
55
 
56
+ private
57
+
58
+ def humanized_timestamp(ts)
59
+ Time.at(ts).utc
60
+ end
32
61
  end
33
62
 
34
63
  attr_reader :name, :capped
35
64
 
36
65
  def initialize(attributes)
37
- @name = attributes.fetch(:name)
38
- @seconds = attributes.fetch(:seconds)
39
- @capped = attributes.fetch(:capped)
40
- @size = attributes.fetch(:size)
66
+ @name = attributes[:name]
67
+ @seconds = attributes[:seconds]
68
+ @capped = attributes[:capped]
69
+ @size = attributes[:size]
41
70
  end
42
71
 
43
72
  def seconds
@@ -49,7 +78,7 @@ module SimpleMetrics
49
78
  end
50
79
 
51
80
  def ts_bucket(ts)
52
- (ts / seconds) * seconds
81
+ ts / seconds * seconds
53
82
  end
54
83
 
55
84
  def next_ts_bucket(ts)
@@ -60,33 +89,64 @@ module SimpleMetrics
60
89
  ts_bucket(ts) - seconds
61
90
  end
62
91
 
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))
92
+ def find(id)
93
+ mongo_result = mongo_coll.find_one({ :_id => id })
94
+ DataPoint.create_from_db(mongo_result)
66
95
  end
67
96
 
68
- def find_data_point_at_ts(ts, name)
69
- repository.find_data_point_at_ts(ts_bucket(ts), name)
97
+ def find_all_by_name(name)
98
+ mongo_result = mongo_coll.find({ :name => name }).to_a
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) }
70
115
  end
71
116
 
72
117
  def find_all_in_ts_range_by_name(from, to, name)
73
- repository.find_all_in_ts_range_by_name(from, to, name)
118
+ mongo_result = mongo_coll.find({ :name => name, :ts => { "$gte" => from, "$lte" => to }}).to_a
119
+ mongo_result.inject([]) { |result, a| result << DataPoint.create_from_db(a) }
74
120
  end
75
121
 
76
122
  def find_all_in_ts_range_by_wildcard(from, to, target)
77
- repository.find_all_in_ts_range_by_wildcard(from, to, target)
123
+ target = target.gsub('.', '\.')
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) }
78
127
  end
79
128
 
80
- def save(dp, ts)
81
- dp.ts = ts_bucket(ts)
82
- dp.sum = dp.value
83
- dp.total = 1
84
- repository.save(dp)
129
+ def find_all_in_ts_range_by_regexp(from, to, target)
130
+ mongo_result = mongo_coll.find({ :name => /#{target}/, :ts => { "$gte" => from, "$lte" => to } }).to_a
131
+ mongo_result.inject([]) { |result, a| result << DataPoint.create_from_db(a) }
85
132
  end
86
133
 
87
- def update(dp, ts)
88
- dp.ts = ts_bucket(ts)
89
- repository.update(dp, ts)
134
+ def stats_exist_in_previous_ts?(ts)
135
+ mongo_coll.find({ :ts => ts }).count > 0
136
+ end
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)
90
150
  end
91
151
 
92
152
  def capped?
@@ -96,28 +156,31 @@ module SimpleMetrics
96
156
  def fill_gaps(from, to, query_result)
97
157
  return query_result if query_result.nil? || query_result.size == 0
98
158
 
99
- existing_ts_entries = query_result.inject({}) { |result, dp| result[dp.ts] = dp; result }
159
+ tmp_hash = DataPoint.ts_hash(query_result)
100
160
  dp_template = query_result.first
101
161
 
102
162
  result = []
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
163
+ each_ts(from, to) do |current_bucket_ts|
164
+ result <<
165
+ if tmp_hash.key?(current_bucket_ts)
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
106
173
  end
107
174
  result
108
175
  end
109
176
 
110
177
  private
111
178
 
112
- def repository
113
- DataPointRepository.for_retention(name)
114
- end
115
-
116
179
  def each_ts(from, to)
117
- ts_bucket = ts_bucket(from)
118
- while (ts_bucket <= ts_bucket(to))
119
- yield(ts_bucket)
120
- ts_bucket = ts_bucket + seconds
180
+ current_bucket_ts = ts_bucket(from)
181
+ while (current_bucket_ts <= ts_bucket(to))
182
+ yield(current_bucket_ts)
183
+ current_bucket_ts = current_bucket_ts + seconds
121
184
  end
122
185
  end
123
186