graphite-api 0.3.3 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.md +32 -20
- data/Rakefile +3 -8
- data/bin/graphite-middleware +7 -2
- data/lib/graphite-api/buffer.rb +56 -32
- data/lib/graphite-api/cache.rb +2 -6
- data/lib/graphite-api/client.rb +4 -3
- data/lib/graphite-api/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 76010192ae0104397b2f2f069f03ee6f5895f42473f8bab79068ce7808104a58
|
4
|
+
data.tar.gz: da60c3a2a69ed0d1e35232d4b1e4fb90709a7d16c87d241801824b67094cf4b0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 29d966b90c0d676c604e2556a05992667ec6a083e078ae2a2a4cb75a9524ea042919585038ff18dcf1b90b7ed049c414ebefdb5dbc0389787a2976960cf534b9
|
7
|
+
data.tar.gz: 4c1c95a572507ecd6df22581559f615fecdefc8cb8c098707bdaac0ed2bc39f51c6dcbeaa13b3dee441a3b36a0e86cbf30d0e916676214aa0aa40aa38480edc8
|
data/README.md
CHANGED
@@ -13,17 +13,9 @@
|
|
13
13
|
* **Thread-Safe** client.
|
14
14
|
|
15
15
|
## Status
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
<td><a href="https://rubygems.org/gems/graphite-api"><img src=https://fury-badge.herokuapp.com/rb/graphite-api.png></a> </td>
|
20
|
-
</tr>
|
21
|
-
<tr>
|
22
|
-
<td> Build </td>
|
23
|
-
<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>
|
24
|
-
</td>
|
25
|
-
</tr>
|
26
|
-
</table>
|
16
|
+
[![Gem Version](https://badge.fury.io/rb/graphite-api.svg)](https://badge.fury.io/rb/graphite-api)
|
17
|
+
[![Build Status](https://travis-ci.org/kontera-technologies/graphite-api.svg?branch=master)](https://travis-ci.org/kontera-technologies/graphite-api)
|
18
|
+
[![Test Coverage](https://codecov.io/gh/kontera-technologies/graphite-api/branch/master/graph/badge.svg)](https://codecov.io/gh/kontera-technologies/graphite-api)
|
27
19
|
|
28
20
|
## Installation
|
29
21
|
Install stable version
|
@@ -32,14 +24,6 @@ Install stable version
|
|
32
24
|
gem install graphite-api
|
33
25
|
```
|
34
26
|
|
35
|
-
Install the latest from github
|
36
|
-
|
37
|
-
```
|
38
|
-
git clone git://github.com/kontera-technologies/graphite-api.git
|
39
|
-
cd graphite-api
|
40
|
-
rake install
|
41
|
-
```
|
42
|
-
|
43
27
|
## Client Usage
|
44
28
|
|
45
29
|
Creating a new UDP client
|
@@ -61,7 +45,11 @@ options = {
|
|
61
45
|
interval: 60,
|
62
46
|
|
63
47
|
# Optional: set the max age in seconds for records reanimation ( default is 12 hours )
|
64
|
-
cache: 4 * 60 * 60
|
48
|
+
cache: 4 * 60 * 60,
|
49
|
+
|
50
|
+
# Optional: The default aggregation method for multiple reports in the same slice (default is :add).
|
51
|
+
# Possible options: :sum, :avg, :replace
|
52
|
+
default_aggregation_method: :avg
|
65
53
|
}
|
66
54
|
|
67
55
|
client = GraphiteAPI.new options
|
@@ -77,6 +65,11 @@ TCP Client with 30 seconds timeout
|
|
77
65
|
client = GraphiteAPI.new graphite: "tcp://graphite.example.com:2003?timeout=30"
|
78
66
|
```
|
79
67
|
|
68
|
+
TCP Client with custom aggregation method
|
69
|
+
```ruby
|
70
|
+
client = GraphiteAPI.new graphite: "tcp://graphite.example.com:2003", default_aggregation_method: :avg
|
71
|
+
```
|
72
|
+
|
80
73
|
Adding simple metrics
|
81
74
|
```ruby
|
82
75
|
require 'graphite-api'
|
@@ -108,6 +101,24 @@ client.metrics({
|
|
108
101
|
# => webServer.web01.memUsage 40 1326067060
|
109
102
|
```
|
110
103
|
|
104
|
+
Adding metrics with custom aggregation method
|
105
|
+
```ruby
|
106
|
+
require 'graphite-api'
|
107
|
+
|
108
|
+
client = GraphiteAPI.new( graphite: 'udp://graphite:2003' )
|
109
|
+
|
110
|
+
client.metrics({
|
111
|
+
"webServer.web01.loadAvg" => 10,
|
112
|
+
"webServer.web01.memUsage" => 40
|
113
|
+
},Time.at(1326067060), :avg)
|
114
|
+
client.metrics({
|
115
|
+
"webServer.web01.loadAvg" => 20,
|
116
|
+
"webServer.web01.memUsage" => 50
|
117
|
+
},Time.at(1326067060), :avg)
|
118
|
+
# => webServer.web01.loadAvg 15 1326067060
|
119
|
+
# => webServer.web01.memUsage 45 1326067060
|
120
|
+
```
|
121
|
+
|
111
122
|
Verifying connectivity
|
112
123
|
```ruby
|
113
124
|
require 'graphite-api'
|
@@ -225,6 +236,7 @@ Usage: graphite-middleware [options]
|
|
225
236
|
-i, --interval INT report every X seconds (default 60)
|
226
237
|
-s, --slice SECONDS send to graphite in X seconds slices (default 60)
|
227
238
|
-r, --reanimation HOURS reanimate records that are younger than X hours, please see README
|
239
|
+
-m, --aggregation-method method The aggregation method (sum, avg or replace) for multiple reports in the same time slice (default sum)
|
228
240
|
|
229
241
|
More Info @ https://github.com/kontera-technologies/graphite-api
|
230
242
|
```
|
data/Rakefile
CHANGED
@@ -9,7 +9,7 @@ def message msg
|
|
9
9
|
puts "*** #{msg} ***"
|
10
10
|
end
|
11
11
|
|
12
|
-
task(:test => :functional)
|
12
|
+
task(:test => :functional)
|
13
13
|
|
14
14
|
Rake::TestTask.new do |t|
|
15
15
|
t.libs << "tests"
|
@@ -18,14 +18,14 @@ end
|
|
18
18
|
|
19
19
|
task :functional do
|
20
20
|
some_failed = false
|
21
|
-
|
21
|
+
|
22
22
|
next unless ENV['SKIP_FUNC'].nil?
|
23
23
|
|
24
24
|
unless RUBY_COPYRIGHT.end_with?("Matsumoto")
|
25
25
|
puts("Functional tests are enabled only on MRI...")
|
26
26
|
next
|
27
27
|
end
|
28
|
-
|
28
|
+
|
29
29
|
message "Executing GraphiteAPI Functional Tests"
|
30
30
|
message "( You can skip them by passing SKIP_FUNC=true )"
|
31
31
|
|
@@ -56,8 +56,3 @@ GraphiteAPI::GemSpec = eval File.read 'graphite-api.gemspec'
|
|
56
56
|
Gem::PackageTask.new(GraphiteAPI::GemSpec) do |p|
|
57
57
|
p.gem_spec = GraphiteAPI::GemSpec
|
58
58
|
end
|
59
|
-
|
60
|
-
task :install => [:gem] do
|
61
|
-
sh "gem install pkg/graphite-api"
|
62
|
-
Rake::Task['clobber_package'].execute
|
63
|
-
end
|
data/bin/graphite-middleware
CHANGED
@@ -31,7 +31,7 @@ OptionParser.new do |opts|
|
|
31
31
|
options[:pid] = pid_file
|
32
32
|
end
|
33
33
|
|
34
|
-
opts.on("-d", "--daemonize","run in background") do
|
34
|
+
opts.on("-d", "--daemonize","run in background") do
|
35
35
|
options[:daemonize] = true
|
36
36
|
end
|
37
37
|
|
@@ -47,8 +47,13 @@ OptionParser.new do |opts|
|
|
47
47
|
(options[:cache] = exp.to_i * 3600) if exp.to_i > 0
|
48
48
|
end
|
49
49
|
|
50
|
+
opts.on("-m", "--aggregation-method method","The aggregation method (sum, avg or replace) for multiple reports in the same time slice (default sum)") do |exp|
|
51
|
+
raise "Invalid aggregation method. Valid values are sum, avg or replace." unless ["sum", "avg", "replace"].include? exp
|
52
|
+
options[:default_aggregation_method] = exp.to_sym
|
53
|
+
end
|
54
|
+
|
50
55
|
opts.on("-v", "--version","Show version and exit") do |exp|
|
51
|
-
puts "Version #{GraphiteAPI.version}"
|
56
|
+
puts "Version #{GraphiteAPI.version}"
|
52
57
|
exit
|
53
58
|
end
|
54
59
|
|
data/lib/graphite-api/buffer.rb
CHANGED
@@ -3,16 +3,16 @@
|
|
3
3
|
# Handle Socket & Client data streams
|
4
4
|
# -----------------------------------------------------
|
5
5
|
# Usage:
|
6
|
-
# buff = GraphiteAPI::Buffer.new(GraphiteAPI::
|
7
|
-
# buff << {:metric => {"load_avg" => 10},:time => Time.now}
|
8
|
-
# buff << {:metric => {"load_avg" => 30},:time => Time.now}
|
6
|
+
# buff = GraphiteAPI::Buffer.new(GraphiteAPI::Client.default_options)
|
7
|
+
# buff << {:metric => {"load_avg" => 10},:time => Time.now, :aggregation_method => :avg}
|
8
|
+
# buff << {:metric => {"load_avg" => 30},:time => Time.now, :aggregation_method => :avg}
|
9
9
|
# buff.stream "mem.usage 1"
|
10
10
|
# buff.stream "90 1326842563\n"
|
11
11
|
# buff.stream "shuki.tuki 999 1326842563\n"
|
12
|
-
# buff.pull.each {|o| p o}
|
12
|
+
# buff.pull.each {|o| p o}
|
13
13
|
#
|
14
14
|
# Produce:
|
15
|
-
# ["load_avg",
|
15
|
+
# ["load_avg", 20.0, 1326881160]
|
16
16
|
# ["mem.usage", 190.0, 1326842520]
|
17
17
|
# ["shuki.tuki", 999.0, 1326842520]
|
18
18
|
# -----------------------------------------------------
|
@@ -21,38 +21,44 @@ require 'set'
|
|
21
21
|
|
22
22
|
module GraphiteAPI
|
23
23
|
class Buffer
|
24
|
-
|
24
|
+
|
25
25
|
IGNORE = ["\r"]
|
26
26
|
END_OF_STREAM = "\n"
|
27
27
|
VALID_MESSAGE = /^[\w|\.|-]+ \d+(?:\.|\d)* \d+$/
|
28
|
-
|
28
|
+
|
29
|
+
AGGREGATORS = {
|
30
|
+
sum: ->(*args) { args.reduce(0) { |sum, x| sum + x } },
|
31
|
+
avg: ->(*args) { args.reduce(0) { |sum, x| sum + x } / [args.length, 1].max },
|
32
|
+
replace: ->(*args) { args.last },
|
33
|
+
}
|
34
|
+
|
29
35
|
def initialize options
|
30
36
|
@options = options
|
31
37
|
@queue = Queue.new
|
32
38
|
@streamer = Hash.new {|h,k| h[k] = ""}
|
33
|
-
@cache = Cache::Memory.new
|
39
|
+
@cache = Cache::Memory.new(options) if options[:cache]
|
34
40
|
end
|
35
|
-
|
41
|
+
|
36
42
|
attr_reader :queue, :options, :streamer, :cache
|
37
|
-
|
43
|
+
|
38
44
|
# this method isn't thread safe
|
39
45
|
# use #push for multiple threads support
|
40
46
|
def stream message, client_id = nil
|
41
47
|
message.gsub(/\t/,' ').each_char do |char|
|
42
48
|
next if invalid_char? char
|
43
|
-
streamer[client_id] += char
|
44
|
-
|
49
|
+
streamer[client_id] += char
|
50
|
+
|
45
51
|
if closed_stream? streamer[client_id]
|
46
|
-
if streamer[client_id] =~ VALID_MESSAGE
|
52
|
+
if streamer[client_id] =~ VALID_MESSAGE
|
47
53
|
push stream_message_to_obj streamer[client_id]
|
48
54
|
end
|
49
55
|
streamer.delete client_id
|
50
56
|
end
|
51
57
|
end
|
52
58
|
end
|
53
|
-
|
59
|
+
|
54
60
|
# Add records to buffer
|
55
|
-
# push({:metric => {'a' => 10},:time => Time.now})
|
61
|
+
# push({:metric => {'a' => 10},:time => Time.now,:aggregation_method => :sum})
|
56
62
|
def push obj
|
57
63
|
Logger.debug [:buffer,:add, obj]
|
58
64
|
queue.push obj
|
@@ -62,49 +68,67 @@ module GraphiteAPI
|
|
62
68
|
alias_method :<<, :push
|
63
69
|
|
64
70
|
def pull format = nil
|
65
|
-
data = Hash.new {|h,
|
71
|
+
data = Hash.new { |h,time| h[time] = Hash.new { |h2,metric| h2[metric] = cache_get(time, metric) } }
|
72
|
+
aggregation_methods = Hash.new
|
66
73
|
|
67
74
|
counter = 0
|
68
|
-
while new_records?
|
69
|
-
|
70
|
-
|
71
|
-
|
75
|
+
while new_records? and (counter += 1) < 1_000_000
|
76
|
+
metrics, time, method_name = queue.pop.values_at(:metric, :time, :aggregation_method)
|
77
|
+
|
78
|
+
normalized_time = normalize_time(time, options[:slice])
|
79
|
+
metrics.each do |metric, value|
|
80
|
+
aggregation_methods[metric] = method_name || options[:default_aggregation_method]
|
81
|
+
data[normalized_time][metric].push value.to_f
|
82
|
+
cache_set(normalized_time, metric, data[normalized_time][metric])
|
83
|
+
end
|
72
84
|
end
|
73
|
-
|
74
|
-
data.map do |time,
|
75
|
-
|
76
|
-
value =
|
77
|
-
results = ["#{prefix}#{
|
85
|
+
|
86
|
+
data.map do |time, metrics|
|
87
|
+
metrics.map do |metric, raw_values|
|
88
|
+
value = AGGREGATORS[aggregation_methods[metric]].call(*raw_values)
|
89
|
+
results = ["#{prefix}#{metric}",("%f"%value).to_f, time]
|
78
90
|
format == :string ? results.join(" ") : results
|
79
91
|
end
|
80
92
|
end.flatten(1)
|
81
93
|
end
|
82
|
-
|
94
|
+
|
83
95
|
def inspect
|
84
|
-
"#<GraphiteAPI::Buffer:%s @quque#size=%s @streamer=%s>" %
|
96
|
+
"#<GraphiteAPI::Buffer:%s @quque#size=%s @streamer=%s>" %
|
85
97
|
[ object_id, queue.size, streamer]
|
86
98
|
end
|
87
|
-
|
99
|
+
|
88
100
|
def new_records?
|
89
101
|
!queue.empty?
|
90
102
|
end
|
91
103
|
|
92
104
|
private
|
93
105
|
|
106
|
+
def cache_get time, metric
|
107
|
+
if cache
|
108
|
+
cache.get(time, metric) || []
|
109
|
+
else
|
110
|
+
[]
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def cache_set time, metric, value
|
115
|
+
cache.set(time, metric, value) if cache
|
116
|
+
end
|
117
|
+
|
94
118
|
def normalize_time time, slice
|
95
119
|
slice = 60 if slice.nil?
|
96
120
|
((time || Time.now).to_i / slice * slice).to_i
|
97
121
|
end
|
98
|
-
|
122
|
+
|
99
123
|
def stream_message_to_obj message
|
100
124
|
parts = message.split
|
101
125
|
{:metric => { parts[0] => parts[1] },:time => Time.at(parts[2].to_i) }
|
102
126
|
end
|
103
|
-
|
127
|
+
|
104
128
|
def invalid_char? char
|
105
129
|
IGNORE.include? char
|
106
130
|
end
|
107
|
-
|
131
|
+
|
108
132
|
def closed_stream? string
|
109
133
|
string[-1,1] == END_OF_STREAM
|
110
134
|
end
|
@@ -116,6 +140,6 @@ module GraphiteAPI
|
|
116
140
|
""
|
117
141
|
end
|
118
142
|
end
|
119
|
-
|
143
|
+
|
120
144
|
end
|
121
145
|
end
|
data/lib/graphite-api/cache.rb
CHANGED
@@ -11,17 +11,13 @@ module GraphiteAPI
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def set time, key, value
|
14
|
-
cache[time.to_i][key] = value
|
15
|
-
end
|
16
|
-
|
17
|
-
def incr time, key, value
|
18
|
-
set(time, key, value.to_f + get(time, key))
|
14
|
+
cache[time.to_i][key] = value
|
19
15
|
end
|
20
16
|
|
21
17
|
private
|
22
18
|
|
23
19
|
def cache
|
24
|
-
@cache ||= Hash.new {|h,k| h[k] = Hash.new
|
20
|
+
@cache ||= Hash.new {|h,k| h[k] = Hash.new}
|
25
21
|
end
|
26
22
|
|
27
23
|
def clean max_age
|
data/lib/graphite-api/client.rb
CHANGED
@@ -29,9 +29,9 @@ module GraphiteAPI
|
|
29
29
|
Zscheduler.every( interval ) { block.arity == 1 ? block.call(self) : block.call }
|
30
30
|
end
|
31
31
|
|
32
|
-
def metrics metric, time =
|
32
|
+
def metrics metric, time = nil, aggregation_method = nil
|
33
33
|
return if metric.empty?
|
34
|
-
buffer.push :metric => metric, :time => time
|
34
|
+
buffer.push :metric => metric, :time => (time || Time.now), :aggregation_method => aggregation_method
|
35
35
|
send_metrics! if options[:direct]
|
36
36
|
end
|
37
37
|
|
@@ -59,7 +59,8 @@ module GraphiteAPI
|
|
59
59
|
:prefix => [],
|
60
60
|
:interval => 0,
|
61
61
|
:slice => 60,
|
62
|
-
:pid => "/tmp/graphite-middleware.pid"
|
62
|
+
:pid => "/tmp/graphite-middleware.pid",
|
63
|
+
:default_aggregation_method => :sum
|
63
64
|
}
|
64
65
|
end
|
65
66
|
|
data/lib/graphite-api/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: graphite-api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Eran Barak Levi
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-02-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: eventmachine
|
@@ -78,7 +78,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
78
78
|
version: '0'
|
79
79
|
requirements: []
|
80
80
|
rubyforge_project: graphite-api
|
81
|
-
rubygems_version: 2.
|
81
|
+
rubygems_version: 2.7.8
|
82
82
|
signing_key:
|
83
83
|
specification_version: 4
|
84
84
|
summary: Graphite Ruby Client
|