graphite-api 0.0.1.4 → 0.0.2.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.
- data/README.md +115 -39
- data/lib/core-extensions/numeric.rb +20 -0
- data/lib/graphite-api.rb +1 -0
- data/lib/graphite-api/buffer.rb +22 -14
- data/lib/graphite-api/cli.rb +1 -0
- data/lib/graphite-api/client.rb +86 -49
- data/lib/graphite-api/connector.rb +2 -2
- data/lib/graphite-api/logger.rb +5 -0
- data/lib/graphite-api/middleware.rb +33 -24
- data/lib/graphite-api/reactor.rb +1 -1
- data/lib/graphite-api/runner.rb +7 -7
- data/lib/graphite-api/utils.rb +26 -4
- data/lib/graphite-api/version.rb +1 -1
- metadata +11 -5
data/README.md
CHANGED
@@ -2,50 +2,90 @@
|
|
2
2
|
A Ruby API toolkit for [Graphite](http://graphite.wikidot.com/).
|
3
3
|
|
4
4
|
## Description
|
5
|
-
Graphite
|
5
|
+
**GraphiteAPI** is a library written in Ruby that provides two ways for interacting with **Graphite's Carbon Daemon**, the first is for Ruby applications using the **GraphiteAPI::Client**, the second is through **GraphiteAPI-Middleware** daemon, both methods implements Graphite's [plaintext protocol](http://graphite.readthedocs.org/en/1.0/feeding-carbon.html).
|
6
6
|
|
7
|
-
|
7
|
+
## Package Content
|
8
|
+
* Includes a **simple** client for ruby.
|
8
9
|
* Ships with a **GraphiteAPI-Middleware**, which is a lightweight, event-driven, aggregator daemon.
|
9
10
|
* only one dependency (EventMachine).
|
10
11
|
* Utilities like scheduling and caching.
|
11
12
|
|
12
|
-
## Features
|
13
|
-
* Multiple Graphite Servers Support - GraphiteAPI-Middleware supports sending aggregated data to multiple graphite servers, useful for large data centers and backup purposes
|
14
|
-
* Reanimation mode - support cases which the same keys (same timestamps as well) can be received simultaneously and asynchronously from multiple input sources, in these cases GraphiteAPI-Middleware will "reanimate" old records (records that were already sent to Graphite server), and will send the sum of the reanimated record value + the value of the record that was just received to the graphite server; this new summed record should override the key with the new value on Graphite database.
|
13
|
+
## Key Features
|
14
|
+
* **Multiple Graphite Servers Support** - GraphiteAPI-Middleware supports sending aggregated data to multiple graphite servers, useful for large data centers and backup purposes
|
15
|
+
* **Reanimation mode** - support cases which the same keys (same timestamps as well) can be received simultaneously and asynchronously from multiple input sources, in these cases GraphiteAPI-Middleware will "reanimate" old records (records that were already sent to Graphite server), and will send the sum of the reanimated record value + the value of the record that was just received to the graphite server; this new summed record should override the key with the new value on Graphite database.
|
16
|
+
|
17
|
+
## Installation
|
18
|
+
Install stable version
|
19
|
+
|
20
|
+
```
|
21
|
+
gem install graphite-api
|
22
|
+
```
|
23
|
+
|
24
|
+
Install the latest from github
|
25
|
+
|
26
|
+
```
|
27
|
+
git clone git://github.com/kontera-technologies/graphite-api.git
|
28
|
+
cd graphite-api
|
29
|
+
rake install
|
30
|
+
```
|
15
31
|
|
16
32
|
## Client Usage
|
17
33
|
```ruby
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
34
|
+
require 'graphite-api'
|
35
|
+
require 'logger'
|
36
|
+
|
37
|
+
# Turn on the logging ( optional )
|
38
|
+
GraphiteAPI::Logger.logger = ::Logger.new(STDOUT)
|
39
|
+
GraphiteAPI::Logger.logger.level = ::Logger::DEBUG
|
40
|
+
|
41
|
+
# Setup client
|
42
|
+
client = GraphiteAPI::Client.new(
|
43
|
+
:graphite => "graphite.example.com:2003",
|
44
|
+
:prefix => ["example","prefix"], # add example.prefix to each key
|
45
|
+
:slice => 60.seconds # results are aggregated in 60 seconds slices
|
46
|
+
:interval => 60.seconds # send to graphite every 60 seconds
|
47
|
+
)
|
48
|
+
|
49
|
+
# Simple
|
50
|
+
client.webServer.web01.loadAvg 10.7
|
51
|
+
# => example.prefix.webServer.web01.loadAvg 10.7 time.now.to_i
|
52
|
+
|
53
|
+
# "Same Same But Different" ( http://en.wikipedia.org/wiki/Tinglish )
|
54
|
+
client.metrics "webServer.web01.loadAvg" => 10.7
|
55
|
+
# => example.prefix.webServer.web01.loadAvg 10.7 time.now.to_i
|
56
|
+
|
57
|
+
# With event time
|
58
|
+
client.webServer.web01.blaBlaBla(29.1, Time.at(9999999999))
|
59
|
+
# => example.prefix.webServer.web01.blaBlaBla 29.1 9999999999
|
60
|
+
|
61
|
+
# Multiple with event time
|
62
|
+
client.metrics({
|
63
|
+
"webServer.web01.loadAvg" => 10.7,
|
64
|
+
"webServer.web01.memUsage" => 40
|
65
|
+
},Time.at(1326067060))
|
66
|
+
# => example.prefix.webServer.web01.loadAvg 10.7 1326067060
|
67
|
+
# => example.prefix.webServer.web01.memUsage 40 1326067060
|
68
|
+
|
69
|
+
# Timers
|
70
|
+
client.every 10.seconds do |c|
|
71
|
+
c.webServer.web01.uptime `uptime`.split.first.to_i
|
72
|
+
# => example.prefix.webServer.web01.uptime 40 1326067060
|
73
|
+
end
|
74
|
+
|
75
|
+
client.every 52.minutes do |c|
|
76
|
+
c.abcd.efghi.jklmnop.qrst 12
|
77
|
+
# => example.prefix.abcd.efghi.jklmnop.qrst 12 1326067060
|
78
|
+
end
|
79
|
+
|
80
|
+
client.join # wait...
|
44
81
|
```
|
82
|
+
> more examples can be found [here](https://github.com/kontera-technologies/graphite-api/tree/master/examples).
|
83
|
+
|
45
84
|
## GraphiteAPI-Middleware Usage
|
85
|
+
* After installing GraphiteAPI gem, the `graphite-middleware` command should be available.
|
46
86
|
|
47
87
|
```
|
48
|
-
[root@
|
88
|
+
[root@graphite-middleware-node]# graphite-middleware --help
|
49
89
|
|
50
90
|
GraphiteAPI Middleware Server
|
51
91
|
|
@@ -63,21 +103,57 @@ Usage: graphite-middleware [options]
|
|
63
103
|
More Info @ https://github.com/kontera-technologies/graphite-api
|
64
104
|
```
|
65
105
|
|
66
|
-
|
67
|
-
Install stable version
|
106
|
+
* launch **GraphiteAPI-Middleware** daemon
|
68
107
|
|
69
108
|
```
|
70
|
-
|
109
|
+
[root@graphite-middleware-node]# graphite-middleware \
|
110
|
+
--port 2005 \
|
111
|
+
--interval 60 \
|
112
|
+
--log-level debug \
|
113
|
+
--log-file /tmp/graphite-middleware.out \
|
114
|
+
--daemonize \
|
115
|
+
--graphite graphite-server:2003 \
|
116
|
+
--graphite graphite-backup-server:2003
|
71
117
|
```
|
72
118
|
|
73
|
-
|
119
|
+
* Send metrics via **UDP/TCP sockets**
|
74
120
|
|
75
121
|
```
|
76
|
-
|
77
|
-
|
78
|
-
|
122
|
+
[root@graphite-middleware-node] telnet localhost 2005
|
123
|
+
Trying 127.0.0.1...
|
124
|
+
Connected to localhost.
|
125
|
+
Escape character is '^]'.
|
126
|
+
example.middleware.value 10.2 1335008343
|
127
|
+
example.middleware.value2 99 1334929231
|
128
|
+
^C
|
129
|
+
[root@graphite-middleware-node]
|
79
130
|
```
|
80
131
|
|
132
|
+
* Send metrics via **GraphtieAPI client**
|
133
|
+
|
134
|
+
```ruby
|
135
|
+
require 'graphite-api'
|
136
|
+
client = GraphiteAPI::Client.new(:graphite => graphite-middleware-node)
|
137
|
+
client.example.middleware.value 10.2
|
138
|
+
client.example.middleware.value2 27
|
139
|
+
client.bla.bla.value2 27
|
140
|
+
```
|
141
|
+
|
142
|
+
> more examples can be found [here](https://github.com/kontera-technologies/graphite-api/tree/master/examples).
|
143
|
+
|
144
|
+
|
145
|
+
## Recommended Topologies
|
146
|
+
<br/>
|
147
|
+
|
148
|
+
<img src="https://raw.github.com/kontera-technologies/graphite-api/master/examples/graphite-middleware-star.jpg" align="center">
|
149
|
+
|
150
|
+
<hr/>
|
151
|
+
<br/>
|
152
|
+
|
153
|
+
<img src="https://raw.github.com/kontera-technologies/graphite-api/master/examples/graphite-middleware-mesh.jpg" align="center">
|
154
|
+
|
155
|
+
<hr/>
|
156
|
+
|
81
157
|
## TODO:
|
82
158
|
* Documentation
|
83
159
|
* Use Redis
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class Numeric
|
2
|
+
{
|
3
|
+
:year => 365 * 24 * 3600,
|
4
|
+
:month => 30 * 24 * 3600,
|
5
|
+
:week => 7 * 24 * 3600,
|
6
|
+
:day => 24 * 3600,
|
7
|
+
:hour => 3600,
|
8
|
+
:minute => 60,
|
9
|
+
:second => 1
|
10
|
+
}.each do |m,val|
|
11
|
+
respond_to? m or define_method m do
|
12
|
+
self * val
|
13
|
+
end
|
14
|
+
|
15
|
+
"#{m}s".tap do |plural|
|
16
|
+
respond_to? plural or alias_method plural, m
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
data/lib/graphite-api.rb
CHANGED
data/lib/graphite-api/buffer.rb
CHANGED
@@ -23,7 +23,7 @@ module GraphiteAPI
|
|
23
23
|
attr_reader :options,:keys_to_send,:reanimation_mode, :streamer_buff
|
24
24
|
|
25
25
|
CLOSING_STREAM_CHAR = "\n" # end of message - when streaming to buffer obj
|
26
|
-
|
26
|
+
CHARS_TO_IGNORE = ["\r"] # skip these chars when parsing new message
|
27
27
|
FLOATS_ROUND_BY = 2 # round(x) after summing floats
|
28
28
|
VALID_MESSAGE = /^[\w|\.]+ \d+(?:\.|\d)* \d+$/ # how a valid message should look like
|
29
29
|
|
@@ -36,30 +36,37 @@ module GraphiteAPI
|
|
36
36
|
end
|
37
37
|
|
38
38
|
def push hash
|
39
|
-
debug [:buffer,:add,hash]
|
40
|
-
time = Utils
|
39
|
+
debug [:buffer,:add, hash]
|
40
|
+
time = Utils.normalize_time(hash[:time],options[:slice])
|
41
41
|
hash[:metric].each { |k,v| cache_set(time,k,v) }
|
42
42
|
end
|
43
43
|
|
44
|
-
|
44
|
+
alias_method :<<, :push
|
45
45
|
|
46
46
|
def stream message, client_id = nil
|
47
47
|
message.each_char do |char|
|
48
48
|
next if invalid_char? char
|
49
|
-
streamer_buff[client_id]
|
49
|
+
streamer_buff[client_id] += char
|
50
50
|
|
51
51
|
if closed_stream? streamer_buff[client_id]
|
52
|
-
|
52
|
+
if valid streamer_buff[client_id]
|
53
|
+
push build_metric *streamer_buff[client_id].split
|
54
|
+
end
|
53
55
|
streamer_buff.delete client_id
|
54
56
|
end
|
55
|
-
|
56
57
|
end
|
57
58
|
end
|
58
59
|
|
59
|
-
def pull
|
60
|
-
|
61
|
-
keys_to_send.each
|
60
|
+
def pull as = nil
|
61
|
+
Array.new.tap do |data|
|
62
|
+
keys_to_send.each do |time,keys|
|
63
|
+
keys.each do |key|
|
64
|
+
data.push cache_get(time, key, as)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
clear
|
62
68
|
end
|
69
|
+
|
63
70
|
end
|
64
71
|
|
65
72
|
def new_records?
|
@@ -67,21 +74,22 @@ module GraphiteAPI
|
|
67
74
|
end
|
68
75
|
|
69
76
|
private
|
77
|
+
|
70
78
|
def closed_stream? string
|
71
79
|
string[-1,1] == CLOSING_STREAM_CHAR
|
72
80
|
end
|
73
81
|
|
74
82
|
def invalid_char? char
|
75
|
-
|
83
|
+
CHARS_TO_IGNORE.include? char
|
76
84
|
end
|
77
85
|
|
78
86
|
def cache_set time, key, value
|
79
|
-
buffer_cache[time][key] = sum
|
80
|
-
keys_to_send[time].push
|
87
|
+
buffer_cache[time][key] = sum buffer_cache[time][key], value.to_f
|
88
|
+
keys_to_send[time].push key unless keys_to_send[time].include? key
|
81
89
|
end
|
82
90
|
|
83
91
|
def sum float1, float2
|
84
|
-
("%.#{FLOATS_ROUND_BY}f" % (float1 + float2)).to_f # can't use round on 1.8.
|
92
|
+
("%.#{FLOATS_ROUND_BY}f" % (float1 + float2)).to_f # can't use round on 1.8.X
|
85
93
|
end
|
86
94
|
|
87
95
|
def cache_get time, key, as
|
data/lib/graphite-api/cli.rb
CHANGED
data/lib/graphite-api/client.rb
CHANGED
@@ -4,83 +4,120 @@
|
|
4
4
|
# -----------------------------------------------------
|
5
5
|
# Usage
|
6
6
|
#
|
7
|
-
# client = GraphiteAPI::Client.new(
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
7
|
+
# client = GraphiteAPI::Client.new(
|
8
|
+
# :graphite => "graphite.example.com:2003",
|
9
|
+
# :prefix => ["example","prefix"], # add example.prefix to each key
|
10
|
+
# :slice => 60.seconds # results are aggregated in 60 seconds slices
|
11
|
+
# :interval => 60.seconds # send to graphite every 60 seconds
|
12
|
+
# )
|
12
13
|
#
|
13
|
-
# # Simple
|
14
|
-
# client.
|
15
|
-
# # => example.prefix.webServer.web01.loadAvg 10.7 time.now.
|
14
|
+
# # Simple
|
15
|
+
# client.webServer.web01.loadAvg 10.7
|
16
|
+
# # => example.prefix.webServer.web01.loadAvg 10.7 time.now.to_i
|
17
|
+
|
18
|
+
# # "Same Same But Different" ( http://en.wikipedia.org/wiki/Tinglish )
|
19
|
+
# client.metrics "webServer.web01.loadAvg" => 10.7
|
20
|
+
# # => example.prefix.webServer.web01.loadAvg 10.7 time.now.to_i
|
16
21
|
#
|
17
|
-
# # Multiple with time
|
22
|
+
# # Multiple with event time
|
18
23
|
# client.metrics({
|
19
|
-
#
|
20
|
-
#
|
24
|
+
# "webServer.web01.loadAvg" => 10.7,
|
25
|
+
# "webServer.web01.memUsage" => 40
|
21
26
|
# },Time.at(1326067060))
|
22
27
|
# # => example.prefix.webServer.web01.loadAvg 10.7 1326067060
|
23
28
|
# # => example.prefix.webServer.web01.memUsage 40 1326067060
|
24
|
-
#
|
25
|
-
# #
|
26
|
-
#
|
27
|
-
#
|
28
|
-
#
|
29
|
-
#
|
30
|
-
#
|
29
|
+
#
|
30
|
+
# # Timers
|
31
|
+
# client.every 10.seconds do |c|
|
32
|
+
# c.webServer.web01.uptime `uptime`.split.first.to_i
|
33
|
+
# # => example.prefix.webServer.web01.uptime 40 1326067060
|
34
|
+
# end
|
35
|
+
#
|
36
|
+
# client.every 52.minutes do |c|
|
37
|
+
# c.abcd.efghi.jklmnop.qrst 12
|
38
|
+
# # => example.prefix.abcd.efghi.jklmnop.qrst 12 1326067060
|
39
|
+
# end
|
40
|
+
#
|
41
|
+
# client.join # wait...
|
31
42
|
# -----------------------------------------------------
|
43
|
+
|
44
|
+
require File.expand_path '../utils', __FILE__
|
45
|
+
|
32
46
|
module GraphiteAPI
|
33
47
|
class Client
|
34
48
|
include Utils
|
35
49
|
|
36
|
-
|
37
|
-
|
50
|
+
extend Utils::ClassMethods
|
51
|
+
|
38
52
|
def initialize opt
|
39
|
-
@options
|
40
|
-
@buffer
|
41
|
-
@connectors = GraphiteAPI::ConnectorGroup.new
|
42
|
-
|
53
|
+
@options = build_options validate opt.clone
|
54
|
+
@buffer = GraphiteAPI::Buffer.new options
|
55
|
+
@connectors = GraphiteAPI::ConnectorGroup.new options
|
56
|
+
|
57
|
+
every options.fetch :interval do
|
58
|
+
connectors.publish buffer.pull :string if buffer.new_records?
|
59
|
+
end
|
60
|
+
|
43
61
|
end
|
44
62
|
|
45
|
-
|
46
|
-
|
47
|
-
end
|
48
|
-
alias :metrics :add_metrics
|
63
|
+
attr_private_reader :options, :buffer, :connectors
|
64
|
+
delegate :loop, :stop, :to => :Reactor
|
49
65
|
|
50
|
-
def
|
51
|
-
|
66
|
+
def every interval, &block
|
67
|
+
Reactor.every interval do
|
68
|
+
block.call self
|
69
|
+
end
|
52
70
|
end
|
53
71
|
|
54
|
-
def
|
55
|
-
|
72
|
+
def metrics metric, time = Time.now
|
73
|
+
buffer.push :metric => metric, :time => time
|
56
74
|
end
|
57
|
-
|
58
|
-
def
|
59
|
-
|
75
|
+
|
76
|
+
def join
|
77
|
+
sleep while buffer.new_records?
|
60
78
|
end
|
61
79
|
|
62
|
-
def
|
63
|
-
|
80
|
+
def method_missing m, *args, &block
|
81
|
+
Proxy.new( self ).send m, *args, &block
|
64
82
|
end
|
65
|
-
|
66
|
-
protected
|
67
83
|
|
68
|
-
|
69
|
-
Reactor::every(options[:interval]) { send_metrics }
|
70
|
-
end
|
84
|
+
protected
|
71
85
|
|
72
|
-
|
73
|
-
|
86
|
+
class Proxy
|
87
|
+
extend Utils::ClassMethods
|
88
|
+
|
89
|
+
def initialize client
|
90
|
+
@client = client
|
91
|
+
@keys = []
|
92
|
+
end
|
93
|
+
|
94
|
+
attr_private_reader :client, :keys
|
95
|
+
|
96
|
+
def method_missing m, *args, &block
|
97
|
+
keys.push m
|
98
|
+
if keys.size > 10 # too deep
|
99
|
+
super
|
100
|
+
elsif !args.empty?
|
101
|
+
client.metrics(
|
102
|
+
Hash[keys.join("."),args.first],
|
103
|
+
*args[1..-1]
|
104
|
+
)
|
105
|
+
else
|
106
|
+
self
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
74
110
|
end
|
75
|
-
|
76
|
-
def validate
|
77
|
-
|
78
|
-
|
111
|
+
|
112
|
+
def validate options
|
113
|
+
options.tap do |opt|
|
114
|
+
raise ArgumentError.new ":graphite must be specified" if opt[:graphite].nil?
|
115
|
+
end
|
79
116
|
end
|
80
117
|
|
81
118
|
def build_options opt
|
82
119
|
default_options.tap do |options_hash|
|
83
|
-
options_hash[:backends]
|
120
|
+
options_hash[:backends].push expand_host opt.delete :graphite
|
84
121
|
options_hash.merge! opt
|
85
122
|
options_hash.freeze
|
86
123
|
end
|
@@ -15,7 +15,7 @@ module GraphiteAPI
|
|
15
15
|
|
16
16
|
attr_reader :options, :host, :port
|
17
17
|
|
18
|
-
def initialize
|
18
|
+
def initialize host, port
|
19
19
|
@host = host
|
20
20
|
@port = port
|
21
21
|
end
|
@@ -38,7 +38,7 @@ module GraphiteAPI
|
|
38
38
|
|
39
39
|
def socket
|
40
40
|
if @socket.nil? || @socket.closed?
|
41
|
-
@socket = ::TCPSocket.new
|
41
|
+
@socket = ::TCPSocket.new host, port
|
42
42
|
end
|
43
43
|
@socket
|
44
44
|
end
|
data/lib/graphite-api/logger.rb
CHANGED
@@ -5,6 +5,11 @@
|
|
5
5
|
# Graphite::Logger.logger = ::Logger.new(STDOUT)
|
6
6
|
# Graphite::Logger.info "shuki tuki"
|
7
7
|
# Graphite::Logger.debug "hihi"
|
8
|
+
#
|
9
|
+
# Or:
|
10
|
+
# Graphite::Logger.init :level => :debug
|
11
|
+
# Graphite::Logger.info "shuki tuki"
|
12
|
+
# Graphite::Logger.debug "hihi"
|
8
13
|
# -----------------------------------------------------
|
9
14
|
require 'logger'
|
10
15
|
|
@@ -20,51 +20,60 @@
|
|
20
20
|
require 'rubygems'
|
21
21
|
require 'eventmachine'
|
22
22
|
require 'socket'
|
23
|
+
require File.expand_path '../utils', __FILE__
|
23
24
|
|
24
25
|
module GraphiteAPI
|
25
26
|
class Middleware < EventMachine::Connection
|
26
|
-
include GraphiteAPI::Utils
|
27
|
-
|
28
|
-
attr_reader :logger,:buffer,:client_id
|
29
27
|
|
28
|
+
include Utils
|
29
|
+
extend Utils::ClassMethods
|
30
|
+
|
30
31
|
def initialize buffer
|
31
|
-
@buffer = buffer
|
32
|
-
super
|
32
|
+
@buffer = buffer and super
|
33
33
|
end
|
34
|
-
|
34
|
+
|
35
|
+
attr_private_reader :buffer,:client_id
|
36
|
+
|
35
37
|
def post_init
|
36
|
-
@client_id =
|
37
|
-
debug [:middleware
|
38
|
+
@client_id = peername
|
39
|
+
debug [:middleware, :connecting, client_id]
|
38
40
|
end
|
39
41
|
|
40
42
|
def receive_data data
|
41
|
-
debug [:middleware
|
43
|
+
debug [:middleware, :message, client_id, data]
|
42
44
|
buffer.stream data, client_id
|
43
45
|
end
|
44
46
|
|
45
47
|
def unbind
|
46
|
-
debug [:middleware
|
48
|
+
debug [:middleware, :disconnecting, client_id]
|
47
49
|
end
|
48
|
-
|
50
|
+
|
51
|
+
def peername
|
52
|
+
port, *ip = get_peername[2,6].unpack "nC4"
|
53
|
+
[ip.join("."),port].join ":"
|
54
|
+
end
|
55
|
+
|
56
|
+
private :peername
|
57
|
+
|
49
58
|
def self.start options
|
50
59
|
EventMachine.run do
|
51
|
-
buffer = GraphiteAPI::Buffer.new(options)
|
52
|
-
connectors = GraphiteAPI::ConnectorGroup.new(options)
|
53
|
-
|
54
|
-
# Starting server
|
55
|
-
EventMachine.start_server('0.0.0.0',options[:port],self,buffer)
|
56
60
|
GraphiteAPI::Logger.info "Server running on port #{options[:port]}"
|
57
61
|
|
58
|
-
|
59
|
-
GraphiteAPI::
|
60
|
-
connectors.publish buffer.pull(:string) if buffer.new_records?
|
61
|
-
end # every
|
62
|
+
buffer = GraphiteAPI::Buffer.new options
|
63
|
+
group = GraphiteAPI::ConnectorGroup.new options
|
62
64
|
|
63
|
-
|
64
|
-
|
65
|
+
# Starting server
|
66
|
+
[:start_server, :open_datagram_socket].each do |m|
|
67
|
+
EventMachine.send(m,'0.0.0.0',options[:port],self,buffer)
|
65
68
|
end
|
66
|
-
|
67
|
-
|
69
|
+
|
70
|
+
# Send metrics to graphite every X seconds
|
71
|
+
proc { group.publish buffer.pull :string if buffer.new_records? }.tap do |block|
|
72
|
+
GraphiteAPI::Reactor.every options[:interval], &block
|
73
|
+
GraphiteAPI::Reactor.add_shutdown_hook &block
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
68
77
|
end # start
|
69
78
|
end # Middleware
|
70
79
|
end # GraphiteAPI
|
data/lib/graphite-api/reactor.rb
CHANGED
data/lib/graphite-api/runner.rb
CHANGED
@@ -4,29 +4,29 @@ module GraphiteAPI
|
|
4
4
|
class Runner
|
5
5
|
include Utils
|
6
6
|
|
7
|
-
def initialize
|
8
|
-
|
7
|
+
def initialize argv
|
8
|
+
CLI.parse argv, options
|
9
9
|
validate_options
|
10
10
|
end
|
11
11
|
|
12
12
|
def run
|
13
|
+
Logger.init Hash[[:std,:level].zip options.values_at(:log_file, :log_level) ]
|
13
14
|
options[:daemonize] ? daemonize(options[:pid]) { run! } : run!
|
14
15
|
end
|
15
16
|
|
16
17
|
private
|
17
18
|
|
18
19
|
def run!
|
19
|
-
GraphiteAPI::Logger.init(:std => options[:log_file], :level => options[:log_level])
|
20
20
|
begin
|
21
|
-
Middleware
|
21
|
+
Middleware.start options
|
22
22
|
rescue Interrupt
|
23
|
-
|
24
|
-
|
23
|
+
Logger.info "Shutting down..."
|
24
|
+
Reactor.stop
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
28
|
def options
|
29
|
-
@options ||= Utils
|
29
|
+
@options ||= Utils.default_options
|
30
30
|
end
|
31
31
|
|
32
32
|
def validate_options
|
data/lib/graphite-api/utils.rb
CHANGED
@@ -1,5 +1,26 @@
|
|
1
1
|
module GraphiteAPI
|
2
2
|
module Utils
|
3
|
+
module ClassMethods
|
4
|
+
def attr_private_reader *args
|
5
|
+
args.each { |o| attr_reader o or private o }
|
6
|
+
end
|
7
|
+
|
8
|
+
def delegate *sources, options
|
9
|
+
instance_eval do
|
10
|
+
options.fetch(:to).tap do |target|
|
11
|
+
sources.each do |source|
|
12
|
+
define_method source do |*args, &block|
|
13
|
+
if target.is_a? Symbol
|
14
|
+
eval String target
|
15
|
+
else
|
16
|
+
target
|
17
|
+
end.send source,*args, &block
|
18
|
+
end # define
|
19
|
+
end # sources
|
20
|
+
end # options
|
21
|
+
end # instance_eval
|
22
|
+
end # def delegate
|
23
|
+
end # ClassMethods
|
3
24
|
|
4
25
|
[:info,:error,:warn,:debug].each do |m|
|
5
26
|
define_method(m) do |*args,&block|
|
@@ -9,7 +30,7 @@ module GraphiteAPI
|
|
9
30
|
|
10
31
|
module_function
|
11
32
|
|
12
|
-
def normalize_time
|
33
|
+
def normalize_time time, slice = 60
|
13
34
|
((time || Time.now).to_i / slice * slice).to_i
|
14
35
|
end
|
15
36
|
|
@@ -30,12 +51,13 @@ module GraphiteAPI
|
|
30
51
|
:prefix => [],
|
31
52
|
:interval => 60,
|
32
53
|
:slice => 60,
|
33
|
-
:pid => "/
|
54
|
+
:pid => "/tmp/graphite-middleware.pid"
|
34
55
|
}
|
35
56
|
end
|
36
57
|
|
37
58
|
def daemonize pid
|
38
59
|
block_given? or raise ArgumentError.new "the block is missing..."
|
60
|
+
|
39
61
|
fork do
|
40
62
|
Process.setsid
|
41
63
|
exit if fork
|
@@ -43,10 +65,10 @@ module GraphiteAPI
|
|
43
65
|
STDIN.reopen('/dev/null')
|
44
66
|
STDOUT.reopen('/dev/null','a')
|
45
67
|
STDERR.reopen('/dev/null','a')
|
46
|
-
File.open(pid,'w') { |f| f.write(Process.pid) } rescue
|
68
|
+
File.open(pid,'w') { |f| f.write(Process.pid) } rescue nil
|
47
69
|
yield
|
48
70
|
end
|
49
71
|
end
|
50
|
-
|
72
|
+
|
51
73
|
end
|
52
74
|
end
|
data/lib/graphite-api/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: graphite-api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-11-25 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: eventmachine
|
16
|
-
requirement:
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,7 +21,12 @@ dependencies:
|
|
21
21
|
version: 0.3.3
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements:
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 0.3.3
|
25
30
|
description: Graphite API - A Simple ruby client, aggregator daemon and API tools
|
26
31
|
email: eran@kontera.com
|
27
32
|
executables:
|
@@ -32,6 +37,7 @@ files:
|
|
32
37
|
- README.md
|
33
38
|
- Rakefile
|
34
39
|
- bin/graphite-middleware
|
40
|
+
- lib/core-extensions/numeric.rb
|
35
41
|
- lib/graphite-api/buffer.rb
|
36
42
|
- lib/graphite-api/cli.rb
|
37
43
|
- lib/graphite-api/client.rb
|
@@ -66,7 +72,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
66
72
|
version: '0'
|
67
73
|
requirements: []
|
68
74
|
rubyforge_project: graphite-api
|
69
|
-
rubygems_version: 1.8.
|
75
|
+
rubygems_version: 1.8.24
|
70
76
|
signing_key:
|
71
77
|
specification_version: 3
|
72
78
|
summary: Graphite Ruby Client
|