meter 0.0.10 → 0.1.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4b51363f08ba9926173d4fc3ea17658953d17621
4
- data.tar.gz: df0465fd8394b30a9723c8958d171a9976ea1121
3
+ metadata.gz: 1fea98858b4bdf1096610854053ff2f28532ed90
4
+ data.tar.gz: b24dab519654d590152ee94dc88f60e671575ffa
5
5
  SHA512:
6
- metadata.gz: 2bfb300157cea6663debde191fa1ad5e460329764422f6608da0f3e12de7195273fa7a7a8b9848610fc0d6fc8ac9914859caa2b3e4a63ac03415195020d27812
7
- data.tar.gz: 94945415dfd1ad008a7d89a1ea5b53ff29316333feabccc4211d1f4292d5f2ff8bcb2d1145f51d5ad074119e5ae48318173308bed89dbe50f5b50af72d498eb5
6
+ metadata.gz: 842d05e7398a50393fa7c3ee6252ef07e08ef37eda3757129d32d4b6972ffe4486b362dd881483e04d6728075d00d28a441d3d69fa1ff12cbc4401861e9af5e1
7
+ data.tar.gz: 2c57251afb124930882c5d546bb9916354a289cd91ed9499ccc10f27933bdb1914ac5b17f3d3b5a01788f56af9b031a2dfd8f154c45232be1126b6ade2a725bb
data/lib/meter/backend.rb CHANGED
@@ -1,216 +1,56 @@
1
+ require 'json'
1
2
  require 'socket'
2
- require 'pathname'
3
-
4
-
5
- # Copy and paste from https://github.com/DataDog/dogstatsd-ruby/blob/master/lib/statsd.rb
6
- # Changes:
7
- # - The class is renamed to "Backend"
8
- # - the logger class method points to meter's logger
9
3
 
10
4
  module Meter
11
- # = Statsd: A DogStatsd client (https://www.datadoghq.com)
12
- #
13
- # @example Set up a global Statsd client for a server on localhost:8125
14
- # require 'statsd'
15
- # $statsd = Statsd.new 'localhost', 8125
16
- # @example Send some stats
17
- # $statsd.increment 'page.views'
18
- # $statsd.timing 'page.load', 320
19
- # $statsd.gauge 'users.online', 100
20
- # @example Use {#time} to time the execution of a block
21
- # $statsd.time('account.activate') { @account.activate! }
22
- # @example Create a namespaced statsd client and increment 'account.activate'
23
- # statsd = Statsd.new('localhost').tap{|sd| sd.namespace = 'account'}
24
- # statsd.increment 'activate'
25
5
  class Backend
26
- # A namespace to prepend to all statsd calls.
27
- attr_reader :namespace
28
-
29
- # A String describing the environment, useful to distinguish staging/production
30
- attr_reader :environment
31
-
32
- attr_reader :log_dir
33
-
34
- # StatsD host. Defaults to 127.0.0.1.
35
- attr_accessor :host
36
6
 
37
- # StatsD port. Defaults to 8125.
38
- attr_accessor :port
39
-
40
- def self.logger
41
- Meter.config.logger
42
- end
43
-
44
- # Return the current version of the library.
45
- def self.VERSION
46
- "1.1.0"
47
- end
7
+ attr_reader :host, :port
48
8
 
49
- # @param [String] host your statsd host
50
- # @param [Integer] port your statsd port
51
9
  def initialize(host = '127.0.0.1', port = 8125)
52
- self.host, self.port = host, port
10
+ @host, @port = host, port
53
11
  @prefix = nil
54
12
  @socket = UDPSocket.new
55
13
  end
56
14
 
57
- def namespace=(namespace) #:nodoc:
58
- @namespace = namespace
59
- @prefix = "#{namespace}." if @namespace
60
- end
61
-
62
- def environment=(new_environment)
63
- @environment = new_environment.to_s
64
- end
65
-
66
- def host=(host) #:nodoc:
67
- @host = host || '127.0.0.1'
68
- end
69
-
70
- def port=(port) #:nodoc:
71
- @port = port || 8125
72
- end
73
-
74
- def log_dir=(log_dir)
75
- @log_dir = Pathname.new log_dir
15
+ def increment(stat, options = {})
16
+ send_stats stat, 1, :c, options
76
17
  end
77
18
 
