leela_client 0.0.2 → 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/leela_client/api.rb +34 -0
- data/leela_client/lb.rb +50 -0
- data/leela_client/metrics.rb +90 -0
- data/leela_client/ring.rb +85 -0
- data/leela_client/transport.rb +39 -0
- data/{lib/leela_client → leela_client}/version.rb +1 -1
- data/leela_client.gemspec +6 -9
- data/leela_client.rb +22 -0
- metadata +16 -37
- data/Gemfile +0 -4
- data/Gemfile.lock +0 -26
- data/lib/leela_client.rb +0 -27
- data/spec/leela_client_spec.rb +0 -29
- data/spec/spec_helper.rb +0 -1
data/leela_client/api.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# -*- encoding: utf-8; -*-
|
2
|
+
#
|
3
|
+
# All Rights Reserved.
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
|
17
|
+
require "resolv"
|
18
|
+
|
19
|
+
DEFAULT_PORT = 6968
|
20
|
+
|
21
|
+
module LeelaClient
|
22
|
+
module Api
|
23
|
+
extend self
|
24
|
+
|
25
|
+
def transport(servers)
|
26
|
+
servers = servers.map do |addr|
|
27
|
+
host, port = addr.split(":", 2)
|
28
|
+
[Resolv.getaddress(host), (port || 6968).to_i]
|
29
|
+
end
|
30
|
+
|
31
|
+
UDPTransport.new MD5Ring.from_list(servers)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/leela_client/lb.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
# -*- encoding: utf-8; -*-
|
2
|
+
#
|
3
|
+
# All Rights Reserved.
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
|
17
|
+
module LeelaClient
|
18
|
+
module LoadBalancer
|
19
|
+
extend self
|
20
|
+
|
21
|
+
def group(ring, metrics)
|
22
|
+
group = Hash[ ring.values.map {|x| [x, []]} ]
|
23
|
+
metrics.each do |m|
|
24
|
+
node = ring.select(m.key)
|
25
|
+
group[node] << m
|
26
|
+
end
|
27
|
+
|
28
|
+
group
|
29
|
+
end
|
30
|
+
|
31
|
+
def group_limit(ring, metrics, maxsize)
|
32
|
+
g1 = {}
|
33
|
+
c = 0
|
34
|
+
|
35
|
+
group(ring, metrics).each do |k, ms|
|
36
|
+
g1[k] = [[]]
|
37
|
+
ms.each do |m|
|
38
|
+
c += m.size
|
39
|
+
g1[k][-1] << m
|
40
|
+
if (c >= maxsize)
|
41
|
+
c = 0
|
42
|
+
g1[k] << []
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
g1
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# -*- encoding: utf-8; -*-
|
2
|
+
#
|
3
|
+
# All Rights Reserved.
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
|
17
|
+
module LeelaClient
|
18
|
+
module Metric
|
19
|
+
attr_reader :type
|
20
|
+
attr_accessor :key
|
21
|
+
attr_accessor :value
|
22
|
+
attr_accessor :timestamp
|
23
|
+
|
24
|
+
def serialize
|
25
|
+
size = @key.size
|
26
|
+
now = @timestamp.to_f.to_s
|
27
|
+
if (@value.integer?)
|
28
|
+
value = @value.to_f.to_s
|
29
|
+
elsif (@value.nan?)
|
30
|
+
value = "nan"
|
31
|
+
elsif (@value.infinite? == 1)
|
32
|
+
value = "inf"
|
33
|
+
elsif (@value.infinite? == -1)
|
34
|
+
value = "-inf"
|
35
|
+
else
|
36
|
+
value = @value.to_s
|
37
|
+
end
|
38
|
+
|
39
|
+
"#{@type} #{size}|#{@key} #{value} #{now};"
|
40
|
+
end
|
41
|
+
|
42
|
+
def size
|
43
|
+
self.serialize.size
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
class Gauge
|
48
|
+
include Metric
|
49
|
+
|
50
|
+
def initialize(key, value)
|
51
|
+
@type = "gauge"
|
52
|
+
@key = key
|
53
|
+
@value = value
|
54
|
+
@timestamp = Time.now
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
class Counter
|
59
|
+
include Metric
|
60
|
+
|
61
|
+
def initialize(key, value)
|
62
|
+
@type = "counter"
|
63
|
+
@key = key
|
64
|
+
@value = value
|
65
|
+
@timestamp = Time.now
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
class Derive
|
70
|
+
include Metric
|
71
|
+
|
72
|
+
def initialize(key, value)
|
73
|
+
@type = "derive"
|
74
|
+
@key = key
|
75
|
+
@value = value
|
76
|
+
@timestamp = Time.now
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
class Absolute
|
81
|
+
include Metric
|
82
|
+
|
83
|
+
def initialize(key, value)
|
84
|
+
@type = "absolute"
|
85
|
+
@key = key
|
86
|
+
@value = value
|
87
|
+
@timestamp = Time.now
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# -*- encoding: utf-8; -*-
|
2
|
+
#
|
3
|
+
# All Rights Reserved.
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
|
17
|
+
require "set"
|
18
|
+
require "digest/md5"
|
19
|
+
|
20
|
+
module LeelaClient
|
21
|
+
class Ring
|
22
|
+
def token(key)
|
23
|
+
raise(RuntimeError.new "abstract method")
|
24
|
+
end
|
25
|
+
|
26
|
+
def add_token!(token, value)
|
27
|
+
raise(RuntimeError.new "abstract method")
|
28
|
+
end
|
29
|
+
|
30
|
+
def rm_token!(token)
|
31
|
+
raise(RuntimeError.new "abstract method")
|
32
|
+
end
|
33
|
+
|
34
|
+
def select(token)
|
35
|
+
raise(RuntimeError.new "abstract method")
|
36
|
+
end
|
37
|
+
|
38
|
+
def values
|
39
|
+
raise(RuntimeError.new "abstract method")
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class MD5Ring < Ring
|
44
|
+
def self.from_list(values)
|
45
|
+
ring = MD5Ring.new
|
46
|
+
step = 2**128 / values.size
|
47
|
+
token = 0
|
48
|
+
Set.new(values).sort.each do |v|
|
49
|
+
ring.add_token!(token, v)
|
50
|
+
token += step
|
51
|
+
end
|
52
|
+
|
53
|
+
ring
|
54
|
+
end
|
55
|
+
|
56
|
+
def initialize
|
57
|
+
@ring = {}
|
58
|
+
end
|
59
|
+
|
60
|
+
def token(key)
|
61
|
+
Digest::MD5.hexdigest(key).to_i(16)
|
62
|
+
end
|
63
|
+
|
64
|
+
def add_token!(token, value)
|
65
|
+
@ring[token] = value
|
66
|
+
end
|
67
|
+
|
68
|
+
def rm_token!(token)
|
69
|
+
@ring.delete(token)
|
70
|
+
end
|
71
|
+
|
72
|
+
def values
|
73
|
+
@ring.values
|
74
|
+
end
|
75
|
+
|
76
|
+
def select(value)
|
77
|
+
self.select_(self.token(value))
|
78
|
+
end
|
79
|
+
|
80
|
+
def select_(token)
|
81
|
+
k = @ring.keys.sort.select {|x| x < token}.last
|
82
|
+
@ring[k]
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# -*- encoding: utf-8; -*-
|
2
|
+
#
|
3
|
+
# All Rights Reserved.
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
|
17
|
+
module LeelaClient
|
18
|
+
class UDPTransport
|
19
|
+
MAXPAYLOAD = 1472
|
20
|
+
|
21
|
+
def initialize(ring)
|
22
|
+
@ring = ring
|
23
|
+
@sock = UDPSocket.new
|
24
|
+
end
|
25
|
+
|
26
|
+
def serialize_list(metrics)
|
27
|
+
metrics.map(&:serialize).join("")
|
28
|
+
end
|
29
|
+
|
30
|
+
def send(metrics)
|
31
|
+
LeelaClient::LoadBalancer.group_limit(@ring, metrics, MAXPAYLOAD).each do |addr, mms|
|
32
|
+
mms.each do |ms|
|
33
|
+
sent = @sock.send(serialize_list(ms), 0, addr[0], addr[1])
|
34
|
+
raise if (sent > MAXPAYLOAD)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/leela_client.gemspec
CHANGED
@@ -1,19 +1,16 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
require File.expand_path('../
|
2
|
+
require File.expand_path('../leela_client/version', __FILE__)
|
3
3
|
|
4
4
|
Gem::Specification.new do |gem|
|
5
|
-
gem.authors = ["PotHix", "
|
6
|
-
gem.email = ["pothix@pothix.com", "
|
5
|
+
gem.authors = ["PotHix", "dgvncsz0f"]
|
6
|
+
gem.email = ["pothix@pothix.com", "dgvncsz0f@bitforest.com"]
|
7
7
|
gem.description = %q{A client for leela chart server}
|
8
|
-
gem.summary
|
9
|
-
gem.homepage = "https://github.com/
|
8
|
+
gem.summary = gem.description
|
9
|
+
gem.homepage = "https://github.com/locaweb/leela-client"
|
10
10
|
|
11
11
|
gem.files = Dir["./**/*"].reject {|file| file =~ /\.git|pkg/}
|
12
|
-
gem.require_paths = ["
|
12
|
+
gem.require_paths = ["leela_client"]
|
13
13
|
|
14
14
|
gem.name = "leela_client"
|
15
15
|
gem.version = LeelaClient::VERSION
|
16
|
-
|
17
|
-
gem.add_dependency "bzip2-ruby"
|
18
|
-
gem.add_development_dependency "rspec"
|
19
16
|
end
|
data/leela_client.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# -*- coding: utf-8; -*-
|
2
|
+
#
|
3
|
+
# All Rights Reserved.
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
|
17
|
+
require "leela_client/api"
|
18
|
+
require "leela_client/lb"
|
19
|
+
require "leela_client/metrics"
|
20
|
+
require "leela_client/ring"
|
21
|
+
require "leela_client/transport"
|
22
|
+
require "leela_client/version"
|
metadata
CHANGED
@@ -1,61 +1,40 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: leela_client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- PotHix
|
9
|
-
-
|
9
|
+
- dgvncsz0f
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date:
|
14
|
-
dependencies:
|
15
|
-
- !ruby/object:Gem::Dependency
|
16
|
-
name: bzip2-ruby
|
17
|
-
requirement: &12335200 !ruby/object:Gem::Requirement
|
18
|
-
none: false
|
19
|
-
requirements:
|
20
|
-
- - ! '>='
|
21
|
-
- !ruby/object:Gem::Version
|
22
|
-
version: '0'
|
23
|
-
type: :runtime
|
24
|
-
prerelease: false
|
25
|
-
version_requirements: *12335200
|
26
|
-
- !ruby/object:Gem::Dependency
|
27
|
-
name: rspec
|
28
|
-
requirement: &12334600 !ruby/object:Gem::Requirement
|
29
|
-
none: false
|
30
|
-
requirements:
|
31
|
-
- - ! '>='
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: '0'
|
34
|
-
type: :development
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: *12334600
|
13
|
+
date: 2013-04-17 00:00:00.000000000 Z
|
14
|
+
dependencies: []
|
37
15
|
description: A client for leela chart server
|
38
16
|
email:
|
39
17
|
- pothix@pothix.com
|
40
|
-
-
|
18
|
+
- dgvncsz0f@bitforest.com
|
41
19
|
executables: []
|
42
20
|
extensions: []
|
43
21
|
extra_rdoc_files: []
|
44
22
|
files:
|
45
|
-
- ./
|
46
|
-
- ./leela_client.
|
47
|
-
- ./
|
48
|
-
- ./
|
49
|
-
- ./
|
23
|
+
- ./leela_client/version.rb
|
24
|
+
- ./leela_client/transport.rb
|
25
|
+
- ./leela_client/api.rb
|
26
|
+
- ./leela_client/ring.rb
|
27
|
+
- ./leela_client/lb.rb
|
28
|
+
- ./leela_client/metrics.rb
|
50
29
|
- ./Rakefile
|
51
|
-
- ./
|
52
|
-
- ./
|
53
|
-
homepage: https://github.com/
|
30
|
+
- ./leela_client.gemspec
|
31
|
+
- ./leela_client.rb
|
32
|
+
homepage: https://github.com/locaweb/leela-client
|
54
33
|
licenses: []
|
55
34
|
post_install_message:
|
56
35
|
rdoc_options: []
|
57
36
|
require_paths:
|
58
|
-
-
|
37
|
+
- leela_client
|
59
38
|
required_ruby_version: !ruby/object:Gem::Requirement
|
60
39
|
none: false
|
61
40
|
requirements:
|
@@ -70,7 +49,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
70
49
|
version: '0'
|
71
50
|
requirements: []
|
72
51
|
rubyforge_project:
|
73
|
-
rubygems_version: 1.8.
|
52
|
+
rubygems_version: 1.8.23
|
74
53
|
signing_key:
|
75
54
|
specification_version: 3
|
76
55
|
summary: A client for leela chart server
|
data/Gemfile
DELETED
data/Gemfile.lock
DELETED
@@ -1,26 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
leela_client (0.0.1)
|
5
|
-
bzip2-ruby
|
6
|
-
|
7
|
-
GEM
|
8
|
-
remote: https://rubygems.org/
|
9
|
-
specs:
|
10
|
-
bzip2-ruby (0.2.7)
|
11
|
-
diff-lcs (1.1.3)
|
12
|
-
rspec (2.8.0)
|
13
|
-
rspec-core (~> 2.8.0)
|
14
|
-
rspec-expectations (~> 2.8.0)
|
15
|
-
rspec-mocks (~> 2.8.0)
|
16
|
-
rspec-core (2.8.0)
|
17
|
-
rspec-expectations (2.8.0)
|
18
|
-
diff-lcs (~> 1.1.2)
|
19
|
-
rspec-mocks (2.8.0)
|
20
|
-
|
21
|
-
PLATFORMS
|
22
|
-
ruby
|
23
|
-
|
24
|
-
DEPENDENCIES
|
25
|
-
leela_client!
|
26
|
-
rspec
|
data/lib/leela_client.rb
DELETED
@@ -1,27 +0,0 @@
|
|
1
|
-
require "leela_client/version"
|
2
|
-
require "socket"
|
3
|
-
require "bzip2"
|
4
|
-
|
5
|
-
module LeelaClient
|
6
|
-
class Client
|
7
|
-
attr_reader :data
|
8
|
-
|
9
|
-
def initialize(service, server="127.0.0.1", port=6968)
|
10
|
-
@server, @port = server, port
|
11
|
-
@service = service
|
12
|
-
@data = []
|
13
|
-
end
|
14
|
-
|
15
|
-
def add(name, value)
|
16
|
-
@data << "#{name}|#{value}"
|
17
|
-
end
|
18
|
-
|
19
|
-
def publish
|
20
|
-
sock = UDPSocket.new
|
21
|
-
sock.connect(@server, @port)
|
22
|
-
|
23
|
-
message = "#{Socket.gethostname}|#{@service}||" + @data.join("||")
|
24
|
-
sock.send(Bzip2.compress(message, 9), 0)
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
data/spec/leela_client_spec.rb
DELETED
@@ -1,29 +0,0 @@
|
|
1
|
-
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
-
|
3
|
-
describe LeelaClient do
|
4
|
-
it "shold add the correct data in normal order" do
|
5
|
-
leela = LeelaClient::Client.new "service"
|
6
|
-
|
7
|
-
leela.data.should be_empty
|
8
|
-
leela.add("attr", 10)
|
9
|
-
leela.data.should have(1).item
|
10
|
-
|
11
|
-
leela.add("attr", 20)
|
12
|
-
leela.data.should have(2).items
|
13
|
-
leela.data.last.should eql("attr|20")
|
14
|
-
end
|
15
|
-
|
16
|
-
it "should send the complete information to the socket" do
|
17
|
-
host = "machine"
|
18
|
-
Socket.stub(:gethostname).and_return(host)
|
19
|
-
|
20
|
-
sock = UDPSocket.new
|
21
|
-
sock.bind("127.0.0.1",6968)
|
22
|
-
|
23
|
-
leela = LeelaClient::Client.new("service", "127.0.0.1", 6968)
|
24
|
-
leela.add("param", 50)
|
25
|
-
leela.publish
|
26
|
-
|
27
|
-
sock.recvfrom(100)[0].should eql(Bzip2.compress("machine|service||param|50",9))
|
28
|
-
end
|
29
|
-
end
|
data/spec/spec_helper.rb
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
require "leela_client"
|