lookout-statsd 0.9.0 → 1.0.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 +5 -13
- data/.gitignore +2 -0
- data/Gemfile +1 -5
- data/README.md +1 -63
- data/lib/statsd.rb +0 -5
- data/spec/statsd_spec.rb +7 -0
- data/statsd.gemspec +3 -7
- metadata +10 -57
- data/bin/statsd +0 -46
- data/config.yml +0 -25
- data/lib/statsd/aggregator.rb +0 -53
- data/lib/statsd/daemon.rb +0 -78
- data/lib/statsd/echos.rb +0 -21
- data/lib/statsd/forwarder.rb +0 -52
- data/lib/statsd/graphite.rb +0 -70
- data/spec/statsd/aggregator_spec.rb +0 -15
- data/spec/statsd/daemon_spec.rb +0 -47
- data/spec/statsd/forwarder_spec.rb +0 -51
- data/stats.rb +0 -24
checksums.yaml
CHANGED
@@ -1,15 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
5
|
-
data.tar.gz: !binary |-
|
6
|
-
NGFmMzljMDhhZTE2MzkzYzZhYTJjZTBhYmFlYjE4MjNjY2I2ZTc2ZQ==
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: c46d6d96b1086ab6165a4254009cfdd9e3dc7dfa
|
4
|
+
data.tar.gz: a3d8a60d8abbc04a730e281edf58015d638eb587
|
7
5
|
SHA512:
|
8
|
-
metadata.gz:
|
9
|
-
|
10
|
-
YWY1MzUzMzVlZGI1OWY4OTBkNTIxODhhNmQ4MDMyZjU3OGYwNTdhZjRjMTZl
|
11
|
-
N2RjZjQxN2RiYzdhN2EwYTEzMDgxZDU0NTM1YzliMjNlYjc3YTc=
|
12
|
-
data.tar.gz: !binary |-
|
13
|
-
YWI2ODM0NzUxODhmNjZkYzAxNWU5NGNjOTRlNmQ2ZmY0MDc5NDUyOGFlNjUw
|
14
|
-
MTE2ZDgwMTgwYThiNzgwYWNmY2RkMzE3OWQ0MTVlZWI1ZWQyYzYwMjMzNDEw
|
15
|
-
ZThiMjRhZDVkZmUwOGJmZTczNDRhY2UxNDIxOWM2OTJiMmRhNDY=
|
6
|
+
metadata.gz: aad201320598de48a5002b876d0738981784e7acb82216b37e30b1f796aa5886f535fa6935b0de71ba89d7ca3dae7014f125752e8ea90f73fc23ff1cea551e51
|
7
|
+
data.tar.gz: 5050801e669c08aa9a12d2d6ac5da237eef48996f5af5edcb1b2799060dc40812a1f1f44d26cac613437cb16f81eddc790826af6186dc0ab4b5df4ba81be1f8d
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,36 +1,11 @@
|
|
1
1
|
# StatsD
|
2
2
|
|
3
|
-
A
|
4
|
-
|
3
|
+
A very simple client to format and send metrics to a StatsD server.
|
5
4
|
|
6
5
|
### Installation
|
7
6
|
|
8
7
|
gem install statsd
|
9
8
|
|
10
|
-
### Configuration
|
11
|
-
|
12
|
-
Create config.yml to your liking.
|
13
|
-
|
14
|
-
Example config.yml
|
15
|
-
---
|
16
|
-
bind: 127.0.0.1
|
17
|
-
port: 8125
|
18
|
-
|
19
|
-
# Flush interval should be your finest retention in seconds
|
20
|
-
flush_interval: 10
|
21
|
-
|
22
|
-
# Graphite
|
23
|
-
graphite_host: localhost
|
24
|
-
graphite_port: 2003
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
### Server
|
29
|
-
Run the server:
|
30
|
-
|
31
|
-
Flush to Graphite (default):
|
32
|
-
statsd -c config.yml
|
33
|
-
|
34
9
|
### Client
|
35
10
|
In your client code:
|
36
11
|
|
@@ -47,48 +22,12 @@ In your client code:
|
|
47
22
|
STATSD.timing('some_job_time', 20) # reporting job that took 20ms
|
48
23
|
STATSD.timing('some_job_time', 20, 0.05) # reporting job that took 20ms with sampling (5% sampling)
|
49
24
|
|
50
|
-
Concepts
|
51
|
-
--------
|
52
|
-
|
53
|
-
* *buckets*
|
54
|
-
Each stat is in it's own "bucket". They are not predefined anywhere. Buckets can be named anything that will translate to Graphite (periods make folders, etc)
|
55
|
-
|
56
|
-
* *values*
|
57
|
-
Each stat will have a value. How it is interpreted depends on modifiers
|
58
|
-
|
59
|
-
* *flush*
|
60
|
-
After the flush interval timeout (default 10 seconds), stats are munged and sent over to Graphite.
|
61
|
-
|
62
|
-
Counting
|
63
|
-
--------
|
64
|
-
|
65
|
-
gorets:1|c
|
66
|
-
|
67
|
-
This is a simple counter. Add 1 to the "gorets" bucket. It stays in memory until the flush interval.
|
68
|
-
|
69
|
-
|
70
|
-
Timing
|
71
|
-
------
|
72
|
-
|
73
|
-
glork:320|ms
|
74
|
-
|
75
|
-
The glork took 320ms to complete this time. StatsD figures out 90th percentile, average (mean), lower and upper bounds for the flush interval.
|
76
|
-
|
77
|
-
Sampling
|
78
|
-
--------
|
79
|
-
|
80
|
-
gorets:1|c|@0.1
|
81
|
-
|
82
|
-
Tells StatsD that this counter is being sent sampled ever 1/10th of the time.
|
83
|
-
|
84
|
-
|
85
25
|
Guts
|
86
26
|
----
|
87
27
|
|
88
28
|
* [UDP][udp]
|
89
29
|
Client libraries use UDP to send information to the StatsD daemon.
|
90
30
|
|
91
|
-
* [EventMachine][eventmachine]
|
92
31
|
* [Graphite][graphite]
|
93
32
|
|
94
33
|
|
@@ -123,4 +62,3 @@ StatsD was inspired (heavily) by the project (of the same name) at Flickr. Here'
|
|
123
62
|
[etsy]: http://www.etsy.com
|
124
63
|
[blog post]: http://codeascraft.etsy.com/2011/02/15/measure-anything-measure-everything/
|
125
64
|
[udp]: http://enwp.org/udp
|
126
|
-
[eventmachine]: http://rubyeventmachine.com/
|
data/lib/statsd.rb
CHANGED
data/spec/statsd_spec.rb
CHANGED
@@ -2,6 +2,13 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe Statsd do
|
4
4
|
describe '#create_instance' do
|
5
|
+
before(:each) do
|
6
|
+
# Make sure prior test hasn't already invoked create_instance
|
7
|
+
if Statsd.class_variable_defined?(:@@instance)
|
8
|
+
Statsd.send(:remove_class_variable, :@@instance)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
5
12
|
after(:each) do
|
6
13
|
Statsd.send(:remove_class_variable, :@@instance)
|
7
14
|
end
|
data/statsd.gemspec
CHANGED
@@ -2,23 +2,19 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = "lookout-statsd"
|
5
|
-
s.version = "0.
|
5
|
+
s.version = "1.0.0"
|
6
6
|
s.platform = Gem::Platform::RUBY
|
7
7
|
|
8
8
|
s.authors = ['R. Tyler Croy', 'Andrew Coldham', 'Ben VandenBos']
|
9
9
|
s.email = ['rtyler.croy@mylookout.com']
|
10
10
|
s.homepage = "https://github.com/lookout/statsd"
|
11
11
|
|
12
|
-
s.summary = "Ruby
|
13
|
-
s.description = "A
|
12
|
+
s.summary = "Ruby statsd client."
|
13
|
+
s.description = "A simple ruby statsd client."
|
14
14
|
|
15
15
|
s.required_rubygems_version = ">= 1.3.6"
|
16
16
|
|
17
|
-
s.add_dependency "eventmachine", ">= 0.12.10", "< 0.15.2"
|
18
|
-
s.add_dependency "erubis", ">= 2.6.6"
|
19
|
-
|
20
17
|
s.files = `git ls-files`.split("\n")
|
21
18
|
s.executables = `git ls-files`.split("\n").map{|f| f =~ /^bin\/(.*)/ ? $1 : nil}.compact
|
22
19
|
s.require_path = 'lib'
|
23
20
|
end
|
24
|
-
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lookout-statsd
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- R. Tyler Croy
|
@@ -10,73 +10,26 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date:
|
14
|
-
dependencies:
|
15
|
-
|
16
|
-
name: eventmachine
|
17
|
-
requirement: !ruby/object:Gem::Requirement
|
18
|
-
requirements:
|
19
|
-
- - ! '>='
|
20
|
-
- !ruby/object:Gem::Version
|
21
|
-
version: 0.12.10
|
22
|
-
- - <
|
23
|
-
- !ruby/object:Gem::Version
|
24
|
-
version: 0.15.2
|
25
|
-
type: :runtime
|
26
|
-
prerelease: false
|
27
|
-
version_requirements: !ruby/object:Gem::Requirement
|
28
|
-
requirements:
|
29
|
-
- - ! '>='
|
30
|
-
- !ruby/object:Gem::Version
|
31
|
-
version: 0.12.10
|
32
|
-
- - <
|
33
|
-
- !ruby/object:Gem::Version
|
34
|
-
version: 0.15.2
|
35
|
-
- !ruby/object:Gem::Dependency
|
36
|
-
name: erubis
|
37
|
-
requirement: !ruby/object:Gem::Requirement
|
38
|
-
requirements:
|
39
|
-
- - ! '>='
|
40
|
-
- !ruby/object:Gem::Version
|
41
|
-
version: 2.6.6
|
42
|
-
type: :runtime
|
43
|
-
prerelease: false
|
44
|
-
version_requirements: !ruby/object:Gem::Requirement
|
45
|
-
requirements:
|
46
|
-
- - ! '>='
|
47
|
-
- !ruby/object:Gem::Version
|
48
|
-
version: 2.6.6
|
49
|
-
description: A network daemon for aggregating statistics (counters and timers), rolling
|
50
|
-
them up, then sending them to graphite.
|
13
|
+
date: 2015-07-09 00:00:00.000000000 Z
|
14
|
+
dependencies: []
|
15
|
+
description: A simple ruby statsd client.
|
51
16
|
email:
|
52
17
|
- rtyler.croy@mylookout.com
|
53
|
-
executables:
|
54
|
-
- statsd
|
18
|
+
executables: []
|
55
19
|
extensions: []
|
56
20
|
extra_rdoc_files: []
|
57
21
|
files:
|
58
|
-
- .gitignore
|
22
|
+
- ".gitignore"
|
59
23
|
- Gemfile
|
60
24
|
- Guardfile
|
61
25
|
- README.md
|
62
26
|
- Rakefile
|
63
|
-
- bin/statsd
|
64
|
-
- config.yml
|
65
27
|
- lib/statsd.rb
|
66
|
-
- lib/statsd/aggregator.rb
|
67
|
-
- lib/statsd/daemon.rb
|
68
|
-
- lib/statsd/echos.rb
|
69
|
-
- lib/statsd/forwarder.rb
|
70
|
-
- lib/statsd/graphite.rb
|
71
28
|
- lib/statsd/test.rb
|
72
29
|
- netcat-example.sh
|
73
30
|
- spec/spec_helper.rb
|
74
|
-
- spec/statsd/aggregator_spec.rb
|
75
|
-
- spec/statsd/daemon_spec.rb
|
76
|
-
- spec/statsd/forwarder_spec.rb
|
77
31
|
- spec/statsd/rails/action_timer_filter_spec.rb
|
78
32
|
- spec/statsd_spec.rb
|
79
|
-
- stats.rb
|
80
33
|
- statsd.gemspec
|
81
34
|
homepage: https://github.com/lookout/statsd
|
82
35
|
licenses: []
|
@@ -87,18 +40,18 @@ require_paths:
|
|
87
40
|
- lib
|
88
41
|
required_ruby_version: !ruby/object:Gem::Requirement
|
89
42
|
requirements:
|
90
|
-
- -
|
43
|
+
- - ">="
|
91
44
|
- !ruby/object:Gem::Version
|
92
45
|
version: '0'
|
93
46
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
94
47
|
requirements:
|
95
|
-
- -
|
48
|
+
- - ">="
|
96
49
|
- !ruby/object:Gem::Version
|
97
50
|
version: 1.3.6
|
98
51
|
requirements: []
|
99
52
|
rubyforge_project:
|
100
|
-
rubygems_version: 2.
|
53
|
+
rubygems_version: 2.4.5
|
101
54
|
signing_key:
|
102
55
|
specification_version: 4
|
103
|
-
summary: Ruby
|
56
|
+
summary: Ruby statsd client.
|
104
57
|
test_files: []
|
data/bin/statsd
DELETED
@@ -1,46 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
|
4
|
-
require 'yaml'
|
5
|
-
require 'optparse'
|
6
|
-
require 'rubygems'
|
7
|
-
require 'pry'
|
8
|
-
|
9
|
-
begin
|
10
|
-
ORIGINAL_ARGV = ARGV.dup
|
11
|
-
options = {}
|
12
|
-
|
13
|
-
parser = OptionParser.new do |opts|
|
14
|
-
opts.banner = "Usage: statsd [options]"
|
15
|
-
|
16
|
-
opts.separator ""
|
17
|
-
opts.separator "Options:"
|
18
|
-
|
19
|
-
opts.on("-cCONFIG", "--config-file CONFIG", "Configuration file") do |x|
|
20
|
-
options[:config_file] = x
|
21
|
-
end
|
22
|
-
|
23
|
-
opts.on("-h", "--help", "Show this message") do
|
24
|
-
puts opts
|
25
|
-
exit
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
parser.parse!
|
30
|
-
|
31
|
-
# dispatch
|
32
|
-
if !options[:config_file]
|
33
|
-
puts parser.help
|
34
|
-
else
|
35
|
-
require 'statsd'
|
36
|
-
Statsd::Daemon.new.run(options)
|
37
|
-
end
|
38
|
-
rescue Exception => e
|
39
|
-
if e.instance_of?(SystemExit)
|
40
|
-
raise
|
41
|
-
else
|
42
|
-
puts 'Uncaught exception'
|
43
|
-
puts e.message
|
44
|
-
puts e.backtrace.join("\n")
|
45
|
-
end
|
46
|
-
end
|
data/config.yml
DELETED
@@ -1,25 +0,0 @@
|
|
1
|
-
---
|
2
|
-
# Accept incoming Statsd UDP messages.
|
3
|
-
bind: 127.0.0.1
|
4
|
-
port: 8125
|
5
|
-
|
6
|
-
# Flush interval should be your finest retention in seconds
|
7
|
-
flush_interval: 5
|
8
|
-
|
9
|
-
# Graphite
|
10
|
-
graphite_host: localhost
|
11
|
-
graphite_port: 2003
|
12
|
-
|
13
|
-
# Forwarding sends copies of incoming UDP statsd messages to other
|
14
|
-
# destinations.
|
15
|
-
# This allows for bundling of many senders into one UDP flow/stream, or
|
16
|
-
# directs stats to redundant carbon caches.
|
17
|
-
#
|
18
|
-
forwarding: true
|
19
|
-
forwarding_socket_lifetime: 10
|
20
|
-
# Example destinations:
|
21
|
-
forwarding_destinations:
|
22
|
-
- hostname: localhost
|
23
|
-
port: 9000
|
24
|
-
- hostname: 127.0.0.1
|
25
|
-
port: 9001
|
data/lib/statsd/aggregator.rb
DELETED
@@ -1,53 +0,0 @@
|
|
1
|
-
module Statsd
|
2
|
-
module Aggregator
|
3
|
-
Version = '0.5.5'
|
4
|
-
|
5
|
-
FLUSH_INTERVAL = 10
|
6
|
-
COUNTERS = {}
|
7
|
-
TIMERS = {}
|
8
|
-
GAUGES = {}
|
9
|
-
|
10
|
-
def post_init
|
11
|
-
puts "statsd server started!"
|
12
|
-
end
|
13
|
-
|
14
|
-
def self.get_and_clear_stats!
|
15
|
-
counters = COUNTERS.dup
|
16
|
-
timers = TIMERS.dup
|
17
|
-
gauges = GAUGES.dup
|
18
|
-
COUNTERS.clear
|
19
|
-
TIMERS.clear
|
20
|
-
GAUGES.clear
|
21
|
-
[counters,timers,gauges]
|
22
|
-
end
|
23
|
-
|
24
|
-
def self.receive_data(msg)
|
25
|
-
msg.split("\n").each do |row|
|
26
|
-
bits = row.split(':')
|
27
|
-
key = bits.shift.gsub(/\s+/, '_').gsub(/\//, '-').gsub(/[^a-zA-Z_\-0-9\.]/, '')
|
28
|
-
bits.each do |record|
|
29
|
-
sample_rate = 1
|
30
|
-
fields = record.split("|")
|
31
|
-
if fields.nil? || fields.count < 2
|
32
|
-
next
|
33
|
-
end
|
34
|
-
if (fields[1].strip == "ms")
|
35
|
-
TIMERS[key] ||= []
|
36
|
-
TIMERS[key].push(fields[0].to_i)
|
37
|
-
elsif (fields[1].strip == "c")
|
38
|
-
if (fields[2] && fields[2].match(/^@([\d\.]+)/))
|
39
|
-
sample_rate = fields[2].match(/^@([\d\.]+)/)[1]
|
40
|
-
end
|
41
|
-
COUNTERS[key] ||= 0
|
42
|
-
COUNTERS[key] += (fields[0].to_i || 1) * (1.0 / sample_rate.to_f)
|
43
|
-
elsif (fields[1].strip == "g")
|
44
|
-
GAUGES[key] ||= (fields[0].to_i || 0)
|
45
|
-
else
|
46
|
-
puts "Invalid statistic #{fields.inspect} received; ignoring"
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
end
|
53
|
-
end
|
data/lib/statsd/daemon.rb
DELETED
@@ -1,78 +0,0 @@
|
|
1
|
-
require 'eventmachine'
|
2
|
-
require 'yaml'
|
3
|
-
require 'erb'
|
4
|
-
|
5
|
-
module Statsd
|
6
|
-
class MessageDispatchDaemon < EventMachine::Connection
|
7
|
-
# Methods to be called when a statsd message comes in.
|
8
|
-
@@receivers = []
|
9
|
-
# Register a Module implementing an EventMachine::Connection -like
|
10
|
-
# interface.
|
11
|
-
#
|
12
|
-
# receive_data methods on all registered modules will get called, but for
|
13
|
-
# any other EM::Connection methods, the last registered module/method will
|
14
|
-
# take precedence.
|
15
|
-
def self.register_receiver(mod)
|
16
|
-
begin
|
17
|
-
method = mod.method('receive_data')
|
18
|
-
@@receivers << method unless @@receivers.include?(method)
|
19
|
-
rescue NameError
|
20
|
-
raise ArgumentError.new("The passed module #{mod} doesn't implement a receive_data method.")
|
21
|
-
end
|
22
|
-
include mod
|
23
|
-
end
|
24
|
-
def self.receivers=(list)
|
25
|
-
raise ArgumentError unless list.is_a?(Array)
|
26
|
-
@@receivers = list
|
27
|
-
end
|
28
|
-
def self.receivers
|
29
|
-
@@receivers
|
30
|
-
end
|
31
|
-
def receive_data(msg)
|
32
|
-
@@receivers.each do |method|
|
33
|
-
method.call(msg)
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
class Daemon
|
38
|
-
def run(options)
|
39
|
-
config = if options[:config] and options[:config].is_a?(Hash)
|
40
|
-
options[:config]
|
41
|
-
elsif options[:config_file] and options[:config_file].is_a?(String)
|
42
|
-
YAML::load(ERB.new(IO.read(options[:config_file])).result)
|
43
|
-
end
|
44
|
-
|
45
|
-
EventMachine::run do
|
46
|
-
## statsd->graphite aggregation
|
47
|
-
if config['graphite_host']
|
48
|
-
MessageDispatchDaemon.register_receiver(Statsd::Aggregator)
|
49
|
-
EventMachine::add_periodic_timer(config['flush_interval']) do
|
50
|
-
counters,timers = Statsd::Aggregator.get_and_clear_stats!
|
51
|
-
EventMachine.connect config['graphite_host'], config['graphite_port'], Statsd::Graphite do |conn|
|
52
|
-
conn.counters = counters
|
53
|
-
conn.timers = timers
|
54
|
-
conn.flush_interval = config['flush_interval']
|
55
|
-
conn.flush_stats
|
56
|
-
end
|
57
|
-
end
|
58
|
-
##
|
59
|
-
|
60
|
-
## statsd->statsd data relay
|
61
|
-
if config['forwarding']
|
62
|
-
Statsd::Forwarder.set_destinations(config['forwarding_destinations'])
|
63
|
-
MessageDispatchDaemon.register_receiver(Statsd::Forwarder)
|
64
|
-
|
65
|
-
Statsd::Forwarder.build_fresh_sockets
|
66
|
-
EventMachine::add_periodic_timer(config['forwarding_socket_lifetime']) do
|
67
|
-
Statsd::Forwarder.build_fresh_sockets
|
68
|
-
end
|
69
|
-
end
|
70
|
-
##
|
71
|
-
|
72
|
-
puts "Going to listen on #{config['bind']}:#{config['port']}"
|
73
|
-
EventMachine::open_datagram_socket(config['bind'], config['port'], MessageDispatchDaemon)
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|
data/lib/statsd/echos.rb
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
#
|
3
|
-
|
4
|
-
require 'rubygems'
|
5
|
-
require 'eventmachine'
|
6
|
-
|
7
|
-
module EchoServer
|
8
|
-
def post_init
|
9
|
-
puts "-- someone connected to the server!"
|
10
|
-
end
|
11
|
-
|
12
|
-
def receive_data data
|
13
|
-
puts data
|
14
|
-
send_data ">>> you sent: #{data}"
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
EventMachine::run {
|
19
|
-
EventMachine::start_server "127.0.0.1", 2003, EchoServer
|
20
|
-
puts 'running dummy graphite echo server on 2003'
|
21
|
-
}
|
data/lib/statsd/forwarder.rb
DELETED
@@ -1,52 +0,0 @@
|
|
1
|
-
require 'socket'
|
2
|
-
|
3
|
-
module Statsd
|
4
|
-
module Forwarder
|
5
|
-
@@sockets = {}
|
6
|
-
@@destinations = []
|
7
|
-
|
8
|
-
def self.sockets; @@sockets; end
|
9
|
-
def self.sockets=(hash)
|
10
|
-
raise ArgumentError unless hash.is_a?(Hash)
|
11
|
-
@@sockets = hash
|
12
|
-
end
|
13
|
-
def self.destinations; @@destinations; end
|
14
|
-
def self.destinations=(list)
|
15
|
-
raise ArgumentError unless list.is_a?(Array)
|
16
|
-
@@destinations = list
|
17
|
-
end
|
18
|
-
|
19
|
-
def self.receive_data(msg)
|
20
|
-
# Broadcast the incoming message to all the forwarding destinations.
|
21
|
-
@@sockets.each do |destination, socket|
|
22
|
-
begin
|
23
|
-
socket.send(msg, 0)
|
24
|
-
rescue SocketError, Errno::ECONNREFUSED => e
|
25
|
-
puts "ERROR: Couldn't send message to #{destination}. Stopping this output.(#{e.inspect})"
|
26
|
-
@@sockets.delete(destination)
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
def self.build_fresh_sockets
|
31
|
-
# Reset destinations to those destinations for which we could
|
32
|
-
# actually get a socket going.
|
33
|
-
@@sockets.clear
|
34
|
-
@@destinations = @@destinations.select do |destination|
|
35
|
-
begin
|
36
|
-
s = UDPSocket.new(Socket::AF_INET)
|
37
|
-
s.connect destination['hostname'], destination['port']
|
38
|
-
@@sockets[destination] = s
|
39
|
-
true
|
40
|
-
rescue SocketError => e
|
41
|
-
puts "ERROR: Couldn't create a socket to #{destination['hostname']}/#{destination['port']}. Pruning destination from Forwarder. (#{e.inspect})"
|
42
|
-
false
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
def self.set_destinations(destinations)
|
47
|
-
raise ArgumentError unless destinations.is_a?(Array)
|
48
|
-
raise ArgumentError unless destinations.map { |d| d.keys }.flatten.uniq.sort == ['hostname', 'port']
|
49
|
-
@@destinations = destinations
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
data/lib/statsd/graphite.rb
DELETED
@@ -1,70 +0,0 @@
|
|
1
|
-
require 'benchmark'
|
2
|
-
require 'eventmachine'
|
3
|
-
|
4
|
-
|
5
|
-
module Statsd
|
6
|
-
class Graphite < EM::Connection
|
7
|
-
attr_accessor :counters, :timers, :flush_interval
|
8
|
-
|
9
|
-
def flush_stats
|
10
|
-
puts "#{Time.now} Flushing #{counters.count} counters and #{timers.count} timers to Graphite."
|
11
|
-
|
12
|
-
stat_string = ''
|
13
|
-
|
14
|
-
ts = Time.now.to_i
|
15
|
-
num_stats = 0
|
16
|
-
|
17
|
-
# store counters
|
18
|
-
counters.each_pair do |key,value|
|
19
|
-
message = "#{key} #{value} #{ts}\n"
|
20
|
-
stat_string += message
|
21
|
-
counters[key] = 0
|
22
|
-
|
23
|
-
num_stats += 1
|
24
|
-
end
|
25
|
-
|
26
|
-
# store timers
|
27
|
-
timers.each_pair do |key, values|
|
28
|
-
if (values.length > 0)
|
29
|
-
pct_threshold = 90
|
30
|
-
values.sort!
|
31
|
-
count = values.count
|
32
|
-
min = values.first
|
33
|
-
max = values.last
|
34
|
-
|
35
|
-
mean = min
|
36
|
-
max_at_threshold = max
|
37
|
-
|
38
|
-
if (count > 1)
|
39
|
-
# average all the timing data
|
40
|
-
sum = values.inject( 0 ) { |s,x| s+x }
|
41
|
-
mean = sum / values.count
|
42
|
-
|
43
|
-
# strip off the top 100-threshold
|
44
|
-
threshold_index = (((100 - pct_threshold) / 100.0) * count).round
|
45
|
-
values = values[0..-threshold_index]
|
46
|
-
max_at_threshold = values.last
|
47
|
-
end
|
48
|
-
|
49
|
-
message = ""
|
50
|
-
message += "#{key}.mean #{mean} #{ts}\n"
|
51
|
-
message += "#{key}.upper #{max} #{ts}\n"
|
52
|
-
message += "#{key}.upper_#{pct_threshold} #{max_at_threshold} #{ts}\n"
|
53
|
-
message += "#{key}.lower #{min} #{ts}\n"
|
54
|
-
message += "#{key}.count #{count} #{ts}\n"
|
55
|
-
stat_string += message
|
56
|
-
|
57
|
-
timers[key] = []
|
58
|
-
|
59
|
-
num_stats += 1
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
stat_string += "statsd.numStats #{num_stats} #{ts}\n"
|
64
|
-
|
65
|
-
# send to graphite
|
66
|
-
send_data stat_string
|
67
|
-
close_connection_after_writing
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
@@ -1,15 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe Statsd::Aggregator do
|
4
|
-
#include Statsd::Aggregator
|
5
|
-
|
6
|
-
describe :receive_data do
|
7
|
-
it 'should not vomit on bad data' do
|
8
|
-
bad_data = "dev.rwygand.app.flexd.exception.no action responded to index. actions: authenticate, authentication_request, authorization, bubble_stacktrace?, decode_credentials, encode_credentials, not_found, and user_name_and_password:1|c"
|
9
|
-
|
10
|
-
expect {
|
11
|
-
Statsd::Aggregator.receive_data(bad_data)
|
12
|
-
}.not_to raise_error
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
data/spec/statsd/daemon_spec.rb
DELETED
@@ -1,47 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe Statsd::Daemon do
|
4
|
-
describe :new do
|
5
|
-
before(:each) do
|
6
|
-
EventMachine.should_receive(:run) { |&block| block.call }
|
7
|
-
EventMachine.should_receive(:open_datagram_socket).and_return true
|
8
|
-
EventMachine.should_receive(:add_periodic_timer).at_least(:once) { |delay, &block| block.call }
|
9
|
-
EventMachine.should_receive(:connect).and_return true
|
10
|
-
Statsd::MessageDispatchDaemon.receivers = []
|
11
|
-
end
|
12
|
-
|
13
|
-
it 'Should extend MessageDispatchDaemon with an Aggregator if "carbon_cache" is configured' do
|
14
|
-
config = {
|
15
|
-
"bind"=>"127.0.0.1",
|
16
|
-
"port"=>8125,
|
17
|
-
"flush_interval"=>5,
|
18
|
-
"graphite_host"=>"localhost",
|
19
|
-
"graphite_port"=>2003,
|
20
|
-
"forwarding"=>false,
|
21
|
-
}
|
22
|
-
|
23
|
-
Statsd::Daemon.new.run(:config => config)
|
24
|
-
Statsd::MessageDispatchDaemon.receivers.should eq([Statsd::Aggregator.method(:receive_data)])
|
25
|
-
end
|
26
|
-
|
27
|
-
it 'Should extend MessageDispatchDaemon with an Aggregator and Forwarder if "carbon_cache" is configured and forwarding is enabled' do
|
28
|
-
config = {
|
29
|
-
"bind"=>"127.0.0.1",
|
30
|
-
"port"=>8125,
|
31
|
-
"flush_interval"=>5,
|
32
|
-
"graphite_host"=>"localhost",
|
33
|
-
"graphite_port"=>2003,
|
34
|
-
"forwarding"=>true,
|
35
|
-
"forwarding_destinations"=>
|
36
|
-
[
|
37
|
-
{"port"=>9000, "hostname"=>"localhost"},
|
38
|
-
{"port"=>9001, "hostname"=>"127.0.0.1"}
|
39
|
-
]
|
40
|
-
}
|
41
|
-
|
42
|
-
Statsd::Daemon.new.run(:config => config)
|
43
|
-
Statsd::MessageDispatchDaemon.receivers.should eq([Statsd::Aggregator.method(:receive_data), Statsd::Forwarder.method(:receive_data)])
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
@@ -1,51 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'timeout'
|
3
|
-
|
4
|
-
describe Statsd::Forwarder do
|
5
|
-
let(:destinations) do
|
6
|
-
[ {'hostname'=>'localhost', 'port'=>9000},
|
7
|
-
{'hostname'=>'127.0.0.1', 'port'=>9001} ]
|
8
|
-
end
|
9
|
-
before(:each) do
|
10
|
-
Statsd::Forwarder.sockets = {}
|
11
|
-
expect { Statsd::Forwarder.set_destinations(destinations) }.not_to raise_error
|
12
|
-
end
|
13
|
-
it 'Should accept a list of destinations to forward to.' do
|
14
|
-
Statsd::Forwarder.destinations.should eq(destinations)
|
15
|
-
end
|
16
|
-
it 'Should create sockets to the destinations with #build_fresh_sockets' do
|
17
|
-
Statsd::Forwarder.sockets.should eq({})
|
18
|
-
Statsd::Forwarder.build_fresh_sockets
|
19
|
-
Statsd::Forwarder.sockets.should be_a_kind_of(Hash)
|
20
|
-
Statsd::Forwarder.sockets.keys.length.should eq(destinations.length)
|
21
|
-
Statsd::Forwarder.sockets.values.each { |socket| socket.should be_a_kind_of(UDPSocket) }
|
22
|
-
end
|
23
|
-
describe 'Replicating incoming messages' do
|
24
|
-
let(:socket_one) do
|
25
|
-
u = UDPSocket.new
|
26
|
-
u.bind('127.0.0.1', 0)
|
27
|
-
#let(:socket_one_port) { u.local_address.ip_port }
|
28
|
-
u
|
29
|
-
end
|
30
|
-
let(:socket_two) do
|
31
|
-
u = UDPSocket.new
|
32
|
-
u.bind('127.0.0.1', 0)
|
33
|
-
u
|
34
|
-
end
|
35
|
-
let(:test_stat) { "app.thing.speed:10|ms\n" }
|
36
|
-
it 'Registers two local receivers, Gets an incoming message, both receivers get it' do
|
37
|
-
Statsd::Forwarder.set_destinations([{'hostname' => '127.0.0.1', 'port' => socket_one.addr[1] },
|
38
|
-
{'hostname' => '127.0.0.1', 'port' => socket_two.addr[1] }])
|
39
|
-
Statsd::Forwarder.build_fresh_sockets
|
40
|
-
Statsd::Forwarder.receive_data(test_stat)
|
41
|
-
|
42
|
-
Timeout.timeout(3) do
|
43
|
-
msg, _, _ = socket_one.recv(4_096)
|
44
|
-
msg.should eq(test_stat)
|
45
|
-
|
46
|
-
msg, _, _ = socket_two.recv(4_096)
|
47
|
-
msg.should eq(test_stat)
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
data/stats.rb
DELETED
@@ -1,24 +0,0 @@
|
|
1
|
-
require 'eventmachine'
|
2
|
-
require 'statsd'
|
3
|
-
|
4
|
-
require 'yaml'
|
5
|
-
require 'erb'
|
6
|
-
|
7
|
-
ROOT = File.expand_path(File.dirname(__FILE__))
|
8
|
-
APP_CONFIG = YAML::load(ERB.new(IO.read(File.join(ROOT,'config.yml'))).result)
|
9
|
-
|
10
|
-
# Start the server
|
11
|
-
EventMachine::run do
|
12
|
-
EventMachine::open_datagram_socket('127.0.0.1', 8125, Statsd::Aggregator)
|
13
|
-
EventMachine::add_periodic_timer(APP_CONFIG['flush_interval']) do
|
14
|
-
counters,timers = Statsd::Aggregator.get_and_clear_stats!
|
15
|
-
|
16
|
-
# Graphite
|
17
|
-
EventMachine.connect APP_CONFIG['graphite_host'], APP_CONFIG['graphite_port'], Statsd::Graphite do |conn|
|
18
|
-
conn.counters = counters
|
19
|
-
conn.timers = timers
|
20
|
-
conn.flush_interval = 10
|
21
|
-
conn.flush_stats
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|