78
- # Sends an increment (count = 1) for the given stat to the statsd server.
79
- #
80
- # @param [String] stat stat name
81
- # @param [Hash] opts the options to create the metric with
82
- # @option opts [Numeric] :sample_rate sample rate, 1 for always
83
- # @option opts [Array<String>] :tags An array of tags
84
- # @see #count
85
- def increment(stat, opts={})
86
- count stat, 1, opts
19
+ def gauge(stat, value, options = {})
20
+ send_stats stat, value, :g, options
87
21
  end
88
22
 
89
- # Sends a decrement (count = -1) for the given stat to the statsd server.
90
- #
91
- # @param [String] stat stat name
92
- # @param [Hash] opts the options to create the metric with
93
- # @option opts [Numeric] :sample_rate sample rate, 1 for always
94
- # @option opts [Array<String>] :tags An array of tags
95
- # @see #count
96
- def decrement(stat, opts={})
97
- count stat, -1, opts
98
- end
99
-
100
- # Sends an arbitrary count for the given stat to the statsd server.
101
- #
102
- # @param [String] stat stat name
103
- # @param [Integer] count count
104
- # @param [Hash] opts the options to create the metric with
105
- # @option opts [Numeric] :sample_rate sample rate, 1 for always
106
- # @option opts [Array<String>] :tags An array of tags
107
- def count(stat, count, opts={})
108
- send_stats stat, count, :c, opts
109
- end
110
-
111
- # Sends an arbitary gauge value for the given stat to the statsd server.
112
- #
113
- # This is useful for recording things like available disk space,
114
- # memory usage, and the like, which have different semantics than
115
- # counters.
116
- #
117
- # @param [String] stat stat name.
118
- # @param [Numeric] gauge value.
119
- # @param [Hash] opts the options to create the metric with
120
- # @option opts [Numeric] :sample_rate sample rate, 1 for always
121
- # @option opts [Array<String>] :tags An array of tags
122
- # @example Report the current user count:
123
- # $statsd.gauge('user.count', User.count)
124
- def gauge(stat, value, opts={})
125
- send_stats stat, value, :g, opts
126
- end
127
-
128
- # Sends a value to be tracked as a histogram to the statsd server.
129
- #
130
- # @param [String] stat stat name.
131
- # @param [Numeric] histogram value.
132
- # @param [Hash] opts the options to create the metric with
133
- # @option opts [Numeric] :sample_rate sample rate, 1 for always
134
- # @option opts [Array<String>] :tags An array of tags
135
- # @example Report the current user count:
136
- # $statsd.histogram('user.count', User.count)
137
- def histogram(stat, value, opts={})
138
- send_stats stat, value, :h, opts
139
- end
140
-
141
- # Sends a timing (in ms) for the given stat to the statsd server. The
142
- # sample_rate determines what percentage of the time this report is sent. The
143
- # statsd server then uses the sample_rate to correctly track the average
144
- # timing for the stat.
145
- #
146
- # @param [String] stat stat name
147
- # @param [Integer] ms timing in milliseconds
148
- # @param [Hash] opts the options to create the metric with
149
- # @option opts [Numeric] :sample_rate sample rate, 1 for always
150
- # @option opts [Array<String>] :tags An array of tags
151
- def timing(stat, ms, opts={})
152
- send_stats stat, ms, :ms, opts
153
- end
154
-
155
- # Reports execution time of the provided block using {#timing}.
156
- #
157
- # @param [String] stat stat name
158
- # @param [Hash] opts the options to create the metric with
159
- # @option opts [Numeric] :sample_rate sample rate, 1 for always
160
- # @option opts [Array<String>] :tags An array of tags
161
- # @yield The operation to be timed
162
- # @see #timing
163
- # @example Report the time (in ms) taken to activate an account
164
- # $statsd.time('account.activate') { @account.activate! }
165
- def time(stat, opts={})
166
- start = Time.now
167
- result = yield
168
- timing(stat, ((Time.now - start) * 1000).round, opts)
169
- result
170
- end
171
- # Sends a value to be tracked as a set to the statsd server.
172
- #
173
- # @param [String] stat stat name.
174
- # @param [Numeric] set value.
175
- # @param [Hash] opts the options to create the metric with
176
- # @option opts [Numeric] :sample_rate sample rate, 1 for always
177
- # @option opts [Array<String>] :tags An array of tags
178
- # @example Record a unique visitory by id:
179
- # $statsd.set('visitors.uniques', User.id)
180
- def set(stat, value, opts={})
181
- send_stats stat, value, :s, opts
23
+ def histogram(stat, value, options = {})
24
+ send_stats stat, value, :h, options
182
25
  end
