fluent-plugin-postgres-replicator 0.0.2 → 0.1.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e0800a5552e7c84208560aa4e71ae507af0c826a
4
- data.tar.gz: 0b17c898e047944522ef5f97fb6f10c3f4631701
3
+ metadata.gz: 8e07e9cc31d9517ca679f7d82b4e64c497a788c2
4
+ data.tar.gz: 234391df516fbe3a7b57c66c13b28d231d85d752
5
5
  SHA512:
6
- metadata.gz: ce731ae495459c72229c84760df4c76963b08618f0d55300156b7d8303a838b0b8609d2b6d2ece8e27e0d01273eedd9b195bef6c74c215311b9cbf3149cf3d22
7
- data.tar.gz: 3c98a0b8018703aa6e748c5b62eae1ddca8f4fe951c0c430e7594e5624d81b726ac1307766550d27b3b724eb274f0ce7ac0d838d11cee04a5803c9f89ffc7379
6
+ metadata.gz: 874a6e13a95cd16be2549b686db73c8bb00f0f5c0ec6c609828203cb38ffc585bb8e24c142f0b98640d205cac3335f4560ff32952aeb7b18df5a733cb2849463
7
+ data.tar.gz: d62069b79b4744282714d04361cf7f44ae38132af5677f35683449c0a64454f405d26b8fcbaefa389e99c87935b3599e22ff7df19efc61d33a30121a10d4afc9
@@ -1,10 +1,10 @@
1
1
  language: ruby
2
2
 
3
3
  rvm:
4
- - 1.9.3
5
- - 2.0.0
6
4
  - 2.1
7
5
  - 2.2
6
+ - 2.3
7
+ - 2.4.1
8
8
 
9
9
  addons:
10
10
  postgresql: "9.4"
data/README.md CHANGED
@@ -5,28 +5,31 @@
5
5
 
6
6
  Fluentd input plugin to track insert/update event from PostgreSQL.
7
7
 
8
+ ## Requirements
9
+
10
+ | fluent-plugin-postgres-replicator | fluentd | ruby |
11
+ |-----------------------------------|---------|------|
12
+ | >= 0.1.0 | >= v0.14.0 | >= 2.1 |
13
+ | < 0.1.0 | >= v0.12.0 | >= 1.9 |
14
+
8
15
  ## Installation
9
16
 
10
17
  ```sh
11
- # requirements
12
18
  $ apt-get install libpq-dev
13
19
 
14
20
  $ gem install fluent-plugin-postgres-replicator
15
21
  ```
16
22
 
17
- ## Usage
18
-
19
- In your Fluentd configuration, use `type postgres_replicator`.
20
- Default values would look like this:
23
+ ## Configuration
21
24
 
