graphite-api 0.0.3.beta3 → 0.0.3
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 +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
|