183
26
 
184
27
  def log(stat, data = {})
185
- data = { environment: environment }.merge data
186
- data.merge! app: namespace, statname: stat
187
- File.open(log_dir.join('application.json.log'), 'a') {|f| f.puts(data.to_json) }
188
- end
189
-
190
- def increment_and_log(stat, data = {})
191
- increment stat
192
- log stat, data
28
+ data = { environment: ::Meter.config.environment, Timestamp: Time.now }.merge data
29
+ data.merge! app: ::Meter.config.namespace, statname: stat
30
+ ::Meter.config.logger.debug { "Logging #{log_file} - #{data}"}
31
+ log_file.open('a') { |f| f.puts(JSON.dump data) }
193
32
  end
194
33
 
195
34
  private
196
35
 
197
- def send_stats(stat, delta, type, opts={})
198
- sample_rate = opts[:sample_rate] || 1
199
- if sample_rate == 1 or rand < sample_rate
200
- # Replace Ruby module scoping with '.' and reserved chars (: | @) with underscores.
201
- stat = stat.to_s.gsub('::', '.').tr(':|@', '_')
202
- rate = "|@#{sample_rate}" unless sample_rate == 1
203
- tags = "|##{opts[:tags].join(",")}" if opts[:tags]
204
- send_to_socket "#{@prefix}#{stat}:#{delta}|#{type}#{rate}#{tags}"
205
- end
36
+ def log_file
37
+ ::Meter.config.log_dir.join('application.json.log')
38
+ end
39
+
40
+ # See https://github.com/DataDog/dogstatsd-ruby/blob/master/lib/statsd.rb
41
+ def send_stats(stat, delta, type, options = {})
42
+ sample_rate = options[:sample_rate] || 1
43
+ return unless sample_rate == 1 or rand < sample_rate
44
+ stat = stat.to_s.gsub('::', '.').tr(':|@', '_')
45
+ rate = "|@#{sample_rate}" unless sample_rate == 1
46
+ tags = "|##{Array(options[:tags]).join(",")}" if options[:tags]
47
+ send_to_socket "#{@prefix}#{stat}:#{delta}|#{type}#{rate}#{tags}"
206
48
  end
207
49
 
208
50
  def send_to_socket(message)
209
- self.class.logger.debug { "Statsd: #{message}" } if self.class.logger
210
- @socket.send(message, 0, @host, @port)
211
- rescue => boom
212
- self.class.logger.error { "boom Statsd: #{boom.class} #{boom}" } if self.class.logger
213
- nil
51
+ ::Meter.config.logger.debug { "UDP #{self.host}:#{self.port} - #{message}" }
52
+ @socket.send message, 0, self.host, self.port
214
53
  end
54
+
215
55
  end
216
56
  end
@@ -0,0 +1,16 @@
1
+ require 'meter/backend'
2
+ require 'ostruct'
3
+
4
+ module Meter
5
+
6
+ # Holds the currently known backends.
7
+ #
8
+ def self.backends
9
+ @backends ||= ::OpenStruct.new(
10
+ datadog: ::Meter::Backend.new('127.0.0.1', 8125),
11
+ counter: ::Meter::Backend.new('127.0.0.1', 3333),
12
+ heka: ::Meter::Backend.new('127.0.0.1', 8128),
13
+ )
14
+ end
15
+
16
+ end
@@ -5,164 +5,59 @@ require 'meter/backend'
5
5
  module Meter
6
6
  class Configuration
7
7
 
8
- attr_accessor :logger, :tags
9
- attr_reader :primary_backend, :secondary_backend, :counter_backend, :meter_backend
8
+ attr_reader :options
10
9
 
