fluent-mixin-config-placeholders 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in fluent-mixin-config-placeholders.gemspec
4
+ gemspec
@@ -0,0 +1,13 @@
1
+ Copyright (c) 2012- TAGOMORI Satoshi
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
@@ -0,0 +1,42 @@
1
+ # Fluent::Mixin::ConfigPlaceholders
2
+
3
+ Fluent::Mixin::ConfigPlaceHolders provide some placeholders to fluentd plugins that includes this mix-in. Placeholders below are expanded in 'super' of including plugin's #configure method.
4
+
5
+ Available placeholders are:
6
+
7
+ * hostname (${hostname} or \_\_HOSTNAME\_\_)
8
+ * you can specify hostname string explicitly on 'hostname' parameter
9
+ * random uuid (${uuid}, ${uuid:random}, \_\_UUID\_\_ or \_\_UUID\_RANDOM\_\_)
10
+ * hostname string based uuid (${uuid:hostname} or \_\_UUID\_HOSTNAME\_\_)
11
+ * timestamp based uuid (${uuid:timestamp} or \_\_UUID\_TIMESTAMP\_\_)
12
+
13
+ ## Usage
14
+
15
+ In plugin (both of input and output), just include mixin.
16
+
17
+ class FooInput < Fluent::Input
18
+ Fluent::Plugin.register_input('foo', self)
19
+
20
+ config_param :tag, :string
21
+
22
+ include Fluent::Mixin::ConfigPlaceholders
23
+
24
+ def configure(conf)
25
+ super # MUST call 'super' at first!
26
+
27
+ @tag #=> here, you can get string replaced '${hostname}' into actual hostname
28
+ end
29
+
30
+ # ...
31
+ end
32
+
33
+ You can use this feature for tags for each fluentd node, paths for remote storage services like /root/${hostname}/access_log or non-race-condition paths like /files/${uuid:random}.
34
+
35
+ ## AUTHORS
36
+
37
+ * TAGOMORI Satoshi <tagomoris@gmail.com>
38
+
39
+ ## LICENSE
40
+
41
+ * Copyright: Copyright (c) 2012- tagomoris
42
+ * License: Apache License, Version 2.0
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+
4
+ require 'rake/testtask'
5
+ Rake::TestTask.new(:test) do |test|
6
+ test.libs << 'lib' << 'test'
7
+ test.pattern = 'test/**/test_*.rb'
8
+ test.verbose = true
9
+ end
10
+
11
+ task :default => :test
@@ -0,0 +1,20 @@
1
+ # -*- encoding: utf-8 -*-
2
+ Gem::Specification.new do |gem|
3
+ gem.name = "fluent-mixin-config-placeholders"
4
+ gem.version = "0.1.0"
5
+ gem.authors = ["TAGOMORI Satoshi"]
6
+ gem.email = ["tagomoris@gmail.com"]
7
+ gem.description = %q{to add various placeholders for plugin configurations}
8
+ gem.summary = %q{Configuration syntax extension mixin for fluentd plugin}
9
+ gem.homepage = "https://github.com/tagomoris/fluent-mixin-config-placeholders"
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
+ gem.require_paths = ["lib"]
15
+
16
+ gem.add_development_dependency "fluentd"
17
+ gem.add_development_dependency "uuidtools"
18
+ gem.add_runtime_dependency "fluentd"
19
+ gem.add_runtime_dependency "uuidtools"
20
+ end
@@ -0,0 +1,74 @@
1
+ require 'fluent/config'
2
+ require 'uuidtools'
3
+
4
+ module Fluent
5
+ module Mixin
6
+ module ConfigPlaceholders
7
+ attr_accessor :hostname
8
+
9
+ # ${hostname}, __HOSTNAME__
10
+
11
+ # ${uuid} or ${uuid:random} , __UUID__ or __UUID_RANDOM__
12
+ # UUIDTools::UUID.random_create
13
+ # => #<UUID:0x19013a UUID:984265dc-4200-4f02-ae70-fe4f48964159>
14
+
15
+ # ${uuid:hostname} , __UUID_HOSTNAME__
16
+ # UUIDTools::UUID.sha1_create(UUIDTools::UUID_DNS_NAMESPACE, "www.widgets.com")
17
+ # => #<UUID:0x2a0116 UUID:21f7f8de-8051-5b89-8680-0195ef798b6a>
18
+
19
+ # ${uuid:timestamp} , __UUID_TIMESTAMP__
20
+ # UUIDTools::UUID.timestamp_create
21
+ # => #<UUID:0x2adfdc UUID:64a5189c-25b3-11da-a97b-00c04fd430c8>
22
+
23
+ def uuid_random
24
+ UUIDTools::UUID.random_create.to_s
25
+ end
26
+
27
+ def uuid_hostname(hostname)
28
+ UUIDTools::UUID.sha1_create(UUIDTools::UUID_DNS_NAMESPACE, hostname).to_s
29
+ end
30
+
31
+ def uuid_timestamp
32
+ UUIDTools::UUID.timestamp_create.to_s
33
+ end
34
+
35
+ def replace(map, value)
36
+ map.reduce(value){|r,p| r.gsub(p[0], p[1].call())}
37
+ end
38
+
39
+ def configure(conf)
40
+ # Element#has_key? inserts key name into 'used' list, so we should escape that method...
41
+ hostname = conf.keys.include?('hostname') ? conf['hostname'] : `hostname`.chomp
42
+
43
+ mapping = {
44
+ '${hostname}' => lambda{ hostname },
45
+ '__HOSTNAME__' => lambda{ hostname },
46
+ '${uuid}' => lambda{ uuid_random() },
47
+ '__UUID__' => lambda{ uuid_random() },
48
+ '${uuid:random}' => lambda{ uuid_random() },
49
+ '__UUID_RANDOM__' => lambda{ uuid_random() },
50
+ '${uuid:hostname}' => lambda { uuid_hostname(hostname) },
51
+ '__UUID_HOSTNAME__' => lambda { uuid_hostname(hostname) },
52
+ '${uuid:timestamp}' => lambda { uuid_timestamp() },
53
+ '__UUID_TIMESTAMP__' => lambda { uuid_timestamp() },
54
+ }
55
+
56
+ def check_element(map,c)
57
+ c.arg = replace(map, c.arg)
58
+ c.keys.each do |k|
59
+ v = c.fetch(k, nil)
60
+ if v and v.is_a? String
61
+ c[k] = replace(map, v)
62
+ end
63
+ end
64
+ c.elements.each{|e| check_element(map,e)}
65
+ end
66
+
67
+ check_element(mapping,conf)
68
+
69
+ super
70
+ end
71
+
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,30 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'test/unit'
11
+
12
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
13
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
14
+
15
+ require 'fluent/test'
16
+ unless ENV.has_key?('VERBOSE')
17
+ nulllogger = Object.new
18
+ nulllogger.instance_eval {|obj|
19
+ def method_missing(method, *args)
20
+ # pass
21
+ end
22
+ }
23
+ $log = nulllogger
24
+ end
25
+
26
+ require 'fluent/mixin/config_placeholders'
27
+ require_relative 'plugin'
28
+
29
+ class Test::Unit::TestCase
30
+ end
@@ -0,0 +1,159 @@
1
+ require 'helper'
2
+
3
+ class ConfigPlaceholdersTest < Test::Unit::TestCase
4
+ def create_plugin_instances(conf)
5
+ [
6
+ Fluent::ConfigPlaceholdersTest0Input, Fluent::ConfigPlaceholdersTest1Input, Fluent::ConfigPlaceholdersTest2Input
7
+ ].map{|klass| Fluent::Test::InputTestDriver.new(klass).configure(conf).instance }
8
+ end
9
+
10
+ def test_unused
11
+ conf = %[
12
+ tag HOGE
13
+ path POSPOSPOS
14
+ ]
15
+ p = Fluent::Test::InputTestDriver.new(Fluent::ConfigPlaceholdersTest2Input).configure(conf).instance
16
+ assert_equal ['tag','path'], p.conf.used
17
+
18
+ conf = %[
19
+ tag HOGE
20
+ path POSPOSPOS
21
+ ]
22
+ p = Fluent::Test::InputTestDriver.new(Fluent::ConfigPlaceholdersTestXInput).configure(conf).instance
23
+ assert_equal [], p.conf.used
24
+
25
+ conf = %[
26
+ tag HOGE
27
+ path POSPOSPOS ${hostname} MOGEMOGE
28
+ ]
29
+ p = Fluent::Test::InputTestDriver.new(Fluent::ConfigPlaceholdersTestXInput).configure(conf).instance
30
+ assert_equal [], p.conf.used
31
+ end
32
+
33
+ def test_hostname
34
+ conf = %[
35
+ hostname testing.local
36
+ tag out.${hostname}
37
+ path /path/to/file.__HOSTNAME__.txt
38
+ ]
39
+ p1, p2, p3 = create_plugin_instances(conf)
40
+
41
+ assert_equal 'out.${hostname}', p1.tag
42
+ assert_equal 'out.testing.local', p2.tag
43
+ assert_equal 'out.testing.local', p3.tag
44
+
45
+ assert_equal '/path/to/file.__HOSTNAME__.txt', p1.path
46
+ assert_equal '/path/to/file.testing.local.txt', p2.path
47
+ assert_equal '/PATH/TO/FILE.TESTING.LOCAL.TXT', p3.path
48
+ end
49
+
50
+ PATH_CHECK_REGEXP = Regexp.compile('^/path/to/file\.[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}.txt$')
51
+ PATH_CHECK_REGEXP2 = Regexp.compile('^/PATH/TO/FILE\.[0-9A-F]{8}-([0-9A-F]{4}-){3}[0-9A-F]{12}.TXT$')
52
+
53
+ def test_uuid_random
54
+ conf1 = %[
55
+ tag test.out
56
+ path /path/to/file.${uuid}.txt
57
+ ]
58
+ p1, p2, p3 = create_plugin_instances(conf1)
59
+ assert_match PATH_CHECK_REGEXP, p2.path
60
+ assert_match PATH_CHECK_REGEXP2, p3.path
61
+
62
+ conf2 = %[
63
+ tag test.out
64
+ path /path/to/file.${uuid:random}.txt
65
+ ]
66
+ p1, p2, p3 = create_plugin_instances(conf2)
67
+ assert_match PATH_CHECK_REGEXP, p2.path
68
+ assert_match PATH_CHECK_REGEXP2, p3.path
69
+
70
+ conf3 = %[
71
+ tag test.out
72
+ path /path/to/file.__UUID__.txt
73
+ ]
74
+ p1, p2, p3 = create_plugin_instances(conf3)
75
+ assert_match PATH_CHECK_REGEXP, p2.path
76
+ assert_match PATH_CHECK_REGEXP2, p3.path
77
+
78
+ conf4 = %[
79
+ tag test.out
80
+ path /path/to/file.__UUID__.txt
81
+ ]
82
+ p1, p2, p3 = create_plugin_instances(conf4)
83
+ assert_match PATH_CHECK_REGEXP, p2.path
84
+ assert_match PATH_CHECK_REGEXP2, p3.path
85
+ end
86
+
87
+ PATH_CHECK_H_REGEXP = Regexp.compile('^/path/to/file\.[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}.log$')
88
+ PATH_CHECK_H_REGEXP2 = Regexp.compile('^/PATH/TO/FILE\.[0-9A-F]{8}-([0-9A-F]{4}-){3}[0-9A-F]{12}.LOG$')
89
+
90
+ def test_uuid_hostname
91
+ conf1 = %[
92
+ tag test.out
93
+ path /path/to/file.${uuid:hostname}.log
94
+ ]
95
+ p1, p2, p3 = create_plugin_instances(conf1)
96
+ assert_match PATH_CHECK_H_REGEXP, p2.path
97
+ assert_equal '/path/to/file.87577bd5-6d8c-5dff-8988-0bc01cb8ed53.log', p2.path
98
+ assert_match PATH_CHECK_H_REGEXP2, p3.path
99
+ assert_equal '/PATH/TO/FILE.87577BD5-6D8C-5DFF-8988-0BC01CB8ED53.LOG', p3.path
100
+
101
+ conf2 = %[
102
+ tag test.out
103
+ path /path/to/file.__UUID_HOSTNAME__.log
104
+ ]
105
+ p1, p2, p3 = create_plugin_instances(conf2)
106
+ assert_match PATH_CHECK_H_REGEXP, p2.path
107
+ assert_equal '/path/to/file.87577bd5-6d8c-5dff-8988-0bc01cb8ed53.log', p2.path
108
+ assert_match PATH_CHECK_H_REGEXP2, p3.path
109
+ assert_equal '/PATH/TO/FILE.87577BD5-6D8C-5DFF-8988-0BC01CB8ED53.LOG', p3.path
110
+ end
111
+
112
+ PATH_CHECK_T_REGEXP = Regexp.compile('^/path/to/file\.[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}.out$')
113
+ PATH_CHECK_T_REGEXP2 = Regexp.compile('^/PATH/TO/FILE\.[0-9A-F]{8}-([0-9A-F]{4}-){3}[0-9A-F]{12}.OUT$')
114
+
115
+ def test_uuid_hostname
116
+ conf1 = %[
117
+ tag test.out
118
+ path /path/to/file.${uuid:timestamp}.out
119
+ ]
120
+ p1, p2, p3 = create_plugin_instances(conf1)
121
+ assert_match PATH_CHECK_T_REGEXP, p2.path
122
+ assert_match PATH_CHECK_T_REGEXP2, p3.path
123
+
124
+ conf2 = %[
125
+ tag test.out
126
+ path /path/to/file.__UUID_HOSTNAME__.out
127
+ ]
128
+ p1, p2, p3 = create_plugin_instances(conf2)
129
+ assert_match PATH_CHECK_T_REGEXP, p2.path
130
+ assert_match PATH_CHECK_T_REGEXP2, p3.path
131
+ end
132
+
133
+ def test_nested
134
+ conf = %[
135
+ hostname test.host.local
136
+ tag test.out
137
+ path /path/to/file.log
138
+ <config ${hostname}>
139
+ var val1.${uuid:hostname}
140
+ <group>
141
+ field value.1.${uuid:hostname}
142
+ </group>
143
+ <group>
144
+ field value.2.__UUID_HOSTNAME__
145
+ </group>
146
+ </config>
147
+ ]
148
+ require 'uuidtools'
149
+ uuid = UUIDTools::UUID.sha1_create(UUIDTools::UUID_DNS_NAMESPACE, "test.host.local").to_s
150
+
151
+ p1, p2, p3 = create_plugin_instances(conf)
152
+ assert_equal "config", p3.conf.elements.first.name
153
+ assert_equal "test.host.local", p3.conf.elements.first.arg
154
+ assert_equal "val1." + uuid, p3.conf.elements.first['var']
155
+ assert_equal "group", p3.conf.elements.first.elements[0].name
156
+ assert_equal "value.1." + uuid, p3.conf.elements.first.elements[0]['field']
157
+ assert_equal "value.2." + uuid, p3.conf.elements.first.elements[1]['field']
158
+ end
159
+ end
@@ -0,0 +1,53 @@
1
+ class Fluent::ConfigPlaceholdersTestXInput < Fluent::Input
2
+ Fluent::Plugin.register_input('config_placeholder_test_x', self)
3
+
4
+ attr_accessor :conf
5
+ def configure(conf)
6
+ super
7
+
8
+ @conf = conf
9
+ end
10
+ end
11
+
12
+ class Fluent::ConfigPlaceholdersTest0Input < Fluent::Input
13
+ Fluent::Plugin.register_input('config_placeholder_test_0', self)
14
+
15
+ config_param :tag, :string
16
+ config_param :path, :string
17
+
18
+ attr_accessor :conf
19
+
20
+ def configure(conf)
21
+ super
22
+
23
+ @conf = conf
24
+ end
25
+ end
26
+
27
+ class Fluent::ConfigPlaceholdersTest1Input < Fluent::Input
28
+ Fluent::Plugin.register_input('config_placeholder_test_1', self)
29
+
30
+ config_param :tag, :string
31
+ config_param :path, :string
32
+
33
+ include Fluent::Mixin::ConfigPlaceholders
34
+ end
35
+
36
+ class Fluent::ConfigPlaceholdersTest2Input < Fluent::Input
37
+ Fluent::Plugin.register_input('config_placeholder_test_2', self)
38
+
39
+ config_param :tag, :string
40
+ config_param :path, :string
41
+
42
+ include Fluent::Mixin::ConfigPlaceholders
43
+
44
+ attr_accessor :conf
45
+
46
+ def configure(conf)
47
+ super
48
+
49
+ @path.upcase!
50
+
51
+ @conf = conf
52
+ end
53
+ end
metadata ADDED
@@ -0,0 +1,122 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fluent-mixin-config-placeholders
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - TAGOMORI Satoshi
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-08-20 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: fluentd
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: uuidtools
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: fluentd
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: uuidtools
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :runtime
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ description: to add various placeholders for plugin configurations
79
+ email:
80
+ - tagomoris@gmail.com
81
+ executables: []
82
+ extensions: []
83
+ extra_rdoc_files: []
84
+ files:
85
+ - .gitignore
86
+ - Gemfile
87
+ - LICENSE.txt
88
+ - README.md
89
+ - Rakefile
90
+ - fluent-mixin-config-placeholders.gemspec
91
+ - lib/fluent/mixin/config_placeholders.rb
92
+ - test/helper.rb
93
+ - test/mixin/test_config_placeholders.rb
94
+ - test/plugin.rb
95
+ homepage: https://github.com/tagomoris/fluent-mixin-config-placeholders
96
+ licenses: []
97
+ post_install_message:
98
+ rdoc_options: []
99
+ require_paths:
100
+ - lib
101
+ required_ruby_version: !ruby/object:Gem::Requirement
102
+ none: false
103
+ requirements:
104
+ - - ! '>='
105
+ - !ruby/object:Gem::Version
106
+ version: '0'
107
+ required_rubygems_version: !ruby/object:Gem::Requirement
108
+ none: false
109
+ requirements:
110
+ - - ! '>='
111
+ - !ruby/object:Gem::Version
112
+ version: '0'
113
+ requirements: []
114
+ rubyforge_project:
115
+ rubygems_version: 1.8.21
116
+ signing_key:
117
+ specification_version: 3
118
+ summary: Configuration syntax extension mixin for fluentd plugin
119
+ test_files:
120
+ - test/helper.rb
121
+ - test/mixin/test_config_placeholders.rb
122
+ - test/plugin.rb