graphite-api 0.0.1.4 → 0.0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|