graphite-api 0.0.3.beta3 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +140 -63
- data/Rakefile +4 -0
- data/lib/graphite-api.rb +0 -1
- data/lib/graphite-api/cache/memory.rb +5 -5
- data/lib/graphite-api/client.rb +0 -3
- data/lib/graphite-api/connector.rb +1 -2
- data/lib/{core-extensions → graphite-api/core_ext}/numeric.rb +0 -0
- data/lib/graphite-api/safe_buffer.rb +7 -7
- data/lib/graphite-api/utils.rb +5 -1
- data/lib/graphite-api/version.rb +1 -1
- data/tasks/build.rake +2 -1
- data/tasks/tests.rake +33 -1
- metadata +6 -7
- data/lib/graphite-api/buffer.rb +0 -137
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# GraphiteAPI
|
1
|
+
# GraphiteAPI
|
2
2
|
A Ruby API toolkit for [Graphite](http://graphite.wikidot.com/).
|
3
3
|
|
4
4
|
## Description
|
@@ -7,12 +7,27 @@ A Ruby API toolkit for [Graphite](http://graphite.wikidot.com/).
|
|
7
7
|
## Package Content
|
8
8
|
* Includes a **simple** client for ruby.
|
9
9
|
* Ships with a **GraphiteAPI-Middleware**, which is a lightweight, event-driven, aggregator daemon.
|
10
|
-
*
|
10
|
+
* Only one gem dependency ( EventMachine ).
|
11
11
|
* Utilities like scheduling and caching.
|
12
12
|
|
13
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
|
14
|
+
* **Multiple Graphite Servers Support** - GraphiteAPI-Middleware supports sending aggregated data to multiple graphite servers, in a multiplex fashion, useful for large data centers and backup purposes
|
15
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
|
+
* **non-blocking I/O** ( EventMachine aware ).
|
17
|
+
* **Thread-Safe** client.
|
18
|
+
|
19
|
+
## Status
|
20
|
+
<table>
|
21
|
+
<tr>
|
22
|
+
<td> Version </td>
|
23
|
+
<td><a href="https://rubygems.org/gems/graphite-api"><img src=https://fury-badge.herokuapp.com/rb/graphite-api.png></a> </td>
|
24
|
+
</tr>
|
25
|
+
<tr>
|
26
|
+
<td> Build </td>
|
27
|
+
<td><a href="https://travis-ci.org/kontera-technologies/graphite-api"><img src=https://travis-ci.org/kontera-technologies/graphite-api.png?branch=master></a>
|
28
|
+
</td>
|
29
|
+
</tr>
|
30
|
+
</table>
|
16
31
|
|
17
32
|
## Installation
|
18
33
|
Install stable version
|
@@ -30,55 +45,125 @@ rake install
|
|
30
45
|
```
|
31
46
|
|
32
47
|
## Client Usage
|
48
|
+
Creating a new client instance
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
require 'graphite-api'
|
52
|
+
|
53
|
+
GraphiteAPI::Client.new(
|
54
|
+
graphite: "graphite.example.com:2003", # not optional
|
55
|
+
prefix: ["example","prefix"], # add example.prefix to each key
|
56
|
+
slice: 60 # results are aggregated in 60 seconds slices
|
57
|
+
interval: 60 # send to graphite every 60 seconds
|
58
|
+
cache: 4 * 60 * 60 # set the max age in seconds for records reanimation
|
59
|
+
)
|
60
|
+
```
|
61
|
+
|
62
|
+
Adding simple metrics
|
33
63
|
```ruby
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
64
|
+
require 'graphite-api'
|
65
|
+
|
66
|
+
client = GraphiteAPI::Client.new( graphite: 'graphite:2003' )
|
67
|
+
|
68
|
+
client.metrics "webServer.web01.loadAvg" => 10.7
|
69
|
+
# => webServer.web01.loadAvg 10.7 time.now.to_i
|
70
|
+
|
71
|
+
client.metrics(
|
72
|
+
"webServer.web01.loadAvg" => 10.7,
|
73
|
+
"webServer.web01.memUsage" => 40
|
74
|
+
)
|
75
|
+
# => webServer.web01.loadAvg 10.7 1326067060
|
76
|
+
# => webServer.web01.memUsage 40 1326067060
|
77
|
+
```
|
78
|
+
|
79
|
+
Adding metrics with timestamp
|
80
|
+
```ruby
|
81
|
+
require 'graphite-api'
|
82
|
+
|
83
|
+
client = GraphiteAPI::Client.new( graphite: 'graphite:2003' )
|
84
|
+
|
85
|
+
client.metrics({
|
86
|
+
"webServer.web01.loadAvg" => 10.7,
|
87
|
+
"webServer.web01.memUsage" => 40
|
88
|
+
},Time.at(1326067060))
|
89
|
+
# => webServer.web01.loadAvg 10.7 1326067060
|
90
|
+
# => webServer.web01.memUsage 40 1326067060
|
91
|
+
```
|
92
|
+
|
93
|
+
Some DSL sweetness
|
94
|
+
```ruby
|
95
|
+
require 'graphite-api'
|
96
|
+
|
97
|
+
client = GraphiteAPI::Client.new( graphite: 'graphite:2003' )
|
98
|
+
|
99
|
+
client.webServer.web01.loadAvg 10.7
|
100
|
+
# => webServer.web01.loadAvg 10.7 time.now.to_i
|
101
|
+
|
102
|
+
client.webServer.web01.blaBlaBla(29.1, Time.at(9999999999))
|
103
|
+
# => webServer.web01.blaBlaBla 29.1 9999999999
|
104
|
+
```
|
105
|
+
|
106
|
+
Built-in timers support
|
107
|
+
```ruby
|
108
|
+
require 'graphite-api'
|
109
|
+
|
110
|
+
client = GraphiteAPI::Client.new( graphite: 'graphite:2003' )
|
111
|
+
|
112
|
+
# lets send the metric every 120 seconds
|
113
|
+
client.every(120) do |c|
|
114
|
+
c.webServer.web01.uptime `uptime`.split.first.to_i
|
115
|
+
end
|
116
|
+
```
|
117
|
+
|
118
|
+
Built-in extension for time declarations stuff, like 2.minutes, 3.hours etc...
|
119
|
+
```ruby
|
120
|
+
require 'graphite-api'
|
121
|
+
require 'graphite-api/core_ext/numeric'
|
122
|
+
|
123
|
+
client = GraphiteAPI::Client.new( graphite: 'graphite:2003' )
|
124
|
+
|
125
|
+
client.every 10.seconds do |c|
|
126
|
+
c.webServer.web01.uptime `uptime`.split.first.to_i
|
127
|
+
end
|
128
|
+
|
129
|
+
client.every 52.minutes do |c|
|
130
|
+
c.just.fake 12
|
131
|
+
end
|
132
|
+
```
|
133
|
+
|
134
|
+
Make your own custom metrics daemons, using `client#join`
|
135
|
+
```ruby
|
136
|
+
require 'graphite-api'
|
137
|
+
require 'graphite-api/core_ext/numeric'
|
138
|
+
|
139
|
+
client = GraphiteAPI::Client.new( graphite: 'graphite:2003' )
|
140
|
+
|
141
|
+
client.every 26.minutes do |c|
|
142
|
+
c.webServer.shuki.stats 10
|
143
|
+
c.webServer.shuki.x 97
|
144
|
+
c.webServer.shuki.y 121
|
145
|
+
end
|
146
|
+
|
147
|
+
client.join # wait for ever...
|
148
|
+
```
|
149
|
+
|
150
|
+
Logging support
|
151
|
+
|
152
|
+
```ruby
|
153
|
+
# Provide an external logger
|
154
|
+
require 'graphite-api'
|
155
|
+
require 'logger'
|
156
|
+
|
157
|
+
GraphiteAPI::Logger.logger = ::Logger.new(STDOUT)
|
158
|
+
GraphiteAPI::Logger.logger.level = ::Logger::DEBUG
|
159
|
+
|
160
|
+
# Or use the built-in one
|
161
|
+
GraphiteAPI::Logger.init(
|
162
|
+
:level => :debug,
|
163
|
+
:std => 'logger.out' # or STDOUT | STDERR
|
164
|
+
)
|
165
|
+
```
|
166
|
+
|
82
167
|
> more examples can be found [here](https://github.com/kontera-technologies/graphite-api/tree/master/examples).
|
83
168
|
|
84
169
|
## GraphiteAPI-Middleware Usage
|
@@ -142,21 +227,13 @@ client.bla.bla.value2 27
|
|
142
227
|
> more examples can be found [here](https://github.com/kontera-technologies/graphite-api/tree/master/examples).
|
143
228
|
|
144
229
|
|
145
|
-
##
|
230
|
+
## Example Setup
|
146
231
|
<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/>
|
232
|
+
<img src="https://raw.github.com/kontera-technologies/graphite-api/master/examples/middleware_t1.png" align="center">
|
156
233
|
|
157
234
|
## TODO:
|
158
|
-
*
|
159
|
-
* Use Redis
|
235
|
+
* Better documentation
|
236
|
+
* Use Redis for caching
|
160
237
|
* Multiple backends via client as well
|
161
238
|
|
162
239
|
## Bugs
|
data/Rakefile
CHANGED
data/lib/graphite-api.rb
CHANGED
@@ -8,11 +8,11 @@ module GraphiteAPI
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def get time, key
|
11
|
-
cache[time][key]
|
11
|
+
cache[time.to_i][key]
|
12
12
|
end
|
13
13
|
|
14
14
|
def set time, key, value
|
15
|
-
cache[time][key] = value.to_f
|
15
|
+
cache[time.to_i][key] = value.to_f
|
16
16
|
end
|
17
17
|
|
18
18
|
def incr time, key, value
|
@@ -22,12 +22,12 @@ module GraphiteAPI
|
|
22
22
|
private
|
23
23
|
|
24
24
|
def cache
|
25
|
-
@cache ||=
|
25
|
+
@cache ||= nested_zero_hash
|
26
26
|
end
|
27
27
|
|
28
|
-
def clean
|
28
|
+
def clean max_age
|
29
29
|
debug [:MemoryCache, :before_clean, cache]
|
30
|
-
cache.delete_if {|t,k| Time.now.to_i - t >
|
30
|
+
cache.delete_if {|t,k| Time.now.to_i - t > max_age }
|
31
31
|
debug [:MemoryCache, :after_clean, cache]
|
32
32
|
end
|
33
33
|
|
data/lib/graphite-api/client.rb
CHANGED
@@ -11,15 +11,12 @@
|
|
11
11
|
# :interval => 60.seconds # send to graphite every 60 seconds
|
12
12
|
# )
|
13
13
|
#
|
14
|
-
# # Simple
|
15
14
|
# client.webServer.web01.loadAvg 10.7
|
16
15
|
# # => example.prefix.webServer.web01.loadAvg 10.7 time.now.to_i
|
17
16
|
|
18
|
-
# # "Same Same But Different" ( http://en.wikipedia.org/wiki/Tinglish )
|
19
17
|
# client.metrics "webServer.web01.loadAvg" => 10.7
|
20
18
|
# # => example.prefix.webServer.web01.loadAvg 10.7 time.now.to_i
|
21
19
|
#
|
22
|
-
# # Multiple with event time
|
23
20
|
# client.metrics({
|
24
21
|
# "webServer.web01.loadAvg" => 10.7,
|
25
22
|
# "webServer.web01.memUsage" => 40
|
@@ -23,8 +23,7 @@ module GraphiteAPI
|
|
23
23
|
|
24
24
|
def puts message
|
25
25
|
begin
|
26
|
-
|
27
|
-
return
|
26
|
+
debug [:connector,:puts,[host,port].join(":"),message]
|
28
27
|
socket.puts message + "\n"
|
29
28
|
rescue Errno::EPIPE, Errno::EINVAL
|
30
29
|
@socket = nil
|
File without changes
|
@@ -16,7 +16,6 @@
|
|
16
16
|
# ["mem.usage", 190.0, 1326842520]
|
17
17
|
# ["shuki.tuki", 999.0, 1326842520]
|
18
18
|
# -----------------------------------------------------
|
19
|
-
|
20
19
|
require 'thread'
|
21
20
|
require 'set'
|
22
21
|
|
@@ -48,7 +47,7 @@ module GraphiteAPI
|
|
48
47
|
streamer[client_id] += char
|
49
48
|
|
50
49
|
if closed_stream? streamer[client_id]
|
51
|
-
if valid_stream_message streamer[client_id]
|
50
|
+
if valid_stream_message? streamer[client_id]
|
52
51
|
push stream_message_to_obj streamer[client_id]
|
53
52
|
end
|
54
53
|
streamer.delete client_id
|
@@ -62,16 +61,16 @@ module GraphiteAPI
|
|
62
61
|
debug [:buffer,:add, obj]
|
63
62
|
queue.push obj
|
64
63
|
nil
|
65
|
-
end
|
64
|
+
end
|
66
65
|
|
67
66
|
alias_method :<<, :push
|
68
67
|
|
69
68
|
def pull format = nil
|
70
|
-
data =
|
69
|
+
data = nested_zero_hash
|
71
70
|
|
72
71
|
counter = 0
|
73
72
|
while new_records?
|
74
|
-
break if ( counter += 1 ) >
|
73
|
+
break if ( counter += 1 ) > 1_000_000 # TODO: fix this
|
75
74
|
hash = queue.pop
|
76
75
|
time = normalize_time(hash[:time],options[:slice])
|
77
76
|
hash[:metric].each { |k,v| data[time][k] += v.to_f }
|
@@ -91,7 +90,8 @@ module GraphiteAPI
|
|
91
90
|
end
|
92
91
|
|
93
92
|
def inspect
|
94
|
-
"#<GraphiteAPI::SafeBuffer
|
93
|
+
"#<GraphiteAPI::SafeBuffer:%s @quque#size=%s @streamer=%s>" %
|
94
|
+
[object_id,queue.size,streamer]
|
95
95
|
end
|
96
96
|
|
97
97
|
private
|
@@ -109,7 +109,7 @@ module GraphiteAPI
|
|
109
109
|
string[-1,1] == END_OF_STREAM
|
110
110
|
end
|
111
111
|
|
112
|
-
def valid_stream_message message
|
112
|
+
def valid_stream_message? message
|
113
113
|
message =~ VALID_MESSAGE
|
114
114
|
end
|
115
115
|
|
data/lib/graphite-api/utils.rb
CHANGED
data/lib/graphite-api/version.rb
CHANGED
data/tasks/build.rake
CHANGED
@@ -19,7 +19,8 @@ GraphiteAPI::GemSpec = Gem::Specification.new do |s|
|
|
19
19
|
s.add_dependency 'eventmachine','>= 0.3.3'
|
20
20
|
end
|
21
21
|
|
22
|
-
task :gem => [:clobber_package]
|
22
|
+
task :gem => [:test,:clobber_package]
|
23
|
+
|
23
24
|
Gem::PackageTask.new(GraphiteAPI::GemSpec) do |p|
|
24
25
|
p.gem_spec = GraphiteAPI::GemSpec
|
25
26
|
end
|
data/tasks/tests.rake
CHANGED
@@ -1,10 +1,42 @@
|
|
1
1
|
require "rake/testtask"
|
2
2
|
|
3
|
-
task(:test) { ENV['with_coverage'] = "true" }
|
3
|
+
task(:test => :functional) { ENV['with_coverage'] = "true" }
|
4
4
|
|
5
5
|
Rake::TestTask.new(:test) do |t|
|
6
6
|
t.libs << "tests"
|
7
7
|
t.pattern = "tests/**/*_test.rb"
|
8
8
|
end
|
9
9
|
|
10
|
+
|
11
|
+
task :functional do
|
12
|
+
some_failed = false
|
13
|
+
|
14
|
+
next unless ENV['SKIP_FUNC'].nil?
|
15
|
+
|
16
|
+
unless RUBY_COPYRIGHT.end_with?("Matsumoto")
|
17
|
+
puts("Functional tests are enabled only on MRI...")
|
18
|
+
next
|
19
|
+
end
|
20
|
+
|
21
|
+
message "Executing GraphiteAPI Functional Tests"
|
22
|
+
message "( You can skip them by passing SKIP_FUNC=true )"
|
23
|
+
|
24
|
+
Dir[File.expand_path("../../tests/functional/*",__FILE__)].each do |file|
|
25
|
+
next unless file.end_with?(".rb")
|
26
|
+
now = Time.now.to_i
|
27
|
+
name = File.basename(file)
|
28
|
+
message "Executing #{name}"
|
29
|
+
Process.waitpid(Process.spawn("ruby", File.expand_path(file)))
|
30
|
+
took = "took #{Time.now.to_i - now} seconds"
|
31
|
+
if $?.success?
|
32
|
+
message "[PASS] #{name}, #{took}"
|
33
|
+
else
|
34
|
+
message "[FAIL] #{name}, #{took}"
|
35
|
+
some_failed = true
|
36
|
+
end
|
37
|
+
end
|
38
|
+
message "Done Executing GraphiteAPI Functional Tests"
|
39
|
+
abort "Some functional tests failed..." if some_failed
|
40
|
+
end
|
41
|
+
|
10
42
|
task :default => :test
|
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: graphite-api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.3
|
5
|
-
prerelease:
|
4
|
+
version: 0.0.3
|
5
|
+
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Eran Barak Levi
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-03-
|
12
|
+
date: 2013-03-07 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: eventmachine
|
@@ -37,14 +37,13 @@ files:
|
|
37
37
|
- README.md
|
38
38
|
- Rakefile
|
39
39
|
- bin/graphite-middleware
|
40
|
-
- lib/core-extensions/numeric.rb
|
41
|
-
- lib/graphite-api/buffer.rb
|
42
40
|
- lib/graphite-api/cache/memory.rb
|
43
41
|
- lib/graphite-api/cache.rb
|
44
42
|
- lib/graphite-api/cli.rb
|
45
43
|
- lib/graphite-api/client.rb
|
46
44
|
- lib/graphite-api/connector.rb
|
47
45
|
- lib/graphite-api/connector_group.rb
|
46
|
+
- lib/graphite-api/core_ext/numeric.rb
|
48
47
|
- lib/graphite-api/logger.rb
|
49
48
|
- lib/graphite-api/middleware.rb
|
50
49
|
- lib/graphite-api/reactor.rb
|
@@ -70,9 +69,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
70
69
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
71
70
|
none: false
|
72
71
|
requirements:
|
73
|
-
- - ! '
|
72
|
+
- - ! '>='
|
74
73
|
- !ruby/object:Gem::Version
|
75
|
-
version:
|
74
|
+
version: '0'
|
76
75
|
requirements: []
|
77
76
|
rubyforge_project: graphite-api
|
78
77
|
rubygems_version: 1.8.25
|
data/lib/graphite-api/buffer.rb
DELETED
@@ -1,137 +0,0 @@
|
|
1
|
-
# -----------------------------------------------------
|
2
|
-
# Buffer Object
|
3
|
-
# Handle Socket & Client data streams
|
4
|
-
# -----------------------------------------------------
|
5
|
-
# Usage:
|
6
|
-
# buff = GraphiteAPI::Buffer.new(GraphiteAPI::Utils.default_options)
|
7
|
-
# buff << {:metric => {"load_avg" => 10},:time => Time.now}
|
8
|
-
# buff << {:metric => {"load_avg" => 30},:time => Time.now}
|
9
|
-
# buff.stream "mem.usage 1"
|
10
|
-
# buff.stream "90 1326842563\n"
|
11
|
-
# buff.stream "shuki.tuki 999 1326842563\n"
|
12
|
-
# buff.pull.each {|o| p o}
|
13
|
-
#
|
14
|
-
# Produce:
|
15
|
-
# ["load_avg", 40.0, 1326881160]
|
16
|
-
# ["mem.usage", 190.0, 1326842520]
|
17
|
-
# ["shuki.tuki", 999.0, 1326842520]
|
18
|
-
# -----------------------------------------------------
|
19
|
-
require 'set'
|
20
|
-
|
21
|
-
module GraphiteAPI
|
22
|
-
class Buffer
|
23
|
-
include Utils
|
24
|
-
|
25
|
-
CLOSING_STREAM = "\n" # end of message - when streaming to buffer obj
|
26
|
-
CHARS_TO_IGNORE = %w(\r) # skip these chars when parsing new message
|
27
|
-
FLOATS_ROUND_BY = 2 # round(x) after summing floats
|
28
|
-
|
29
|
-
VALID_MESSAGE = /^[\w|\.]+ \d+(?:\.|\d)* \d+$/
|
30
|
-
|
31
|
-
def initialize options
|
32
|
-
@options = options
|
33
|
-
@keys_to_sync = Hash.new { |h,k| h[k] = Set.new }
|
34
|
-
@streamer_buff = Hash.new {|h,k| h[k] = ""}
|
35
|
-
@reanimation_mode = !options[:cache].nil?
|
36
|
-
start_cleaner if reanimation_mode
|
37
|
-
end
|
38
|
-
|
39
|
-
private_reader :options, :keys_to_sync, :reanimation_mode, :streamer_buff
|
40
|
-
|
41
|
-
def push hash
|
42
|
-
debug [:buffer,:add, hash]
|
43
|
-
time = normalize_time(hash[:time],options[:slice])
|
44
|
-
hash[:metric].each { |k,v| cache_set(time,k,v) }
|
45
|
-
end
|
46
|
-
|
47
|
-
alias_method :<<, :push
|
48
|
-
|
49
|
-
def stream message, client_id = nil
|
50
|
-
message.gsub(/\t/,' ').each_char do |char|
|
51
|
-
next if invalid_char? char
|
52
|
-
streamer_buff[client_id] += char
|
53
|
-
|
54
|
-
if closed_stream? streamer_buff[client_id]
|
55
|
-
if valid streamer_buff[client_id]
|
56
|
-
push build_metric *streamer_buff[client_id].split
|
57
|
-
end
|
58
|
-
streamer_buff.delete client_id
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
def pull as = nil
|
64
|
-
Array.new.tap do |data|
|
65
|
-
keys_to_sync.each do |time,keys|
|
66
|
-
keys.each do |key|
|
67
|
-
data.push cache_get(time, key, as)
|
68
|
-
end
|
69
|
-
end
|
70
|
-
clear
|
71
|
-
end
|
72
|
-
|
73
|
-
end
|
74
|
-
|
75
|
-
def new_records?
|
76
|
-
!keys_to_sync.empty?
|
77
|
-
end
|
78
|
-
|
79
|
-
private
|
80
|
-
|
81
|
-
def closed_stream? string
|
82
|
-
string[-1,1] == CLOSING_STREAM
|
83
|
-
end
|
84
|
-
|
85
|
-
def invalid_char? char
|
86
|
-
CHARS_TO_IGNORE.include? char
|
87
|
-
end
|
88
|
-
|
89
|
-
def cache_set time, key, value
|
90
|
-
buffer_cache[time][key] = sum buffer_cache[time][key], value.to_f
|
91
|
-
keys_to_sync[time].add key
|
92
|
-
end
|
93
|
-
|
94
|
-
def sum float1, float2
|
95
|
-
("%.#{FLOATS_ROUND_BY}f" % (float1 + float2)).to_f
|
96
|
-
end
|
97
|
-
|
98
|
-
def cache_get time, key, as
|
99
|
-
metric = [prefix + key,buffer_cache[time][key],time]
|
100
|
-
as == :string ? metric.join(" ") : metric
|
101
|
-
end
|
102
|
-
|
103
|
-
def build_metric key, value, time
|
104
|
-
{ :metric => { key => value },:time => Time.at(time.to_i) }
|
105
|
-
end
|
106
|
-
|
107
|
-
def clear
|
108
|
-
keys_to_sync.clear
|
109
|
-
buffer_cache.clear unless reanimation_mode
|
110
|
-
end
|
111
|
-
|
112
|
-
def valid message
|
113
|
-
message =~ VALID_MESSAGE
|
114
|
-
end
|
115
|
-
|
116
|
-
def prefix
|
117
|
-
@prefix ||= options[:prefix].empty? ? '' : prefix_to_s
|
118
|
-
end
|
119
|
-
|
120
|
-
def prefix_to_s
|
121
|
-
Array(options[:prefix]).join('.') << '.'
|
122
|
-
end
|
123
|
-
|
124
|
-
def buffer_cache
|
125
|
-
@buffer_cache ||= Hash.new {|h,k| h[k] = Hash.new {|h1,k1| h1[k1] = 0}}
|
126
|
-
end
|
127
|
-
|
128
|
-
def clean age
|
129
|
-
[buffer_cache,keys_to_sync].each {|o| o.delete_if {|t,k| Time.now.to_i - t > age}}
|
130
|
-
end
|
131
|
-
|
132
|
-
def start_cleaner
|
133
|
-
Reactor::every(options[:cleaner_interval]) { clean(options[:cache]) }
|
134
|
-
end
|
135
|
-
|
136
|
-
end
|
137
|
-
end
|