11
- def initialize(options={})
12
- @logger = options[:logger] || default_logger
13
-
14
- @primary_backend = Backend.new
15
- @primary_backend.host = options[:primary_host] || default_host
16
- @primary_backend.port = options[:primary_port] || default_port
17
- @primary_backend.namespace = options[:namespace] || default_namespace
18
- @primary_backend.environment = options[:environment] || default_environment
19
-
20
- @secondary_backend = Backend.new
21
- @secondary_backend.host = options[:secondary_host] || ENV['METER_SECONDARY_HOST'] || default_host
22
- @secondary_backend.port = options[:secondary_port] || default_secondary_port
23
- @secondary_backend.namespace = options[:namespace] || default_namespace
24
- @secondary_backend.environment = options[:environment] || default_environment
25
-
26
- @counter_backend = Backend.new
27
- @counter_backend.host = options[:counter_host] || default_host
28
- @counter_backend.port = options[:counter_port] || default_counter_port
29
- @counter_backend.namespace = options[:namespace] || default_namespace
30
- @counter_backend.environment = options[:environment] || default_environment
31
-
32
- @meter_backend = Backend.new
33
- @meter_backend.host = options[:meter_host] || default_host
34
- @meter_backend.port = options[:meter_port] || default_meter_port
35
- @meter_backend.namespace = options[:namespace] || default_namespace
36
- @meter_backend.environment = options[:environment] || default_environment
37
- @meter_backend.log_dir = options[:meter_log_dir] || default_meter_log_dir
38
-
39
- @tags = options[:tags] || {}
10
+ def initialize(options = {})
11
+ @options = options
40
12
  end
41
13
 
42
- def namespace=(new_namespace)
43
- primary_backend.namespace = new_namespace
44
- secondary_backend.namespace = new_namespace
45
- counter_backend.namespace = new_namespace
46
- meter_backend.namespace = new_namespace
47
- end
48
-
49
- def environment=(new_environment)
50
- primary_backend.environment = new_environment
51
- secondary_backend.environment = new_environment
52
- counter_backend.environment = new_environment
53
- meter_backend.environment = new_environment
14
+ def logger
15
+ @logger ||= options[:logger] || default_logger
54
16
  end
17
+ attr_writer :logger
55
18
 
56
19
  def namespace
57
- primary_backend.namespace
58
- end
59
-
60
- def primary_host
61
- primary_backend.host
62
- end
63
-
64
- def primary_port
65
- primary_backend.port
66
- end
67
-
68
- def secondary_host
69
- secondary_backend.host
70
- end
71
-
72
- def secondary_port
73
- secondary_backend.port
74
- end
75
-
76
- def secondary_host
77
- secondary_backend.host
78
- end
79
-
80
- def secondary_port
81
- secondary_backend.port
82
- end
83
-
84
- def primary_host=(new_host)
85
- primary_backend.host = new_host
20
+ @namespace ||= options[:namespace] || default_namespace
86
21
  end
22
+ attr_writer :namespace
87
23
 
88
- def primary_port=(new_port)
89
- primary_backend.port = new_port
24
+ def environment
25
+ @environment ||= options[:environment] || default_environment
90
26
  end
27
+ attr_writer :environment
91
28
 
92
- def secondary_host=(new_host)
93
- secondary_backend.host = new_host
29
+ def log_dir
30
+ @log_dir ||= (::Pathname.new(options[:log_dir]) if options[:log_dir]) || default_log_dir
94
31
  end
95
32
 
96
- def secondary_port=(new_port)
97
- secondary_backend.port = new_port
33
+ def log_dir=(new_dir)
34
+ @log_dir = Pathname.new new_dir
98
35
  end
99
36
 
100
37
  private
101
38
 
102
39
  def default_logger
103
- if defined?(Rails)
104
- Rails.logger
105
- else
106
- Logger.new(STDOUT)
107
- end
108
- end
109
-
110
- def default_host
111
- '127.0.0.1'
112
- end
113
-
114
- def default_port
115
- 8125
116
- end
117
-
118
- def default_secondary_port
119
- 8127
120
- end
121
-
122
- def default_counter_port
123
- 3333
124
- end
125
-
126
- def default_meter_port
127
- 8128
40
+ return ::Rails.logger if defined?(::Rails)
41
+ ::Logger.new STDOUT
128
42
  end
129
43
 
130
44
  def default_namespace
131
- nil
45
+ :meter
132
46
  end
133
47
 
134
48
  def default_environment
135
- return Rails.env if defined?(Rails)
49
+ return ::Rails.env if defined?(::Rails)
136
50
  return ENV['RACK_ENV'] if ENV['RACK_ENV'].to_s != ''
137
51
  return ENV['NODE_CHEF_ENVIRONMENT'] if ENV['NODE_CHEF_ENVIRONMENT'].to_s != ''
138
52
  'unknown'
139
53
  end
140
54
 
141
- def default_meter_log_dir
142
- return Rails.root.join('log') if defined?(Rails)
143
- Pathname.pwd
55
+ def default_log_dir
56
+ return ::Rails.root.join('log') if defined?(::Rails)
57
+ log_subdir = ::Pathname.pwd.join('log')
58
+ return log_subdir if log_subdir.directory?
59
+ Pathname.new '/dev/null'
144
60
  end
