fluent-plugin-postgres 0.0.1

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.
@@ -0,0 +1,18 @@
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
18
+ test.conf
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source :rubygems
2
+
3
+ gemspec
@@ -0,0 +1,13 @@
1
+ Copyright 2013 Uken Games
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,133 @@
1
+ # fluent-plugin-postgres
2
+
3
+
4
+ ## Changes from mysql:
5
+
6
+ - We currently don't suppor json format
7
+ - You need to specify a SQL query
8
+ - Placeholders are numbered (yeah, I know).
9
+
10
+ Other than that, just bear in mind that it's Postgres SQL.
11
+
12
+ ### Quick example
13
+
14
+ <match output.by.sql.*>
15
+ type postgres
16
+ host master.db.service.local
17
+ # port 3306 # default
18
+ database application_logs
19
+ username myuser
20
+ password mypass
21
+ key_names status,bytes,vhost,path,rhost,agent,referer
22
+ sql INSERT INTO accesslog (status,bytes,vhost,path,rhost,agent,referer) VALUES ($1,$2,$3,$4,$5,$6,$7)
23
+ flush_intervals 5s
24
+ </match>
25
+
26
+
27
+
28
+ ## Component
29
+
30
+ ### PostgresOutput
31
+
32
+ Plugin to store Postgres tables over SQL, to each columns per values, or to single column as json.
33
+
34
+ ## Configuration
35
+
36
+ ### MysqlOutput
37
+
38
+ MysqlOutput needs MySQL server's host/port/database/username/password, and INSERT format as SQL, or as table name and columns.
39
+
40
+ <match output.by.sql.*>
41
+ type mysql
42
+ host master.db.service.local
43
+ # port 3306 # default
44
+ database application_logs
45
+ username myuser
46
+ password mypass
47
+ key_names status,bytes,vhost,path,rhost,agent,referer
48
+ sql INSERT INTO accesslog (status,bytes,vhost,path,rhost,agent,referer) VALUES (?,?,?,?,?,?,?)
49
+ flush_intervals 5s
50
+ </match>
51
+
52
+ <match output.by.names.*>
53
+ type mysql
54
+ host master.db.service.local
55
+ database application_logs
56
+ username myuser
57
+ password mypass
58
+ key_names status,bytes,vhost,path,rhost,agent,referer
59
+ table accesslog
60
+ # 'columns' names order must be same with 'key_names'
61
+ columns status,bytes,vhost,path,rhost,agent,referer
62
+ flush_intervals 5s
63
+ </match>
64
+
65
+ Or, insert json into single column.
66
+
67
+ <match output.as.json.*>
68
+ type mysql
69
+ host master.db.service.local
70
+ database application_logs
71
+ username root
72
+ table accesslog
73
+ columns jsondata
74
+ format json
75
+ flush_intervals 5s
76
+ </match>
77
+
78
+ To include time/tag into output, use `include_time_key` and `include_tag_key`, like this:
79
+
80
+ <match output.with.tag.and.time.*>
81
+ type mysql
82
+ host my.mysql.local
83
+ database anydatabase
84
+ username yourusername
85
+ password secret
86
+
87
+ include_time_key yes
88
+ ### default `time_format` is ISO-8601
89
+ # time_format %Y%m%d-%H%M%S
90
+ ### default `time_key` is 'time'
91
+ # time_key timekey
92
+
93
+ include_tag_key yes
94
+ ### default `tag_key` is 'tag'
95
+ # tag_key tagkey
96
+
97
+ table anydata
98
+ key_names time,tag,field1,field2,field3,field4
99
+ sql INSERT INTO baz (coltime,coltag,col1,col2,col3,col4) VALUES (?,?,?,?,?,?)
100
+ </match>
101
+
102
+ Or, for json:
103
+
104
+ <match output.with.tag.and.time.as.json.*>
105
+ type mysql
106
+ host database.local
107
+ database foo
108
+ username root
109
+
110
+ include_time_key yes
111
+ utc # with UTC timezome output (default: localtime)
112
+ time_format %Y%m%d-%H%M%S
113
+ time_key timeattr
114
+
115
+ include_tag_key yes
116
+ tag_key tagattr
117
+ table accesslog
118
+ columns jsondata
119
+ format json
120
+ </match>
121
+ #=> inserted json data into column 'jsondata' with addtional attribute 'timeattr' and 'tagattr'
122
+
123
+ ## TODO
124
+
125
+ * implement 'tag_mapped'
126
+ * dynamic tag based table selection
127
+
128
+ ## Copyright
129
+
130
+ * Copyright
131
+ * Copyright 2013 Uken Games
132
+ * License
133
+ * 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,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+ Gem::Specification.new do |s|
3
+ s.name = 'fluent-plugin-postgres'
4
+ s.version = '0.0.1'
5
+ s.authors = ['TAGOMORI Satoshi', 'Diogo Terror', 'pitr']
6
+ s.email = ['team@uken.com']
7
+ s.description = %q{fluent plugin to insert on PostgreSQL}
8
+ s.summary = %q{fluent plugin to insert on PostgreSQL}
9
+ s.homepage = 'https://github.com/uken/fluent-plugin-postgres'
10
+ s.license = 'Apache 2.0'
11
+
12
+ s.files = `git ls-files`.split($\)
13
+ s.executables = s.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
14
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
15
+ s.require_paths = ['lib']
16
+
17
+ s.add_dependency 'fluentd'
18
+ s.add_dependency 'pg'
19
+
20
+ s.add_development_dependency 'rake'
21
+ end
@@ -0,0 +1,74 @@
1
+ class Fluent::PostgresOutput < Fluent::BufferedOutput
2
+ Fluent::Plugin.register_output('postgres', self)
3
+
4
+ include Fluent::SetTimeKeyMixin
5
+ include Fluent::SetTagKeyMixin
6
+
7
+ config_param :host, :string
8
+ config_param :port, :integer, :default => nil
9
+ config_param :database, :string
10
+ config_param :username, :string
11
+ config_param :password, :string, :default => ''
12
+
13
+ config_param :key_names, :string, :default => nil # nil allowed for json format
14
+ config_param :sql, :string, :default => nil
15
+ config_param :table, :string, :default => nil
16
+ config_param :columns, :string, :default => nil
17
+
18
+ config_param :format, :string, :default => "raw" # or json
19
+
20
+ attr_accessor :handler
21
+
22
+ def initialize
23
+ super
24
+ require 'pg'
25
+ end
26
+
27
+ # We don't currently support mysql's analogous json format
28
+ def configure(conf)
29
+ super
30
+
31
+ if @format == 'json'
32
+ @format_proc = Proc.new{|tag, time, record| record.to_json}
33
+ else
34
+ @key_names = @key_names.split(',')
35
+ @format_proc = Proc.new{|tag, time, record| @key_names.map{|k| record[k]}}
36
+ end
37
+
38
+ if @columns.nil? and @sql.nil?
39
+ raise Fluent::ConfigError, "columns or sql MUST be specified, but missing"
40
+ end
41
+ if @columns and @sql
42
+ raise Fluent::ConfigError, "both of columns and sql are specified, but specify one of them"
43
+ end
44
+ end
45
+
46
+ def start
47
+ super
48
+ end
49
+
50
+ def shutdown
51
+ super
52
+ end
53
+
54
+ def format(tag, time, record)
55
+ [tag, time, @format_proc.call(tag, time, record)].to_msgpack
56
+ end
57
+
58
+ def client
59
+ PG::Connection.new({
60
+ :host => @host, :port => @port,
61
+ :user => @username, :password => @password,
62
+ :dbname => @database
63
+ })
64
+ end
65
+
66
+ def write(chunk)
67
+ handler = self.client
68
+ handler.prepare("write", @sql)
69
+ chunk.msgpack_each { |tag, time, data|
70
+ handler.exec_prepared("write", data)
71
+ }
72
+ handler.close
73
+ end
74
+ end
@@ -0,0 +1,28 @@
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
+ require 'fluent/test'
15
+ unless ENV.has_key?('VERBOSE')
16
+ nulllogger = Object.new
17
+ nulllogger.instance_eval {|obj|
18
+ def method_missing(method, *args)
19
+ # pass
20
+ end
21
+ }
22
+ $log = nulllogger
23
+ end
24
+
25
+ require 'fluent/plugin/out_postgres'
26
+
27
+ class Test::Unit::TestCase
28
+ end
@@ -0,0 +1,107 @@
1
+ require 'helper'
2
+ require 'pg'
3
+
4
+ class PostgresOutputTest < Test::Unit::TestCase
5
+ def setup
6
+ Fluent::Test.setup
7
+ end
8
+
9
+ CONFIG = %[
10
+ host database.local
11
+ database foo
12
+ username bar
13
+ password mogera
14
+ key_names field1,field2,field3
15
+ sql INSERT INTO baz (col1,col2,col3,col4) VALUES (?,?,?,?)
16
+ ]
17
+
18
+ def create_driver(conf=CONFIG, tag='test')
19
+ d = Fluent::Test::BufferedOutputTestDriver.new(Fluent::PostgresOutput, tag).configure(conf)
20
+ d.instance.instance_eval {
21
+ def client
22
+ obj = Object.new
23
+ obj.instance_eval {
24
+ def prepare(*args); true; end
25
+ def exec_prepared(*args); true; end
26
+ def close; true; end
27
+ }
28
+ obj
29
+ end
30
+ }
31
+ d
32
+ end
33
+
34
+ def test_configure_fails_if_both_cols_and_sql_specified
35
+ assert_raise(Fluent::ConfigError) {
36
+ create_driver %[
37
+ host database.local
38
+ database foo
39
+ username bar
40
+ password mogera
41
+ key_names field1,field2,field3
42
+ sql INSERT INTO baz (col1,col2,col3,col4) VALUES (?,?,?,?)
43
+ columns col1,col2,col3,col4
44
+ ]
45
+ }
46
+ end
47
+
48
+ def test_configure_fails_if_neither_cols_or_sql_specified
49
+ assert_raise(Fluent::ConfigError) {
50
+ create_driver %[
51
+ host database.local
52
+ database foo
53
+ username bar
54
+ password mogera
55
+ key_names field1,field2,field3
56
+ ]
57
+ }
58
+ end
59
+
60
+ def test_time_and_tag_key
61
+ d = create_driver %[
62
+ host database.local
63
+ database foo
64
+ username bar
65
+ password mogera
66
+ include_time_key yes
67
+ utc
68
+ include_tag_key yes
69
+ table baz
70
+ key_names time,tag,field1,field2,field3,field4
71
+ sql INSERT INTO baz (coltime,coltag,col1,col2,col3,col4) VALUES (?,?,?,?,?,?)
72
+ ]
73
+ assert_equal 'INSERT INTO baz (coltime,coltag,col1,col2,col3,col4) VALUES (?,?,?,?,?,?)', d.instance.sql
74
+
75
+ time = Time.utc(2012,12,17,1,23,45).to_i
76
+ record = {'field1'=>'value1','field2'=>'value2','field3'=>'value3','field4'=>'value4'}
77
+ d.emit(record, time)
78
+ d.expect_format ['test', time, ['2012-12-17T01:23:45Z','test','value1','value2','value3','value4']].to_msgpack
79
+ d.run
80
+ end
81
+
82
+ def test_time_and_tag_key_complex
83
+ d = create_driver %[
84
+ host database.local
85
+ database foo
86
+ username bar
87
+ password mogera
88
+ include_time_key yes
89
+ utc
90
+ time_format %Y%m%d-%H%M%S
91
+ time_key timekey
92
+ include_tag_key yes
93
+ tag_key tagkey
94
+ table baz
95
+ key_names timekey,tagkey,field1,field2,field3,field4
96
+ sql INSERT INTO baz (coltime,coltag,col1,col2,col3,col4) VALUES (?,?,?,?,?,?)
97
+ ]
98
+ assert_equal 'INSERT INTO baz (coltime,coltag,col1,col2,col3,col4) VALUES (?,?,?,?,?,?)', d.instance.sql
99
+
100
+ time = Time.new(2012,12,17,9,23,45,'+09:00').to_i
101
+ record = {'field1'=>'value1','field2'=>'value2','field3'=>'value3','field4'=>'value4'}
102
+ d.emit(record, time)
103
+ d.expect_format ['test', time, ['20121217-002345','test','value1','value2','value3','value4']].to_msgpack
104
+ d.run
105
+ end
106
+ end
107
+
metadata ADDED
@@ -0,0 +1,113 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fluent-plugin-postgres
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - TAGOMORI Satoshi
9
+ - Diogo Terror
10
+ - pitr
11
+ autorequire:
12
+ bindir: bin
13
+ cert_chain: []
14
+ date: 2013-02-11 00:00:00.000000000 Z
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: fluentd
18
+ requirement: !ruby/object:Gem::Requirement
19
+ none: false
20
+ requirements:
21
+ - - ! '>='
22
+ - !ruby/object:Gem::Version
23
+ version: '0'
24
+ type: :runtime
25
+ prerelease: false
26
+ version_requirements: !ruby/object:Gem::Requirement
27
+ none: false
28
+ requirements:
29
+ - - ! '>='
30
+ - !ruby/object:Gem::Version
31
+ version: '0'
32
+ - !ruby/object:Gem::Dependency
33
+ name: pg
34
+ requirement: !ruby/object:Gem::Requirement
35
+ none: false
36
+ requirements:
37
+ - - ! '>='
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ type: :runtime
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ none: false
44
+ requirements:
45
+ - - ! '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ - !ruby/object:Gem::Dependency
49
+ name: rake
50
+ requirement: !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ! '>='
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ type: :development
57
+ prerelease: false
58
+ version_requirements: !ruby/object:Gem::Requirement
59
+ none: false
60
+ requirements:
61
+ - - ! '>='
62
+ - !ruby/object:Gem::Version
63
+ version: '0'
64
+ description: fluent plugin to insert on PostgreSQL
65
+ email:
66
+ - team@uken.com
67
+ executables: []
68
+ extensions: []
69
+ extra_rdoc_files: []
70
+ files:
71
+ - .gitignore
72
+ - Gemfile
73
+ - LICENSE.txt
74
+ - README.md
75
+ - Rakefile
76
+ - fluent-plugin-postgres.gemspec
77
+ - lib/fluent/plugin/out_postgres.rb
78
+ - test/helper.rb
79
+ - test/plugin/test_out_postgres.rb
80
+ homepage: https://github.com/uken/fluent-plugin-postgres
81
+ licenses:
82
+ - Apache 2.0
83
+ post_install_message:
84
+ rdoc_options: []
85
+ require_paths:
86
+ - lib
87
+ required_ruby_version: !ruby/object:Gem::Requirement
88
+ none: false
89
+ requirements:
90
+ - - ! '>='
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
93
+ segments:
94
+ - 0
95
+ hash: 4318069174566996150
96
+ required_rubygems_version: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ segments:
103
+ - 0
104
+ hash: 4318069174566996150
105
+ requirements: []
106
+ rubyforge_project:
107
+ rubygems_version: 1.8.23
108
+ signing_key:
109
+ specification_version: 3
110
+ summary: fluent plugin to insert on PostgreSQL
111
+ test_files:
112
+ - test/helper.rb
113
+ - test/plugin/test_out_postgres.rb