22
25
  ```
23
26
  <source>
24
- type postgres_replicator
27
+ @type postgres_replicator
25
28
  host localhost
26
29
  username pipeline
27
30
  password pipeline
28
31
  database pipeline
29
- query SELECT hour, project, total_pages from wiki_stats;
32
+ sql SELECT hour, project, total_pages from wiki_stats;
30
33
  primary_keys hour,project
31
34
  interval 1m
32
35
  tag replicator.pipeline.wiki_stats.${event}.${primary_keys}
@@ -37,6 +40,18 @@ Default values would look like this:
37
40
 
38
41
  Bug reports and pull requests are welcome.
39
42
 
43
+ You can run the test on your machine as below.
44
+
45
+ ```console
46
+ $ docker run --name fluent-plugin-postgres-replicator-testing -e POSTGRES_DB=pg_repli_test_db -p 5432:5432 -d postgres:9.4.12-alpine
47
+ $ psql -c 'create table pg_repli_test_table (id int8 primary key, total int8) ;' -U postgres -h 127.0.0.1 -d pg_repli_test_db
48
+ $ psql -c 'insert into pg_repli_test_table values (1, 10) ;' -U postgres -h 127.0.0.1 -d pg_repli_test_db
49
+ $ psql -c 'insert into pg_repli_test_table values (2, 20) ;' -U postgres -h 127.0.0.1 -d pg_repli_test_db
50
+
51
+ $ bundle install --path vendor/bundle
52
+ $ bundle exec rake test
53
+ ```
54
+
40
55
  ## License
41
56
 
42
57
  - Copyright (c) 2016 innossh
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
 
5
5
  Gem::Specification.new do |gem|
6
6
  gem.name = "fluent-plugin-postgres-replicator"
7
- gem.version = "0.0.2"
7
+ gem.version = "0.1.0"
8
8
  gem.authors = ["innossh"]
9
9
  gem.email = ["innossh@users.noreply.github.com"]
10
10
 
@@ -17,7 +17,7 @@ Gem::Specification.new do |gem|
17
17
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
18
  gem.require_paths = ["lib"]
19
19
 
20
- gem.add_runtime_dependency "fluentd"
20
+ gem.add_runtime_dependency "fluentd", [">= 0.14.0", "< 2"]
21
21
  gem.add_runtime_dependency "pg"
22
22
  gem.add_development_dependency "rake"
23
23
  gem.add_development_dependency "test-unit"
@@ -1,126 +1,125 @@
1
- class Fluent::PostgresReplicatorInput < Fluent::Input
2
- Fluent::Plugin.register_input('postgres_replicator', self)
3
-
4
- config_param :host, :string, :default => 'localhost'
5
- config_param :port, :integer, :default => 5432
6
- config_param :username, :string, :default => 'root'
7
- config_param :password, :string, :default => nil, :secret => true
8
- config_param :database, :string, :default => nil
9
- config_param :sql, :string, :default => nil
10
- config_param :primary_keys, :string, :default => nil
11
- config_param :interval, :string, :default => '10s'
12
- config_param :tag, :string, :default => nil
13
-
14
- def initialize
15
- super
16
- require 'pg'
17
- require 'digest/sha1'
18
- end
1
+ require 'fluent/plugin/input'
2
+ require 'pg'
3
+ require 'digest/sha1'
4
+
5
+ module Fluent::Plugin
6
+ class PostgresReplicatorInput < Input
7
+ Fluent::Plugin.register_input('postgres_replicator', self)
8
+
9
+ config_param :host, :string, :default => 'localhost'
10
+ config_param :port, :integer, :default => 5432
11
+ config_param :username, :string, :default => 'root'
12
+ config_param :password, :string, :default => nil, :secret => true
13
+ config_param :database, :string, :default => nil
14
+ config_param :sql, :string, :default => nil
15
+ config_param :primary_keys, :string
16
+ config_param :interval, :string, :default => '10s'
17
+ config_param :tag, :string
18
+
19
+ def configure(conf)
20
+ super
19
21
 
20
- def configure(conf)
21
- super
22
- @interval = Fluent::Config.time_value(@interval)
23
- if @primary_keys.nil?
24
- raise Fluent::ConfigError, "primary_keys MUST be specified"
22
+ @interval = Fluent::Config.time_value(@interval)
23
+ @primary_keys = @primary_keys.split(/\s*,\s*/)
25
24
  end
26
- if @tag.nil?
27
- raise Fluent::ConfigError, "tag MUST be specified"
25
+
26
+ def start
27
+ super
28
+
29
+ @thread = Thread.new(&method(:run))
28
30
  end
29
- @primary_keys = @primary_keys.split(/\s*,\s*/)
30
- end
31
31
 
32
- def start
33
- @thread = Thread.new(&method(:run))
34
- end
32
+ def shutdown
33
+ Thread.kill(@thread)
35
34
 
36
- def shutdown
37
- Thread.kill(@thread)
38
- end
35
+ super
36
+ end
39
37
 
40
- def run
41
- begin
42
- poll
43
- rescue StandardError => e
44
- log.error "failed to execute query. error: #{e.message}"
45
- log.error e.backtrace.join("\n")
38
+ def run
39
+ begin
40
+ poll
41
+ rescue StandardError => e
42
+ log.error "failed to execute query. error: #{e.message}"
43
+ log.error e.backtrace.join("\n")
44
+ end
46
45
  end
47
- end
48
46
 
49
- def poll
50
- hash_values = Hash.new
51
- conn = get_connection()
52
- loop do
53
- rows_count = 0
54
- start_time = Time.now
55
- rows, conn = query(@sql, conn)
56
- rows.each do |row|
57
- row_ids = Array.new
58
- @primary_keys.each do |primary_key|
59
- if !row[primary_key].nil?
60
- row_ids << row[primary_key]
47
+ def poll
48
+ hash_values = Hash.new
49
+ conn = get_connection()
50
+ loop do
51
+ rows_count = 0
52
+ start_time = Time.now
53
+ rows, conn = query(@sql, conn)
54
+ rows.each do |row|
55
+ row_ids = Array.new
56
+ @primary_keys.each do |primary_key|
57
+ if !row[primary_key].nil?
58
+ row_ids << row[primary_key]
59
+ end
60
+ end
61
+ if row_ids.size != @primary_keys.size
62
+ log.error "primary_keys column value is something wrong. :tag=>#{@tag} :primary_keys=>#{@primary_keys}"
63
+ break
61
64
  end
62
- end
63
- if row_ids.size != @primary_keys.size
64
- log.error "primary_keys column value is something wrong. :tag=>#{@tag} :primary_keys=>#{@primary_keys}"
65
- break
66
- end
67
65
 
68
- hash_value_id = row_ids.join('_')
69
- hash_value = Digest::SHA1.hexdigest(row.flatten.join)
70
- if !hash_values.include?(hash_value_id)
71
- tag = format_tag(@tag, {:event => :insert})
72
- emit_record(tag, row)
73
- elsif hash_values[hash_value_id] != hash_value
74
- tag = format_tag(@tag, {:event => :update})
75
- emit_record(tag, row)
66
+ hash_value_id = row_ids.join('_')
67
+ hash_value = Digest::SHA1.hexdigest(row.flatten.join)
68
+ if !hash_values.include?(hash_value_id)
69
+ tag = format_tag(@tag, {:event => :insert})
70
+ emit_record(tag, row)
71
+ elsif hash_values[hash_value_id] != hash_value
72
+ tag = format_tag(@tag, {:event => :update})
73
+ emit_record(tag, row)
74
+ end
75
+ hash_values[hash_value_id] = hash_value
76
+ rows_count += 1
76
77
  end
77
- hash_values[hash_value_id] = hash_value
78
- rows_count += 1
78
+ conn.close
79
+ elapsed_time = sprintf('%0.02f', Time.now - start_time)
80
+ log.info "success to execute replicator. :tag=>#{@tag} :rows_count=>#{rows_count} :elapsed_time=>#{elapsed_time} sec"
81
+ sleep @interval
79
82
  end
80
- conn.close
81
- elapsed_time = sprintf('%0.02f', Time.now - start_time)
82
- log.info "success to execute replicator. :tag=>#{@tag} :rows_count=>#{rows_count} :elapsed_time=>#{elapsed_time} sec"
83
- sleep @interval
84
- end
85
83
 
86
- end
84
+ end
87
85
 
88
- def query(sql, conn = nil)
89
- begin
90
- conn = (conn.nil? || conn.finished?) ? get_connection : conn
91
- return conn.query(sql), conn
92
- rescue Exception => e
93
- log.warn "failed to execute query and will retry. error: #{e}"
94
- sleep @interval
95
- retry
86
+ def query(sql, conn = nil)
87
+ begin
88
+ conn = (conn.nil? || conn.finished?) ? get_connection : conn
89
+ return conn.query(sql), conn
90
+ rescue Exception => e
91
+ log.warn "failed to execute query and will retry. error: #{e}"
92
+ sleep @interval
93
+ retry
94
+ end
96
95
  end
97
- end
98
96
 
99
- def format_tag(tag, param)
100
- pattern = {'${event}' => param[:event].to_s, '${primary_keys}' => @primary_keys.join('_')}
101
- tag.gsub(/(\${[a-z_]+})/) do
102
- log.warn "placeholder value is not found. :tag=>#{tag} :placeholder=>#{$1}" unless pattern.include?($1)
103
- pattern[$1]
97
+ def format_tag(tag, param)
98
+ pattern = {'${event}' => param[:event].to_s, '${primary_keys}' => @primary_keys.join('_')}
99
+ tag.gsub(/(\${[a-z_]+})/) do
100
+ log.warn "placeholder value is not found. :tag=>#{tag} :placeholder=>#{$1}" unless pattern.include?($1)
101
+ pattern[$1]
102
+ end
104
103
  end
105
- end
106
104
 
107
- def emit_record(tag, record)
108
- router.emit(tag, Fluent::Engine.now, record)
109
- end
105
+ def emit_record(tag, record)
106
+ router.emit(tag, Fluent::Engine.now, record)
107
+ end
110
108
 
111
- def get_connection
112
- begin
113
- return PG::Connection.new({
114
- :host => @host,
115
- :port => @port,
116
- :user => @username,
117
- :password => @password,
118
- :dbname => @database
119
- })
120
- rescue Exception => e
121
- log.warn "failed to get connection and will retry. error: #{e}"
122
- sleep @interval
123
- retry
109
+ def get_connection
110
+ begin
111
+ return PG::Connection.new({
112
+ :host => @host,
113
+ :port => @port,
114
+ :user => @username,
115
+ :password => @password,
116
+ :dbname => @database
117
+ })
118
+ rescue Exception => e
119
+ log.warn "failed to get connection and will retry. error: #{e}"
120
+ sleep @interval
121
+ retry
122
+ end
124
123
  end
125
124
  end
126
125
  end
@@ -1,5 +1,5 @@
1
- require 'test/unit'
2
1
  require 'fluent/test'
2
+ require 'fluent/test/driver/input'
3
3
  require 'fluent/plugin/in_postgres_replicator'
4
4
 
5
5
  class PostgresReplicatorTest < Test::Unit::TestCase
@@ -20,7 +20,7 @@ class PostgresReplicatorTest < Test::Unit::TestCase
20
20
  ]
21
21
 
22
22
  def create_driver(conf = CONFIG)
23
- Fluent::Test::InputTestDriver.new(Fluent::PostgresReplicatorInput).configure(conf)
23
+ Fluent::Test::Driver::Input.new(Fluent::Plugin::PostgresReplicatorInput).configure(conf)
24
24
  end
25
25
 
26
26
  def test_configure
@@ -43,14 +43,12 @@ class PostgresReplicatorTest < Test::Unit::TestCase
43
43
  def test_emit
44
44
  d = create_driver
45
45
 
46
- d.run do
47
- sleep 2
48
- end
46
+ d.run(expect_records: 2, timeout: 2)
49
47
 
50
- emits = d.emits
51
- assert_equal true, emits.length > 0
52
- assert_equal ['pgreplicator.pg_repli_test_db.pg_repli_test_table.insert.id', @time, {'id' => '1', 'total' => '10'}], emits[0]
53
- assert_equal ['pgreplicator.pg_repli_test_db.pg_repli_test_table.insert.id', @time, {'id' => '2', 'total' => '20'}], emits[1]
48
+ events = d.events
49
+ assert_equal true, events.length == 2
50
+ assert_equal ['pgreplicator.pg_repli_test_db.pg_repli_test_table.insert.id', @time, {'id' => '1', 'total' => '10'}], events[0]
51
+ assert_equal ['pgreplicator.pg_repli_test_db.pg_repli_test_table.insert.id', @time, {'id' => '2', 'total' => '20'}], events[1]
54
52
  end
55
53
 
56
54
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fluent-plugin-postgres-replicator
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - innossh
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-01-07 00:00:00.000000000 Z
11
+ date: 2017-07-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: fluentd
@@ -16,14 +16,20 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '0'
19
+ version: 0.14.0
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '2'
20
23
  type: :runtime
21
24
  prerelease: false
22
25
  version_requirements: !ruby/object:Gem::Requirement
23
26
  requirements:
24
27
  - - ">="
25
28
  - !ruby/object:Gem::Version
26
- version: '0'
29
+ version: 0.14.0
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '2'
27
33
  - !ruby/object:Gem::Dependency
28
34
  name: pg
29
35
  requirement: !ruby/object:Gem::Requirement
@@ -105,7 +111,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
105
111
  version: '0'
106
112
  requirements: []
107
113
  rubyforge_project:
108
- rubygems_version: 2.4.5.1
114
+ rubygems_version: 2.5.1
109
115
  signing_key:
110
116
  specification_version: 4
111
117
  summary: PostgreSQL replication input plugin for Fluent