145
61
 
146
62
  end
147
63
  end
148
-
149
- module Meter
150
-
151
- # Public: Returns the the configuration instance.
152
- #
153
- def self.config
154
- @config ||= Configuration.new
155
- end
156
-
157
- # Public: Yields the configuration instance.
158
- #
159
- def self.configure(&block)
160
- yield config
161
- end
162
-
163
- # Public: Reset the configuration (useful for testing).
164
- #
165
- def self.reset!
166
- @config = nil
167
- end
168
- end
@@ -0,0 +1,17 @@
1
+ require 'meter/configuration'
2
+
3
+ module Meter
4
+
5
+ # Public: Lazy-loads and returns the the configuration instance.
6
+ #
7
+ def self.config
8
+ @config ||= ::Meter::Configuration.new
9
+ end
10
+
11
+ # Public: Yields the configuration instance.
12
+ #
13
+ def self.configure(&block)
14
+ yield config
15
+ end
16
+
17
+ end
data/lib/meter/version.rb CHANGED
@@ -1,8 +1,8 @@
1
1
  module Meter
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 0
4
- MINOR = 0
5
- TINY = 10
4
+ MINOR = 1
5
+ TINY = 0
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].compact.join('.')
8
8
  end
data/lib/meter.rb CHANGED
@@ -1,59 +1,36 @@
1
- require 'json'
2
- require 'meter/configuration'
1
+ require 'meter/backends'
2
+ require 'meter/configure'
3
3
 
4
- # A generic wrapper for Statsd-like gauges and counters.
5
- #
6
4
  module Meter
7
- extend self
8
5
 
9
- def increment(key, options = {})
6
+ def self.increment(key, options = {})
10
7
  id = options.delete(:id)
11
- primary.increment key, options
12
- if id
13
- counter.increment "#{key}.#{id}", options
14
- end
15
- end
16
-
17
- def count(key, delta, options = {})
18
- id = options.delete(:id)
19
- primary.count key, delta, options
20
- if id
21
- counter.count "#{key}.#{id}", delta, options
22
- end
23
- end
24
-
25
- def gauge(key, value, options = {})
26
- primary.gauge key, value, options
27
- end
8
+ backends.datadog.increment key, options
9
+ backends.counter.increment("#{key}.#{id}", options) if id
28
10
 
29
- def histogram(key, value, options = {})
30
- primary.histogram key, value, options
11
+ rescue => exception
12
+ ::Meter.config.logger.error exception.inspect
31
13
  end
32
14
 
33
- def log(key, data)
34
- meter.log(key, data)
35
- end
15
+ def self.gauge(key, value, options = {})
16
+ backends.datadog.gauge key, value, options
36
17
 
37
- def increment_and_log(key, data)
38
- meter.increment_and_log(key, data)
18
+ rescue => exception
19
+ ::Meter.config.logger.error exception.inspect
39
20
  end
40
21
 
41
- private
22
+ def self.histogram(key, value, options = {})
23
+ backends.datadog.histogram key, value, options
42
24
 
43
- def primary
44
- config.primary_backend
25
+ rescue => exception
26
+ ::Meter.config.logger.error exception.inspect
45
27
  end
46
28
 
47
- def secondary
48
- config.secondary_backend
49
- end
50
-
51
- def counter
52
- config.counter_backend
53
- end
29
+ def self.log(key, data)
30
+ backends.heka.log key, data
54
31
 
55
- def meter
56
- config.meter_backend
32
+ rescue => exception
33
+ ::Meter.config.logger.error exception.inspect
57
34
  end
58
35
 
59
36
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: meter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.10
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - bukowskis
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-11-28 00:00:00.000000000 Z
11
+ date: 2014-12-02 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: trouble
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: rspec
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -52,6 +66,20 @@ dependencies:
52
66
  - - ">="
53
67
  - !ruby/object:Gem::Version
54
68
  version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: timecop
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
55
83
  description: A generic abstraction layer for fire and forgetting measurements via
56
84
  UDP.
57
85
  email:
@@ -61,7 +89,9 @@ extra_rdoc_files: []
61
89
  files:
62
90
  - lib/meter.rb
63
91
  - lib/meter/backend.rb
92
+ - lib/meter/backends.rb
64
93
  - lib/meter/configuration.rb
94
+ - lib/meter/configure.rb
65
95
  - lib/meter/version.rb
66
96
  homepage: https://github.com/bukowskis/meter
67
97
  licenses: