fluentd-plugin-cassandra-cqlfunction 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 3094462b950e5bcfa5e519cdd12a1d6aa5ab11de
4
+ data.tar.gz: '0258a672d85301f78ce523605e35bfa7f79021a9'
5
+ SHA512:
6
+ metadata.gz: d45322120cc5230c15412810f4581b597f76e82a9e4c2cd123f6d13784eeaf003f6cf166e1f024ae5f478403fb9fd3b7bc8f019b1886d731bcfca0d2971d1304
7
+ data.tar.gz: 302e8c634cf70714f8b1e5a1b29f96b962fc5fe499fc7890c4910b52ea59267c82aac36b05c4c494beffbbfe07ae7d24f2688455837354079ae971125790afbd
data/.rspec ADDED
@@ -0,0 +1,4 @@
1
+ --color
2
+ --format documentation
3
+ --backtrace
4
+ --default_path spec
@@ -0,0 +1,5 @@
1
+ # configure code coverage
2
+ SimpleCov.start do
3
+ # exclude directories and files
4
+ add_filter "/spec/"
5
+ end
data/Gemfile ADDED
@@ -0,0 +1,13 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gem 'fluentd', '>=0.12.29'
4
+ gem 'cassandra-driver', '>=3.0.3'
5
+
6
+ group :development, :test do
7
+ gem 'rdoc', '>=3.12'
8
+ gem 'bundler', '>=1.0.0'
9
+ gem 'jeweler', '>=1.8.4'
10
+ gem 'rspec', '>=0'
11
+ gem 'simplecov'
12
+ gem 'test-unit', '>=0'
13
+ end
@@ -0,0 +1,29 @@
1
+ Copyright © 2016 by Yaroslav Lukyanov (c_sharp@mail.ru)
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions
6
+ are met:
7
+
8
+ * Redistributions of source code must retain the above copyright
9
+ notice, this list of conditions and the following disclaimer.
10
+ * Redistributions in binary form must reproduce the above copyright
11
+ notice, this list of conditions and the following disclaimer in
12
+ the documentation and/or other materials provided with the
13
+ distribution.
14
+ * Neither the name of the copyright holder nor the names of its
15
+ contributors may be used to endorse or promote products derived
16
+ from this software without specific prior written permission.
17
+
18
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21
+ FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22
+ COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24
+ BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28
+ ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29
+ POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,75 @@
1
+ # Cassandra plugin for Fluentd
2
+
3
+ Cassandra output plugin for Fluentd.
4
+
5
+ Implemented using the Datastax Ruby Driver for Apache Cassandra gem and targets [CQL3](https://docs.datastax.com/en/cql/3.3/)
6
+ and Cassandra 1.2 - 3.x
7
+
8
+ # Installation
9
+
10
+ via RubyGems : https://rubygems.org/gems/fluentd-plugin-cassandra-cqlfunction
11
+
12
+ fluent-gem install fluentd-plugin-cassandra-cqlfunction
13
+
14
+ ## Fluentd.conf Configuration
15
+ ### Filter Plugin:
16
+ <filter **>
17
+ @type cassandra_selector # fluent filter plugin
18
+ host 127.0.0.1,127.0.0.2 # default => 127.0.0.1
19
+ port 9042 # default => 9092
20
+ username # default => null
21
+ password # default => null
22
+ connect_timeout # default => 10 (sec)
23
+ keyspace ex # cassandra keyspace
24
+ tablename tb_ex # cassandra table
25
+ field fieldA,fieldB # select field normal
26
+ field_json fieldC # select field json string on base(ex fieldC='{"a":"1"}')
27
+ where_condition fieldA='xxx' and fieldB=':keyfrominput;' # keyfrominput (fieldB=':a;' --> fieldB='1')
28
+ </filter>
29
+
30
+ ### ex Filter ::
31
+ input -> {'a':'1'}
32
+ output 1 rec -> {'a':'1', 'fieldA':'xxx', 'fieldB':'yyy'}
33
+ output 2+ rec -> {'a':'1', 'data_cassandra': [{fieldA':'xxx', 'fieldB':'yyy'},{fieldA':'aaa', 'fieldB':'bbb'}]}
34
+
35
+ ### Output Plugin:
36
+ <match **>
37
+ @type cassandra_upsert
38
+ host 127.0.0.1,127.0.0.2
39
+ port 9042
40
+ username # default => null
41
+ password # default => null
42
+ connect_timeout # default => 10 (sec)
43
+ keyspace ex
44
+ tablename tb_ex
45
+ case_insert_value fieldPk='xxx', fieldB=':keyfrominput;' #For insert case
46
+ case_update_value fieldA='xxx', fieldB=':keyfrominput;' #For update case
47
+ where_condition_upd fieldPk='xxx' or fieldPk=':keyfrominput;'
48
+ </match>
49
+
50
+ <match **>
51
+ @type cassandra_insert
52
+ host 127.0.0.1,127.0.0.2
53
+ port 9042
54
+ username # default => null
55
+ password # default => null
56
+ connect_timeout # default => 10 (sec)
57
+
58
+ keyspace ex
59
+ tablename tb_ex
60
+ insert_value fieldPk='xxx', fieldB=':keyfrominput;'
61
+ </match>
62
+
63
+ <match **>
64
+ @type cassandra_update
65
+ host 127.0.0.1,127.0.0.2
66
+ port 9092
67
+ username # default => null
68
+ password # default => null
69
+ connect_timeout # default => 10 (sec)
70
+
71
+ keyspace ex
72
+ tablename tb_ex
73
+ update_value fieldPk='xxx', fieldB=':keyfrominput;'
74
+ where_condition_upd fieldPk='xxx' or fieldPk=':keyfrominput;'
75
+ </match>
@@ -0,0 +1,51 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+
6
+ begin
7
+ Bundler.setup(:default, :development)
8
+ rescue Bundler::BundlerError => e
9
+ $stderr.puts e.message
10
+ $stderr.puts 'Run `bundle install` to install missing gems'
11
+ exit e.status_code
12
+ end
13
+
14
+ require 'rake'
15
+ require 'jeweler'
16
+
17
+ Jeweler::Tasks.new do |gem|
18
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
19
+ gem.name = 'fluentd-plugin-cassandra-cqlfunction'
20
+ gem.homepage = 'https://github.com/gozzip2009/fluentd-plugin-cassandra-cqlfunction.git'
21
+ gem.license = 'BSD-3-Clause'
22
+ gem.summary = 'Fluent selector filter plugin for Cassandra'
23
+ gem.description = 'Fluent selector filter plugin for Cassandra via Datastax Ruby Driver for Apache Cassandra'
24
+ gem.email = 'got@gmail.com'
25
+ gem.authors = ['Got jirayu']
26
+ # dependencies defined in Gemfile
27
+ end
28
+
29
+ Jeweler::RubygemsDotOrgTasks.new
30
+
31
+ require 'rdoc/task'
32
+
33
+ Rake::RDocTask.new do |rdoc|
34
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
35
+
36
+ rdoc.rdoc_dir = 'rdoc'
37
+ rdoc.title = "fluentd-plugin-cassandra-cqlfunction #{version}"
38
+ rdoc.rdoc_files.include('README*')
39
+ rdoc.rdoc_files.include('lib/**/*.rb')
40
+ end
41
+
42
+ # Get spec rake tasks working in RSpec 2.0
43
+ require 'rspec/core/rake_task'
44
+
45
+ desc 'Default: run specs.'
46
+ task :default => :spec
47
+
48
+ desc 'Run specs'
49
+ RSpec::Core::RakeTask.new do |t|
50
+
51
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.0.1
@@ -0,0 +1,75 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+ # stub: fluentd-plugin-cassandra-cqlfunction 1.0.0 ruby lib
6
+
7
+ $:.push File.expand_path('../lib', __FILE__)
8
+ Gem::Specification.new do |s|
9
+ s.name = "fluentd-plugin-cassandra-cqlfunction".freeze
10
+ s.version = "1.1.1"
11
+ s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
12
+ s.require_paths = ["lib".freeze]
13
+ s.authors = ["Got jirayu".freeze]
14
+ s.date = "2016-11-12"
15
+ s.description = "Fluent output plugin for Cassandra via Datastax Ruby Driver for Apache Cassandra".freeze
16
+ s.email = "got@gmail.com".freeze
17
+ s.extra_rdoc_files = [
18
+ "LICENSE.txt",
19
+ "README.md"
20
+ ]
21
+ s.files = [
22
+ ".rspec",
23
+ ".simplecov",
24
+ "Gemfile",
25
+ "LICENSE.txt",
26
+ "README.md",
27
+ "Rakefile",
28
+ "VERSION",
29
+ "fluentd-plugin-cassandra-cqlfunction.gemspec",
30
+ "spec/spec.opts",
31
+ "spec/spec_helper.rb",
32
+ "lib/fluent/plugin/filter_cassandra_selector.rb",
33
+ "lib/fluent/plugin/out_cassandra_upsert.rb",
34
+ "lib/fluent/plugin/out_cassandra_insert.rb",
35
+ "lib/fluent/plugin/out_cassandra_update.rb",
36
+ "lib/fluent/plugin/filter_example.rb",
37
+ "lib/fluent/plugin/utils/cassandra_connection.rb",
38
+ ]
39
+ s.homepage = "https://github.com/gozzip2009/fluentd-plugin-cassandra-cqlfunction".freeze
40
+ s.licenses = ["BSD-3-Clause".freeze]
41
+ s.rubygems_version = "2.6.8".freeze
42
+ s.summary = "Fluent selector filter plugin for Cassandra".freeze
43
+ s.add_development_dependency("test-unit", ["~> 3.1.4"])
44
+
45
+ if s.respond_to? :specification_version then
46
+ s.specification_version = 4
47
+
48
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
49
+ s.add_runtime_dependency(%q<fluentd>.freeze, [">= 0.12.29"])
50
+ s.add_runtime_dependency(%q<cassandra-driver>.freeze, [">= 3.0.3"])
51
+ s.add_development_dependency(%q<rdoc>.freeze, [">= 3.12"])
52
+ s.add_development_dependency(%q<bundler>.freeze, [">= 1.0.0"])
53
+ s.add_development_dependency(%q<jeweler>.freeze, [">= 1.8.4"])
54
+ s.add_development_dependency(%q<rspec>.freeze, [">= 0"])
55
+ s.add_development_dependency(%q<simplecov>.freeze, [">= 0"])
56
+ else
57
+ s.add_dependency(%q<fluentd>.freeze, [">= 0.12.29"])
58
+ s.add_dependency(%q<cassandra-driver>.freeze, [">= 3.0.3"])
59
+ s.add_dependency(%q<rdoc>.freeze, [">= 3.12"])
60
+ s.add_dependency(%q<bundler>.freeze, [">= 1.0.0"])
61
+ s.add_dependency(%q<jeweler>.freeze, [">= 1.8.4"])
62
+ s.add_dependency(%q<rspec>.freeze, [">= 0"])
63
+ s.add_dependency(%q<simplecov>.freeze, [">= 0"])
64
+ end
65
+ else
66
+ s.add_dependency(%q<fluentd>.freeze, [">= 0.12.29"])
67
+ s.add_dependency(%q<cassandra-driver>.freeze, [">= 3.0.3"])
68
+ s.add_dependency(%q<rdoc>.freeze, [">= 3.12"])
69
+ s.add_dependency(%q<bundler>.freeze, [">= 1.0.0"])
70
+ s.add_dependency(%q<jeweler>.freeze, [">= 1.8.4"])
71
+ s.add_dependency(%q<rspec>.freeze, [">= 0"])
72
+ s.add_dependency(%q<simplecov>.freeze, [">= 0"])
73
+ end
74
+ end
75
+
@@ -0,0 +1,161 @@
1
+ require 'fluent/plugin/filter'
2
+ require 'fluent/plugin/utils/cassandra_connection'
3
+
4
+ #module Fluent
5
+ # class Plugin::CassandraSelector < Plugin::Filter
6
+
7
+ class Fluent::CassandraSelector < Fluent::Filter
8
+ Fluent::Plugin.register_filter('cassandra_selector', self)
9
+
10
+ include CassandraConnection
11
+
12
+ config_param :host, :string, :default => '127.0.0.1'
13
+ config_param :port, :integer, :default => 9042
14
+
15
+ config_param :username, :string, :default => nil
16
+ config_param :password, :string, :default => nil
17
+
18
+ config_param :connect_timeout, :integer, :default => 10
19
+
20
+ config_param :field, :string, :default => nil
21
+ config_param :keyspace, :string
22
+ config_param :tablename, :string
23
+ config_param :where_condition, :string, :default => nil
24
+
25
+ config_param :field_json, :string, :default => nil
26
+ def start
27
+ super
28
+ @session ||= get_session(self.host, self.port, self.keyspace, self.connect_timeout, self.username, self.password)
29
+ end # start
30
+
31
+ def shutdown
32
+ super
33
+ @session.close if @session
34
+ end # shutdown
35
+
36
+ def configure(conf)
37
+ super
38
+
39
+ raise ConfigError, "params 'field' or 'field_json' is require least once" if self.field_json.nil? && self.field.nil?
40
+
41
+ end # configure
42
+
43
+ def filter(tag, time, record)
44
+
45
+ dataList = nil
46
+ cql = getCql(record)
47
+
48
+ begin
49
+ dataList = @session.execute(cql)
50
+ rescue Exception => e
51
+ $log.error "Cannot select Cassandra: #{e.message}\nTrace: #{e.backtrace.to_s}"
52
+ raise e
53
+ end
54
+
55
+ if dataList.length == 1
56
+ dataList.each do |row|
57
+ record = prepareRowToHash(row, record)
58
+ end
59
+ elsif dataList.length > 1
60
+ if self.field_json.nil? || self.field_json.empty?
61
+ record["data_cassandra"] = dataList.rows.to_a
62
+ else
63
+ tmpListRec = []
64
+ tmpRec = nil
65
+ dataList.each do |row|
66
+ tmpRec = prepareRowToHash(row,{})
67
+ tmpListRec.push(tmpRec)
68
+ end
69
+
70
+ record["data_cassandra"] = tmpListRec
71
+ end
72
+ end
73
+ record
74
+ end # filter
75
+
76
+ private
77
+
78
+ def prepareRowToHash(row, record)
79
+ if self.field
80
+ self.field.split(",").each do |col|
81
+ record[col] = "#{row[col]}"
82
+ end
83
+ end
84
+
85
+ if self.field_json
86
+ self.field_json.split(",").each do |col|
87
+ record = getDataStrJson("#{row[col]}", record)
88
+ end
89
+ end
90
+ record
91
+ end
92
+
93
+ def getDataStrJson(jsonData, record)
94
+ if jsonData && !jsonData.empty?
95
+ jsonData = eval(jsonData)
96
+
97
+ jsonData.each do |k,v|
98
+ record[k.to_s] = v
99
+ end
100
+ end
101
+
102
+ record
103
+ end # getDataStrJson
104
+
105
+ def getCql(record)
106
+ cql = "select "
107
+ if self.field
108
+ cql += self.field + ","
109
+ end
110
+
111
+ if self.field_json
112
+ cql += self.field_json + ","
113
+ end
114
+
115
+ cql = cql.gsub(/,$/, '')
116
+
117
+ cql += " from #{self.keyspace}.#{self.tablename}"
118
+
119
+ if self.where_condition
120
+ cql += " where "+prepareCondition(record)
121
+ end
122
+
123
+ cql += ";"
124
+
125
+ cql
126
+ end # getCql
127
+
128
+ def prepareCondition(record)
129
+ tmpCondVal = {}
130
+ tmpStr = nil
131
+ count = 0
132
+
133
+ self.where_condition.split(":").each do |str|
134
+ if count > 0
135
+ tmpStr = str.gsub(/(;.*)/, '')
136
+ tmpCondVal[tmpStr] = record[tmpStr]
137
+ end
138
+ count += 1
139
+ end
140
+
141
+ tmpStr = self.where_condition
142
+ tmpCondVal.each do |k,v|
143
+ tmpStr = tmpStr.gsub(k,v)
144
+ end
145
+
146
+ tmpStr = tmpStr.gsub(':','')
147
+ tmpStr = tmpStr.gsub(';','')
148
+
149
+ tmpStr
150
+ end # prepareCondition
151
+
152
+ # def filterExample(tag, time, record)
153
+ # sessionExcute = @session
154
+ #
155
+ # sessionExcute.execute("select service_id, golden_id from journey.mobile_state where service_id = '66910000136';").each do |row|
156
+ # record["golden_id"] = "#{row['golden_id']}"
157
+ # end
158
+ #
159
+ # record
160
+ # end filterExample
161
+ end
@@ -0,0 +1,20 @@
1
+ require 'fluent/plugin/filter'
2
+
3
+ class Fluent::ExampleFilter < Fluent::Filter
4
+ Fluent::Plugin.register_filter('example_filter', self)
5
+
6
+ config_param :host, :string
7
+
8
+ def configure(conf)
9
+ super
10
+
11
+ end # configure
12
+
13
+ def filter(tag, time, record)
14
+ if @host
15
+ record["host"] = @host
16
+ end
17
+
18
+ record
19
+ end # filter
20
+ end
@@ -0,0 +1,99 @@
1
+ require 'msgpack'
2
+ require 'fluent/output'
3
+
4
+ module Fluent
5
+ class CassandraInsertor < BufferedOutput
6
+
7
+ Fluent::Plugin.register_output('cassandra_insert', self)
8
+ include CassandraConnection
9
+
10
+ config_param :host, :string, :default => '127.0.0.1'
11
+ config_param :port, :integer, :default => 9042
12
+
13
+ config_param :username, :string, :default => nil
14
+ config_param :password, :string, :default => nil
15
+
16
+ config_param :connect_timeout, :integer, :default => 5
17
+
18
+ config_param :keyspace, :string
19
+ config_param :tablename, :string
20
+
21
+ config_param :insert_value, :string
22
+ def start
23
+ super
24
+ @session ||= get_session(self.host, self.port, self.keyspace, self.connect_timeout, self.username, self.password)
25
+ end # start
26
+
27
+ def shutdown
28
+ super
29
+ @session.close if @session
30
+ end # shutdown
31
+
32
+ def configure(conf)
33
+ super
34
+
35
+ @insertValue = self.insert_value
36
+ end # configure
37
+
38
+ def format(tag, time, record)
39
+ record.to_msgpack
40
+ end
41
+
42
+ def write(chunk)
43
+ chunk.msgpack_each { |record|
44
+ @insertValue = prepareParameter(@insertValue, record)
45
+ insertCassandra(@insertValue)
46
+ }
47
+ end # write
48
+
49
+ private
50
+
51
+ def insertCassandra(insertVal)
52
+ colIns = []
53
+ valIns = []
54
+ tmpStr = nil
55
+
56
+ insertVal.split(",").each do |str|
57
+ tmpStr = str.split("=")
58
+ colIns.push(tmpStr[0])
59
+ valIns.push(tmpStr[1])
60
+ end
61
+
62
+ cql = "INSERT INTO #{self.keyspace}.#{self.tablename} (#{colIns.join(',')}) VALUES (#{valIns.join(',')});"
63
+
64
+ print cql
65
+
66
+ begin
67
+ @session.execute(cql)
68
+ rescue Exception => e
69
+ $log.error "Cannot insert record Cassandra: #{e.message}\nTrace: #{e.backtrace.to_s}"
70
+
71
+ raise e
72
+ end
73
+ end # insertCassandra
74
+
75
+ def prepareParameter(strOri,record)
76
+ tmpCondVal = {}
77
+ tmpStr = nil
78
+ count = 0
79
+
80
+ strOri.split(":").each do |str|
81
+ if count > 0
82
+ tmpStr = str.gsub(/(;.*)/, '')
83
+ tmpCondVal[tmpStr] = record[tmpStr]
84
+ end
85
+ count += 1
86
+ end
87
+
88
+ tmpCondVal.each do |k,v|
89
+ strOri= strOri.gsub(k,v)
90
+ end
91
+
92
+ strOri = strOri.gsub(':','')
93
+ strOri = strOri.gsub(';','')
94
+
95
+ strOri
96
+ end # prepareParameter
97
+
98
+ end
99
+ end
@@ -0,0 +1,96 @@
1
+ require 'msgpack'
2
+ require 'fluent/output'
3
+
4
+ module Fluent
5
+ class CassandraUpdatetor < BufferedOutput
6
+
7
+ Fluent::Plugin.register_output('cassandra_update', self)
8
+ include CassandraConnection
9
+
10
+ config_param :host, :string, :default => '127.0.0.1'
11
+ config_param :port, :integer, :default => 9042
12
+
13
+ config_param :username, :string, :default => nil
14
+ config_param :password, :string, :default => nil
15
+
16
+ config_param :connect_timeout, :integer, :default => 5
17
+
18
+ config_param :keyspace, :string
19
+ config_param :tablename, :string
20
+
21
+ config_param :update_value, :string
22
+ config_param :where_condition_upd, :string
23
+ def start
24
+ super
25
+ @session ||= get_session(self.host, self.port, self.keyspace, self.connect_timeout, self.username, self.password)
26
+ end # start
27
+
28
+ def shutdown
29
+ super
30
+ @session.close if @session
31
+ end # shutdown
32
+
33
+ def configure(conf)
34
+ super
35
+
36
+ @updateValue = self.update_value
37
+ @whereCondUpd = self.where_condition_upd
38
+ end # configure
39
+
40
+ def format(tag, time, record)
41
+ record.to_msgpack
42
+ end
43
+
44
+ def write(chunk)
45
+ chunk.msgpack_each { |record|
46
+
47
+ whereCondition = prepareParameter(@whereCondUpd, record)
48
+
49
+ @updateValue = prepareParameter(@updateValue, record)
50
+ updateCassandra(@updateValue, whereCondition)
51
+
52
+ }
53
+ end # write
54
+
55
+ private
56
+
57
+ def updateCassandra(updateVal, whereCondition)
58
+
59
+ cql = "update #{self.keyspace}.#{self.tablename} set "
60
+ cql += updateVal + " where " + whereCondition + ";"
61
+
62
+ print cql
63
+ begin
64
+ @session.execute(cql)
65
+ rescue Exception => e
66
+ $log.error "Cannot update record Cassandra: #{e.message}\nTrace: #{e.backtrace.to_s}"
67
+
68
+ raise e
69
+ end
70
+ end # updateCassandra
71
+
72
+ def prepareParameter(strOri,record)
73
+ tmpCondVal = {}
74
+ tmpStr = nil
75
+ count = 0
76
+
77
+ strOri.split(":").each do |str|
78
+ if count > 0
79
+ tmpStr = str.gsub(/(;.*)/, '')
80
+ tmpCondVal[tmpStr] = record[tmpStr]
81
+ end
82
+ count += 1
83
+ end
84
+
85
+ tmpCondVal.each do |k,v|
86
+ strOri= strOri.gsub(k,v)
87
+ end
88
+
89
+ strOri = strOri.gsub(':','')
90
+ strOri = strOri.gsub(';','')
91
+
92
+ strOri
93
+ end # prepareParameter
94
+
95
+ end
96
+ end
@@ -0,0 +1,152 @@
1
+ require 'msgpack'
2
+ require 'fluent/output'
3
+
4
+ module Fluent
5
+ class CassandraUpsertor < BufferedOutput
6
+
7
+ Fluent::Plugin.register_output('cassandra_upsert', self)
8
+ include CassandraConnection
9
+
10
+ config_param :host, :string, :default => '127.0.0.1'
11
+ config_param :port, :integer, :default => 9042
12
+
13
+ config_param :username, :string, :default => nil
14
+ config_param :password, :string, :default => nil
15
+
16
+ config_param :connect_timeout, :integer, :default => 5
17
+
18
+ config_param :keyspace, :string
19
+ config_param :tablename, :string
20
+
21
+ config_param :case_insert_value, :string
22
+ config_param :case_update_value, :string
23
+ config_param :where_condition_upd, :string, :default => nil
24
+
25
+ def start
26
+ super
27
+ @session ||= get_session(self.host, self.port, self.keyspace, self.connect_timeout, self.username, self.password)
28
+ end # start
29
+
30
+ def shutdown
31
+ super
32
+ @session.close if @session
33
+ end # shutdown
34
+
35
+ def configure(conf)
36
+ super
37
+
38
+ # perform validations
39
+ raise ConfigError, "params 'where_condition_upd' is require condition or primarykey for case update" if self.where_condition_upd.nil?
40
+
41
+ @caseInsertValue = self.case_insert_value
42
+ @caseUpdateValue = self.case_update_value
43
+ @whereCondUpd = self.where_condition_upd
44
+ end # configure
45
+
46
+ def format(tag, time, record)
47
+ record.to_msgpack
48
+ end
49
+
50
+ def write(chunk)
51
+ chunk.msgpack_each { |record|
52
+
53
+ whereCondition = prepareParameter(@whereCondUpd, record)
54
+
55
+ cql = "select count(*) from #{self.keyspace}.#{self.tablename}"
56
+ cql += " where " + whereCondition + ";"
57
+
58
+ countRow = nil
59
+ begin
60
+ countRow = @session.execute(cql)
61
+ rescue Exception => e
62
+ $log.error "Cannot select Cassandra: #{e.message}\nTrace: #{e.backtrace.to_s}"
63
+ raise e
64
+ end
65
+
66
+ countRow = getRowCount(countRow)
67
+
68
+ if countRow > 0
69
+ @caseUpdateValue = prepareParameter(@caseUpdateValue, record)
70
+ updateCassandra(@caseUpdateValue, whereCondition)
71
+ else
72
+ @caseInsertValue = prepareParameter(@caseInsertValue, record)
73
+ insertCassandra(@caseInsertValue)
74
+ end
75
+
76
+ }
77
+ end # write
78
+
79
+ private
80
+
81
+ def insertCassandra(insertVal)
82
+ colIns = []
83
+ valIns = []
84
+ tmpStr = nil
85
+
86
+ insertVal.split(",").each do |str|
87
+ tmpStr = str.split("=")
88
+ colIns.push(tmpStr[0])
89
+ valIns.push(tmpStr[1])
90
+ end
91
+
92
+ cql = "INSERT INTO #{self.keyspace}.#{self.tablename} (#{colIns.join(',')}) VALUES (#{valIns.join(',')});"
93
+
94
+ begin
95
+ @session.execute(cql)
96
+ rescue Exception => e
97
+ $log.error "Cannot insert record Cassandra: #{e.message}\nTrace: #{e.backtrace.to_s}"
98
+
99
+ raise e
100
+ end
101
+ end # insertCassandra
102
+
103
+ def updateCassandra(updateVal, whereCondition)
104
+
105
+ cql = "update #{self.keyspace}.#{self.tablename} set "
106
+ cql += updateVal + " where " + whereCondition + ";"
107
+
108
+ begin
109
+ @session.execute(cql)
110
+ rescue Exception => e
111
+ $log.error "Cannot update record Cassandra: #{e.message}\nTrace: #{e.backtrace.to_s}"
112
+
113
+ raise e
114
+ end
115
+ end # updateCassandra
116
+
117
+ def getRowCount(countRow)
118
+ rc = 0
119
+ if countRow.length > 0
120
+ countRow.each do |row|
121
+ rc = "#{row['count']}"
122
+ end
123
+ rc = rc.to_i
124
+ end
125
+ rc
126
+ end # getRowCount
127
+
128
+ def prepareParameter(strOri,record)
129
+ tmpCondVal = {}
130
+ tmpStr = nil
131
+ count = 0
132
+
133
+ strOri.split(":").each do |str|
134
+ if count > 0
135
+ tmpStr = str.gsub(/(;.*)/, '')
136
+ tmpCondVal[tmpStr] = record[tmpStr]
137
+ end
138
+ count += 1
139
+ end
140
+
141
+ tmpCondVal.each do |k,v|
142
+ strOri= strOri.gsub(k,v)
143
+ end
144
+
145
+ strOri = strOri.gsub(':','')
146
+ strOri = strOri.gsub(';','')
147
+
148
+ strOri
149
+ end # prepareParameter
150
+
151
+ end
152
+ end
@@ -0,0 +1,15 @@
1
+ require 'cassandra'
2
+
3
+ module CassandraConnection
4
+
5
+ def get_session(host, port, keyspace, connect_timeout, username, password)
6
+ hostNode = host.split(",")
7
+ if self.username
8
+ cluster = ::Cassandra.cluster(hosts: hostNode, port: port, connect_timeout: connect_timeout, username: username, password: password)
9
+ else
10
+ cluster = ::Cassandra.cluster(hosts: hostNode, port: port, connect_timeout: connect_timeout)
11
+ end
12
+ cluster.connect(keyspace)
13
+ end # get_session
14
+
15
+ end
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format
@@ -0,0 +1,9 @@
1
+ require 'simplecov'
2
+ require 'rspec'
3
+ require 'fluent/test'
4
+
5
+ # require the library files
6
+ Dir["./lib/**/*.rb"].each {|f| require f}
7
+
8
+ # require the shared example files
9
+ Dir["./spec/support/**/*.rb"].each {|f| require f}
metadata ADDED
@@ -0,0 +1,174 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fluentd-plugin-cassandra-cqlfunction
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Got jirayu
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-11-12 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: test-unit
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 3.1.4
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 3.1.4
27
+ - !ruby/object:Gem::Dependency
28
+ name: fluentd
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 0.12.29
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 0.12.29
41
+ - !ruby/object:Gem::Dependency
42
+ name: cassandra-driver
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: 3.0.3
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: 3.0.3
55
+ - !ruby/object:Gem::Dependency
56
+ name: rdoc
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '3.12'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '3.12'
69
+ - !ruby/object:Gem::Dependency
70
+ name: bundler
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: 1.0.0
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: 1.0.0
83
+ - !ruby/object:Gem::Dependency
84
+ name: jeweler
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: 1.8.4
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: 1.8.4
97
+ - !ruby/object:Gem::Dependency
98
+ name: rspec
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: simplecov
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ description: Fluent output plugin for Cassandra via Datastax Ruby Driver for Apache
126
+ Cassandra
127
+ email: got@gmail.com
128
+ executables: []
129
+ extensions: []
130
+ extra_rdoc_files:
131
+ - LICENSE.txt
132
+ - README.md
133
+ files:
134
+ - ".rspec"
135
+ - ".simplecov"
136
+ - Gemfile
137
+ - LICENSE.txt
138
+ - README.md
139
+ - Rakefile
140
+ - VERSION
141
+ - fluentd-plugin-cassandra-cqlfunction.gemspec
142
+ - lib/fluent/plugin/filter_cassandra_selector.rb
143
+ - lib/fluent/plugin/filter_example.rb
144
+ - lib/fluent/plugin/out_cassandra_insert.rb
145
+ - lib/fluent/plugin/out_cassandra_update.rb
146
+ - lib/fluent/plugin/out_cassandra_upsert.rb
147
+ - lib/fluent/plugin/utils/cassandra_connection.rb
148
+ - spec/spec.opts
149
+ - spec/spec_helper.rb
150
+ homepage: https://github.com/gozzip2009/fluentd-plugin-cassandra-cqlfunction
151
+ licenses:
152
+ - BSD-3-Clause
153
+ metadata: {}
154
+ post_install_message:
155
+ rdoc_options: []
156
+ require_paths:
157
+ - lib
158
+ required_ruby_version: !ruby/object:Gem::Requirement
159
+ requirements:
160
+ - - ">="
161
+ - !ruby/object:Gem::Version
162
+ version: '0'
163
+ required_rubygems_version: !ruby/object:Gem::Requirement
164
+ requirements:
165
+ - - ">="
166
+ - !ruby/object:Gem::Version
167
+ version: '0'
168
+ requirements: []
169
+ rubyforge_project:
170
+ rubygems_version: 2.6.14.3
171
+ signing_key:
172
+ specification_version: 4
173
+ summary: Fluent selector filter plugin for Cassandra
174
+ test_files: []