fluent-plugin-hash-forward 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -0
- data/README.md +20 -9
- data/fluent-plugin-hash-forward.gemspec +1 -1
- data/lib/fluent/plugin/out_hash_forward.rb +19 -18
- data/spec/out_hash_forward_spec.rb +69 -2
- metadata +2 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 38bfa4c2b8ecb078ef39859c02f535d445f6abc5
|
4
|
+
data.tar.gz: 14a48e69abed66f8ed07ae185286d82d91c3aa21
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 993925c2ddb9e8909c7f1bd508f14b6d0ab22b63d4c267b01808d8bd9c3dd4789b871cc7388e20db5d132469fe19c8d00749a37b116e6d2841572c024c0ef441
|
7
|
+
data.tar.gz: e738d73bdc48f65f64e23287ba1fa8c941a6a5d777686aff5f6c7c82e144919494e9ec925f130cbd4f050420ac744c846fe9b86ebff5bd913347f3bdfb05a2c5
|
data/CHANGELOG.md
ADDED
data/README.md
CHANGED
@@ -35,21 +35,32 @@ Basically same with out\_forward plugin. See [http://docs.fluentd.org/articles/o
|
|
35
35
|
|
36
36
|
Following parameters are additionally available:
|
37
37
|
|
38
|
-
* hash\_key
|
38
|
+
* hash\_key\_slice *min*..*max*
|
39
39
|
|
40
|
-
|
40
|
+
Use sliced `tag` as a hash key to determine a forwarding node. Default: use entire `tag`.
|
41
41
|
|
42
|
-
|
42
|
+
For example, assume tags of input messages are like
|
43
43
|
|
44
|
-
|
44
|
+
foo.bar.host1
|
45
|
+
foo.bar.host2
|
45
46
|
|
46
|
-
|
47
|
-
* ${tags} input tag splitted by '.'
|
47
|
+
but, you want to forward these messages to the same node, configure like
|
48
48
|
|
49
|
-
|
49
|
+
hash_key_slice 0..-2
|
50
50
|
|
51
|
-
|
52
|
-
|
51
|
+
then, hash\_key becomes as `foo.bar` which results in forwarding these messages to the same node.
|
52
|
+
|
53
|
+
FYI: This option behaves like `tag.split('.').slice(min..max)`.
|
54
|
+
|
55
|
+
## ToDo
|
56
|
+
|
57
|
+
* Consistent hashing
|
58
|
+
|
59
|
+
* Consistent hashing is useful on adding or removing nodes dynamically, but currently `out_hash_forward` does not support such a dynamical feature, so consistent hashing is just useless now. To effectively support consistent hashing, this plugin must support ways to add or remove nodes dynamically by preparing http api or reading nodes information from redis or memcached, etc.
|
60
|
+
|
61
|
+
## ChangeLog
|
62
|
+
|
63
|
+
See [CHANGELOG.md](CHANGELOG.md) for details.
|
53
64
|
|
54
65
|
## Copyright
|
55
66
|
|
@@ -3,7 +3,7 @@ $:.push File.expand_path("../lib", __FILE__)
|
|
3
3
|
|
4
4
|
Gem::Specification.new do |s|
|
5
5
|
s.name = "fluent-plugin-hash-forward"
|
6
|
-
s.version = "0.0.
|
6
|
+
s.version = "0.0.2"
|
7
7
|
s.authors = ["Ryosuke IWANAGA", "Naotoshi SEO"]
|
8
8
|
s.email = ["riywo.jp@gmail.com", "sonots@gmail.com"]
|
9
9
|
s.homepage = "https://github.com/riywo/fluent-plugin-hash-forward"
|
@@ -3,15 +3,28 @@ require 'fluent/plugin/out_forward'
|
|
3
3
|
class Fluent::HashForwardOutput < Fluent::ForwardOutput
|
4
4
|
Fluent::Plugin.register_output('hash_forward', self)
|
5
5
|
|
6
|
-
config_param :
|
6
|
+
config_param :hash_key_slice, :string, :default => nil
|
7
7
|
|
8
8
|
def configure(conf)
|
9
9
|
super
|
10
10
|
@standby_nodes, @regular_nodes = @nodes.partition {|n| n.standby? }
|
11
|
+
|
12
|
+
if @hash_key_slice
|
13
|
+
lindex, rindex = @hash_key_slice.split('..', 2)
|
14
|
+
if lindex.nil? or rindex.nil? or lindex !~ /^-?\d+$/ or rindex !~ /^-?\d+$/
|
15
|
+
raise Fluent::ConfigError, "out_hash_forard: hash_key_slice must be formatted like [num]..[num]"
|
16
|
+
else
|
17
|
+
@hash_key_slice_lindex = lindex.to_i
|
18
|
+
@hash_key_slice_rindex = rindex.to_i
|
19
|
+
end
|
20
|
+
end
|
11
21
|
end
|
12
22
|
|
23
|
+
# for test
|
13
24
|
attr_reader :regular_nodes
|
14
25
|
attr_reader :standby_nodes
|
26
|
+
attr_accessor :hash_key_slice_lindex
|
27
|
+
attr_accessor :hash_key_slice_rindex
|
15
28
|
|
16
29
|
# Override
|
17
30
|
def write_objects(tag, chunk)
|
@@ -47,7 +60,7 @@ class Fluent::HashForwardOutput < Fluent::ForwardOutput
|
|
47
60
|
|
48
61
|
# Get nodes (a regular_node and a standby_node if available) using hash algorithm
|
49
62
|
def nodes(tag)
|
50
|
-
hash_key = @
|
63
|
+
hash_key = @hash_key_slice ? perform_hash_key_slice(tag) : tag
|
51
64
|
regular_index = get_index(hash_key, regular_nodes.size)
|
52
65
|
standby_index = standby_nodes.size > 0 ? get_index(hash_key, standby_nodes.size) : 0
|
53
66
|
[regular_nodes[regular_index], standby_nodes[standby_index]].compact
|
@@ -59,21 +72,9 @@ class Fluent::HashForwardOutput < Fluent::ForwardOutput
|
|
59
72
|
MurmurHash3::V32.str_hash(key) % size
|
60
73
|
end
|
61
74
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
def expand_placeholder(str, tag)
|
67
|
-
struct = UndefOpenStruct.new
|
68
|
-
struct.tag = tag
|
69
|
-
struct.tags = tag.split('.')
|
70
|
-
str = str.gsub(/\$\{([^}]+)\}/, '#{\1}') # ${..} => #{..}
|
71
|
-
eval "\"#{str}\"", struct.instance_eval { binding }
|
72
|
-
end
|
73
|
-
|
74
|
-
class UndefOpenStruct < OpenStruct
|
75
|
-
(Object.instance_methods).each do |m|
|
76
|
-
undef_method m unless m.to_s =~ /^__|respond_to_missing\?|object_id|public_methods|instance_eval|method_missing|define_singleton_method|respond_to\?|new_ostruct_member/
|
77
|
-
end
|
75
|
+
def perform_hash_key_slice(tag)
|
76
|
+
tags = tag.split('.')
|
77
|
+
sliced = tags[@hash_key_slice_lindex..@hash_key_slice_rindex]
|
78
|
+
return sliced.nil? ? "" : sliced.join('.')
|
78
79
|
end
|
79
80
|
end
|
@@ -29,6 +29,73 @@ describe Fluent::HashForwardOutput do
|
|
29
29
|
context 'default behavior' do
|
30
30
|
it { lambda{ driver }.should_not raise_error }
|
31
31
|
end
|
32
|
+
|
33
|
+
describe 'bad hash_key_slice' do
|
34
|
+
context 'string' do
|
35
|
+
let(:config) { CONFIG + %[hash_key_slice a..b] }
|
36
|
+
it { lambda{ driver }.should raise_error(Fluent::ConfigError) }
|
37
|
+
end
|
38
|
+
|
39
|
+
context 'no rindex' do
|
40
|
+
let(:config) { CONFIG + %[hash_key_slice 0..] }
|
41
|
+
it { lambda{ driver }.should raise_error(Fluent::ConfigError) }
|
42
|
+
end
|
43
|
+
|
44
|
+
context 'no lindex' do
|
45
|
+
let(:config) { CONFIG + %[hash_key_slice ..1] }
|
46
|
+
it { lambda{ driver }.should raise_error(Fluent::ConfigError) }
|
47
|
+
end
|
48
|
+
|
49
|
+
context 'bad format' do
|
50
|
+
let(:config) { CONFIG + %[hash_key_slice 0,1] }
|
51
|
+
it { lambda{ driver }.should raise_error(Fluent::ConfigError) }
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe 'test perform_hash_key_slice' do
|
57
|
+
# actually the same behavior with ruby Array, so just conforming ruby Array#slice
|
58
|
+
let(:tag) { 'tag0.tag1' }
|
59
|
+
context 'larger than tags size' do
|
60
|
+
let(:config) { CONFIG + %[hash_key_slice 1..10] }
|
61
|
+
it { expect(driver.instance.perform_hash_key_slice(tag)).to eq('tag1') }
|
62
|
+
end
|
63
|
+
|
64
|
+
context 'rindex is smaller than lindex' do
|
65
|
+
let(:config) { CONFIG + %[hash_key_slice 1..0] }
|
66
|
+
it { expect(driver.instance.perform_hash_key_slice(tag)).to eq('') }
|
67
|
+
end
|
68
|
+
|
69
|
+
context 'rindex is -1' do
|
70
|
+
let(:config) { CONFIG + %[hash_key_slice 0..-1] }
|
71
|
+
it { expect(driver.instance.perform_hash_key_slice(tag)).to eq(tag) }
|
72
|
+
end
|
73
|
+
|
74
|
+
context 'rindex is -2' do
|
75
|
+
let(:config) { CONFIG + %[hash_key_slice 0..-2] }
|
76
|
+
it { expect(driver.instance.perform_hash_key_slice(tag)).to eq('tag0') }
|
77
|
+
end
|
78
|
+
|
79
|
+
context 'rindex is large negative integer' do
|
80
|
+
let(:config) { CONFIG + %[hash_key_slice 0..-10] }
|
81
|
+
it { expect(driver.instance.perform_hash_key_slice(tag)).to eq('') }
|
82
|
+
end
|
83
|
+
|
84
|
+
context 'lindex is -1' do
|
85
|
+
let(:config) { CONFIG + %[hash_key_slice -1..10] }
|
86
|
+
it { expect(driver.instance.perform_hash_key_slice(tag)).to eq('tag1') }
|
87
|
+
end
|
88
|
+
|
89
|
+
context 'lindex is -2' do
|
90
|
+
let(:config) { CONFIG + %[hash_key_slice -2..10] }
|
91
|
+
it { expect(driver.instance.perform_hash_key_slice(tag)).to eq(tag) }
|
92
|
+
end
|
93
|
+
|
94
|
+
context 'lindex is large negatize integer' do
|
95
|
+
# this behavior looks wierd for me
|
96
|
+
let(:config) { CONFIG + %[hash_key_slice -3..10] }
|
97
|
+
it { expect(driver.instance.perform_hash_key_slice(tag)).to eq('') }
|
98
|
+
end
|
32
99
|
end
|
33
100
|
|
34
101
|
describe 'test hashing' do
|
@@ -57,10 +124,10 @@ describe Fluent::HashForwardOutput do
|
|
57
124
|
end
|
58
125
|
end
|
59
126
|
|
60
|
-
context 'test
|
127
|
+
context 'test hash_key_slice' do
|
61
128
|
let(:tag1) { 'test.tag1' }
|
62
129
|
let(:tag2) { 'test.tag2' }
|
63
|
-
let(:config) { CONFIG + %[
|
130
|
+
let(:config) { CONFIG + %[hash_key_slice 0..-2] }
|
64
131
|
before do
|
65
132
|
@node1 = driver.instance.nodes(tag1).first
|
66
133
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fluent-plugin-hash-forward
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ryosuke IWANAGA
|
@@ -105,6 +105,7 @@ extensions: []
|
|
105
105
|
extra_rdoc_files: []
|
106
106
|
files:
|
107
107
|
- .gitignore
|
108
|
+
- CHANGELOG.md
|
108
109
|
- Gemfile
|
109
110
|
- README.md
|
110
111
|
- Rakefile
|