fluent-plugin-pghstore 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,11 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ # For TextMate, emacs, vim
6
+ *.tmproj
7
+ tmtags
8
+ *~
9
+ \#*
10
+ .\#*
11
+ *.swp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in fluent-plugin-pghstore.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,13 @@
1
+ Copyright (c) 2012- Shirou WAKAYAMA
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.
data/README.rdoc ADDED
@@ -0,0 +1,76 @@
1
+ = fluent-plugin-pghstore
2
+
3
+ == Component
4
+
5
+ === PgHStoreOutput
6
+
7
+ Output to PostgreSQL hstore database.
8
+
9
+ Output table should have tag, time and record column.:
10
+
11
+ CREATE TABLE #{tablename} (
12
+ tag TEXT,
13
+ time TIMESTAMP WITH TIME ZONE,
14
+ record HSTORE
15
+ );
16
+
17
+ == Requirement
18
+
19
+ - PostgreSQL 9.0 or higher
20
+ - hstore changed at PostgreSQL 9.0.
21
+ - postgres-contrib
22
+ - ruby-pg
23
+
24
+ === How to Install hstore
25
+
26
+ hstore is in the contrib.
27
+
28
+ 9.1 or higher:
29
+
30
+ psql <dbname> -c "CREATE EXTENSION hstore;"
31
+
32
+ 9.0:
33
+
34
+ psql <dbname> -f ${PGHOME}/share/contrib/hstore.sql
35
+
36
+ == Configuration
37
+
38
+ Example:
39
+
40
+ <match apache.*>
41
+ type pghstore
42
+ database test
43
+ table test
44
+ table_option CREATE INDEX time_index ON testb (time);
45
+ </match>
46
+
47
+ === Options
48
+
49
+ - Required
50
+ - database
51
+ - database name
52
+ - Optional
53
+ - table
54
+ - tablename. If not set, use +fluentd_store+. If not exists, creates automatically.
55
+ - host
56
+ - port
57
+ - user
58
+ - password
59
+ - table_option
60
+ - Add some SQL. This SQL is called only once when table is created from this plugin.
61
+
62
+ == Limitation
63
+
64
+ - Nested output is not allowd.
65
+ - Since using only one connection, performance may become bad. When you meet this, use connection pooling and write patch!
66
+
67
+
68
+ == Thanks
69
+
70
+ This source code is mainly borrowed from
71
+ {fluent-plugin-datacounter}{https://rubygems.org/gems/fluent-plugin-datacounter}. Thank you for tagomoris.
72
+
73
+ == Copyright
74
+
75
+ Copyright:: Copyright (c) 2012- Shirou WAKAYAMA
76
+ License:: Apache License
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require 'rake/testtask'
4
+ Rake::TestTask.new(:test) do |test|
5
+ test.libs << 'lib' << 'test'
6
+ # test.pattern = 'test/**/test_*.rb'
7
+ test.test_files = FileList['test/**/test*.rb']
8
+ test.verbose = true
9
+ end
10
+
11
+ task :default => :test
12
+
data/example.conf ADDED
@@ -0,0 +1,13 @@
1
+ <source>
2
+ type tail
3
+ path /var/log/apache/access_log
4
+ tag apache.access
5
+ format apache
6
+ </source>
7
+
8
+ <match apache.*>
9
+ type pghstore
10
+ database test
11
+ table test # (option) default is fluentd_store
12
+ table_option CREATE INDEX time_index ON testb (time); # (option)
13
+ </match>
@@ -0,0 +1,27 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "fluent-plugin-pghstore"
6
+ s.version = "0.0.1"
7
+ s.authors = ["WAKAYAMA Shirou"]
8
+ s.email = ["shirou.faw@gmail.com"]
9
+ s.homepage = "https://github.com/r_rudi/fluent-plugin-pghstore"
10
+ s.summary = %q{Output to PostgreSQL database which has a hstore extension}
11
+ s.description = %q{Output to PostgreSQL database which has a hstore extension}
12
+
13
+ s.rubyforge_project = "fluent-plugin-pghstore"
14
+
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
+ s.require_paths = ["lib"]
19
+
20
+ # specify any dependencies here; for example:
21
+ s.add_development_dependency "rspec"
22
+ # s.add_runtime_dependency "rest-client"
23
+ s.add_development_dependency "fluentd"
24
+ s.add_development_dependency "pg"
25
+ s.add_runtime_dependency "fluentd"
26
+ s.add_runtime_dependency "pg"
27
+ end
@@ -0,0 +1,102 @@
1
+ class Fluent::PgHStoreOutput < Fluent::BufferedOutput
2
+ Fluent::Plugin.register_output('pghstore', self)
3
+
4
+ config_param :database, :string
5
+ config_param :table, :string, :default => 'fluentd_store'
6
+ config_param :host, :string, :default => 'localhost'
7
+ config_param :port, :integer, :default => 5432
8
+ config_param :user, :string, :default => nil
9
+ config_param :password, :string, :default => nil
10
+
11
+ config_param :table_option, :string, :default => nil
12
+
13
+ def initialize
14
+ super
15
+ require 'pg'
16
+ end
17
+
18
+ def start
19
+ super
20
+
21
+ @conn = get_connection(@database, @host, @port, @user, @password)
22
+
23
+ create_table(@table) unless table_exists?(@table)
24
+
25
+ end
26
+
27
+ def shutdown
28
+ super
29
+
30
+ @conn.close
31
+ end
32
+
33
+ def format(tag, time, record)
34
+ [tag, time, record].to_msgpack
35
+ end
36
+
37
+ def write(chunk)
38
+ chunk.msgpack_each {|(tag, time_str, record)|
39
+ sql = generate_sql(tag, time_str, record)
40
+ @conn.exec(sql)
41
+ }
42
+ end
43
+
44
+ private
45
+
46
+ def generate_sql(tag, time, record)
47
+ kv_list = []
48
+ record.each {|(key,value)|
49
+ begin
50
+ v = Integer(value)
51
+ rescue ArgumentError => e
52
+ kv_list.push("#{key} => \"#{value}\"") # might be string
53
+ else
54
+ kv_list.push("#{key} => #{value}")
55
+ end
56
+ }
57
+
58
+ sql =<<"SQL"
59
+ INSERT INTO #{@table} (tag, time, record) VALUES
60
+ ('#{tag}', '#{Time.at(time)}'::TIMESTAMP WITH TIME ZONE, '#{kv_list.join(",")}');
61
+ SQL
62
+ return sql
63
+ end
64
+
65
+ def get_connection(dbname, host, port, user, password)
66
+ if user
67
+ return PG.connect(:dbname => dbname, :host => host, :port => port,
68
+ :user => user, :password => password)
69
+ else
70
+ return PG.connect(:dbname => dbname, :host => host, :port => port)
71
+ end
72
+ end
73
+
74
+ def table_exists?(table)
75
+ sql =<<"SQL"
76
+ SELECT COUNT(*) FROM pg_tables WHERE tablename = '#{table}';
77
+ SQL
78
+ res = @conn.exec(sql)
79
+ if res[0]["count"] == "1"
80
+ return true
81
+ else
82
+ return false
83
+ end
84
+ end
85
+
86
+ def create_table(tablename)
87
+ sql =<<"SQL"
88
+ CREATE TABLE #{tablename} (
89
+ tag TEXT,
90
+ time TIMESTAMP WITH TIME ZONE,
91
+ record HSTORE
92
+ );
93
+ SQL
94
+
95
+ sql += @table_option if @table_option
96
+
97
+ @conn.exec(sql)
98
+
99
+ $log.warn "#{tablename} table is not exists. created."
100
+ end
101
+
102
+ end
data/test/helper.rb ADDED
@@ -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_pghstore'
26
+
27
+ class Test::Unit::TestCase
28
+ end
@@ -0,0 +1,44 @@
1
+ require 'helper'
2
+
3
+ class PGHStoreOutputTest < Test::Unit::TestCase
4
+ def setup
5
+ Fluent::Test.setup
6
+ end
7
+
8
+ CONFIG = %[
9
+ database "testdb"
10
+ table "testtable"
11
+ user "testuser"
12
+ password "testpassword"
13
+ ]
14
+
15
+ def create_driver(conf = CONFIG, tag='test.input')
16
+ Fluent::Test::BufferedOutputTestDriver.new(Fluent::PgHStoreOutput, tag).configure(conf)
17
+ end
18
+
19
+ def test_configure
20
+ end
21
+
22
+ def test_format
23
+ d = create_driver
24
+
25
+ # time = Time.parse("2011-01-02 13:14:15 UTC").to_i
26
+ # d.emit({"a"=>1}, time)
27
+ # d.emit({"a"=>2}, time)
28
+
29
+ # d.expect_format %[2011-01-02T13:14:15Z\ttest\t{"a":1}\n]
30
+ # d.expect_format %[2011-01-02T13:14:15Z\ttest\t{"a":2}\n]
31
+
32
+ # d.run
33
+ end
34
+
35
+ def test_write
36
+ d = create_driver
37
+
38
+ # time = Time.parse("2011-01-02 13:14:15 UTC").to_i
39
+ # d.emit({"a"=>1}, time)
40
+ # d.emit({"a"=>2}, time)
41
+
42
+ end
43
+
44
+ end
@@ -0,0 +1,277 @@
1
+ require 'helper'
2
+
3
+ class DataCounterOutputTest < Test::Unit::TestCase
4
+ def setup
5
+ Fluent::Test.setup
6
+ end
7
+
8
+ CONFIG = %[
9
+ unit minute
10
+ aggregate tag
11
+ input_tag_remove_prefix test
12
+ count_key target
13
+ pattern1 status2xx ^2\\d\\d$
14
+ pattern2 status3xx ^3\\d\\d$
15
+ pattern3 status4xx ^4\\d\\d$
16
+ pattern4 status5xx ^5\\d\\d$
17
+ ]
18
+
19
+ def create_driver(conf = CONFIG, tag='test.input')
20
+ Fluent::Test::OutputTestDriver.new(Fluent::DataCounterOutput, tag).configure(conf)
21
+ end
22
+
23
+ def test_configure
24
+ assert_raise(Fluent::ConfigError) {
25
+ d = create_driver('')
26
+ }
27
+ assert_raise(Fluent::ConfigError) {
28
+ d = create_driver %[
29
+ count_key field
30
+ ]
31
+ }
32
+ assert_raise(Fluent::ConfigError) {
33
+ d = create_driver %[
34
+ pattern1 hoge ^1\\d\\d$
35
+ ]
36
+ }
37
+ assert_raise(Fluent::ConfigError) {
38
+ d = create_driver %[
39
+ count_key field
40
+ pattern2 hoge ^1\\d\\d$
41
+ ]
42
+ }
43
+ assert_raise(Fluent::ConfigError) {
44
+ d = create_driver %[
45
+ count_key field
46
+ pattern1 hoge ^1\\d\\d$
47
+ pattern4 pos ^4\\d\\d$
48
+ ]
49
+ }
50
+ assert_raise(Fluent::ConfigError) {
51
+ d = create_driver %[
52
+ count_key field
53
+ pattern1 hoge ^1\\d\\d$
54
+ pattern2 hoge ^4\\d\\d$
55
+ ]
56
+ }
57
+ d = create_driver %[
58
+ count_key field
59
+ pattern1 ok ^2\\d\\d$
60
+ ]
61
+ assert_equal 60, d.instance.tick
62
+ assert_equal :tag, d.instance.aggregate
63
+ assert_equal 'datacount', d.instance.tag
64
+ assert_nil d.instance.input_tag_remove_prefix
65
+ assert_equal 'field', d.instance.count_key
66
+ assert_equal 'ok ^2\d\d$', d.instance.pattern1
67
+
68
+ d1 = create_driver %[
69
+ unit minute
70
+ count_key field
71
+ pattern1 ok ^2\\d\\d$
72
+ ]
73
+ d2 = create_driver %[
74
+ count_interval 60s
75
+ count_key field
76
+ pattern1 ok ^2\\d\\d$
77
+ ]
78
+ assert_equal d1.instance.tick, d2.instance.tick
79
+
80
+ d = create_driver %[
81
+ count_interval 5m
82
+ count_key field
83
+ pattern1 ok ^2\\d\\d$
84
+ ]
85
+ assert_equal 300, d.instance.tick
86
+
87
+ d = create_driver %[
88
+ count_interval 2h
89
+ count_key field
90
+ pattern1 ok ^2\\d\\d$
91
+ ]
92
+ assert_equal 7200, d.instance.tick
93
+
94
+ d = create_driver %[
95
+ count_interval 30s
96
+ count_key field
97
+ pattern1 ok ^2\\d\\d$
98
+ ]
99
+ assert_equal 30, d.instance.tick
100
+ end
101
+
102
+ def test_count_initialized
103
+ d = create_driver %[
104
+ aggregate all
105
+ count_key field
106
+ pattern1 hoge 1\d\d
107
+ pattern2 moge 2\d\d
108
+ ]
109
+ assert_equal [0,0,0], d.instance.counts['all']
110
+ end
111
+
112
+ def test_countups
113
+ d = create_driver
114
+ assert_nil d.instance.counts['test.input']
115
+
116
+ d.instance.countups('test.input', [0, 0, 0, 0, 0])
117
+ assert_equal [0,0,0,0,0], d.instance.counts['test.input']
118
+ d.instance.countups('test.input', [1, 1, 1, 0, 0])
119
+ assert_equal [1,1,1,0,0], d.instance.counts['test.input']
120
+ d.instance.countups('test.input', [0, 5, 1, 0, 0])
121
+ assert_equal [1,6,2,0,0], d.instance.counts['test.input']
122
+ end
123
+
124
+ def test_stripped_tag
125
+ d = create_driver
126
+ assert_equal 'input', d.instance.stripped_tag('test.input')
127
+ assert_equal 'test.input', d.instance.stripped_tag('test.test.input')
128
+ assert_equal 'input', d.instance.stripped_tag('input')
129
+ end
130
+
131
+ def test_generate_output
132
+ d = create_driver
133
+ r1 = d.instance.generate_output({'test.input' => [60,240,120,180,0], 'test.input2' => [0,600,0,0,0]}, 60)
134
+ assert_equal 60, r1['input_unmatched_count']
135
+ assert_equal 1.0, r1['input_unmatched_rate']
136
+ assert_equal 10.0, r1['input_unmatched_percentage']
137
+ assert_equal 240, r1['input_status2xx_count']
138
+ assert_equal 4.0, r1['input_status2xx_rate']
139
+ assert_equal 40.0, r1['input_status2xx_percentage']
140
+ assert_equal 120, r1['input_status3xx_count']
141
+ assert_equal 2.0, r1['input_status3xx_rate']
142
+ assert_equal 20.0, r1['input_status3xx_percentage']
143
+ assert_equal 180, r1['input_status4xx_count']
144
+ assert_equal 3.0, r1['input_status4xx_rate']
145
+ assert_equal 30.0, r1['input_status4xx_percentage']
146
+ assert_equal 0, r1['input_status5xx_count']
147
+ assert_equal 0.0, r1['input_status5xx_rate']
148
+ assert_equal 0.0, r1['input_status5xx_percentage']
149
+
150
+ assert_equal 0, r1['input2_unmatched_count']
151
+ assert_equal 0.0, r1['input2_unmatched_rate']
152
+ assert_equal 0.0, r1['input2_unmatched_percentage']
153
+ assert_equal 600, r1['input2_status2xx_count']
154
+ assert_equal 10.0, r1['input2_status2xx_rate']
155
+ assert_equal 100.0, r1['input2_status2xx_percentage']
156
+ assert_equal 0, r1['input2_status3xx_count']
157
+ assert_equal 0.0, r1['input2_status3xx_rate']
158
+ assert_equal 0.0, r1['input2_status3xx_percentage']
159
+ assert_equal 0, r1['input2_status4xx_count']
160
+ assert_equal 0.0, r1['input2_status4xx_rate']
161
+ assert_equal 0.0, r1['input2_status4xx_percentage']
162
+ assert_equal 0, r1['input2_status5xx_count']
163
+ assert_equal 0.0, r1['input2_status5xx_rate']
164
+ assert_equal 0.0, r1['input2_status5xx_percentage']
165
+
166
+ d = create_driver %[
167
+ aggregate all
168
+ count_key field
169
+ pattern1 hoge xxx\d\d
170
+ ]
171
+ r2 = d.instance.generate_output({'all' => [60,240]}, 60)
172
+ assert_equal 60, r2['unmatched_count']
173
+ assert_equal 1.0, r2['unmatched_rate']
174
+ assert_equal 20.0, r2['unmatched_percentage']
175
+ assert_equal 240, r2['hoge_count']
176
+ assert_equal 4.0, r2['hoge_rate']
177
+ assert_equal 80.0, r2['hoge_percentage']
178
+ end
179
+
180
+ def test_pattern_num
181
+ assert_equal 20, Fluent::DataCounterOutput::PATTERN_MAX_NUM
182
+
183
+ conf = %[
184
+ aggregate all
185
+ count_key field
186
+ ]
187
+ (1..20).each do |i|
188
+ conf += "pattern#{i} name#{i} ^#{i}$\n"
189
+ end
190
+ d = create_driver(conf, 'test.max')
191
+ d.run do
192
+ (1..20).each do |j|
193
+ d.emit({'field' => j})
194
+ end
195
+ end
196
+ r = d.instance.flush(60)
197
+ assert_equal 1, r['name1_count']
198
+ assert_equal 1, r['name2_count']
199
+ assert_equal 1, r['name3_count']
200
+ assert_equal 1, r['name4_count']
201
+ assert_equal 1, r['name5_count']
202
+ assert_equal 1, r['name6_count']
203
+ assert_equal 1, r['name7_count']
204
+ assert_equal 1, r['name8_count']
205
+ assert_equal 1, r['name9_count']
206
+ assert_equal 1, r['name10_count']
207
+ assert_equal 1, r['name11_count']
208
+ assert_equal 1, r['name12_count']
209
+ assert_equal 1, r['name13_count']
210
+ assert_equal 1, r['name14_count']
211
+ assert_equal 1, r['name15_count']
212
+ assert_equal 1, r['name16_count']
213
+ assert_equal 1, r['name17_count']
214
+ assert_equal 1, r['name18_count']
215
+ assert_equal 1, r['name19_count']
216
+ assert_equal 1, r['name20_count']
217
+ end
218
+
219
+ def test_emit
220
+ d1 = create_driver(CONFIG, 'test.tag1')
221
+ d1.run do
222
+ 60.times do
223
+ d1.emit({'target' => '200'})
224
+ d1.emit({'target' => '100'})
225
+ d1.emit({'target' => '200'})
226
+ d1.emit({'target' => '400'})
227
+ end
228
+ end
229
+ r1 = d1.instance.flush(60)
230
+ assert_equal 120, r1['tag1_status2xx_count']
231
+ assert_equal 2.0, r1['tag1_status2xx_rate']
232
+ assert_equal 50.0, r1['tag1_status2xx_percentage']
233
+
234
+ assert_equal 60, r1['tag1_status4xx_count']
235
+ assert_equal 1.0, r1['tag1_status4xx_rate']
236
+ assert_equal 25.0, r1['tag1_status4xx_percentage']
237
+
238
+ assert_equal 60, r1['tag1_unmatched_count']
239
+ assert_equal 1.0, r1['tag1_unmatched_rate']
240
+ assert_equal 25.0, r1['tag1_unmatched_percentage']
241
+
242
+ assert_equal 0, r1['tag1_status3xx_count']
243
+ assert_equal 0.0, r1['tag1_status3xx_rate']
244
+ assert_equal 0.0, r1['tag1_status3xx_percentage']
245
+ assert_equal 0, r1['tag1_status5xx_count']
246
+ assert_equal 0.0, r1['tag1_status5xx_rate']
247
+ assert_equal 0.0, r1['tag1_status5xx_percentage']
248
+
249
+ d2 = create_driver(%[
250
+ aggregate all
251
+ count_key target
252
+ pattern1 ok 2\\d\\d
253
+ pattern2 redirect 3\\d\\d
254
+ ], 'test.tag2')
255
+ d2.run do
256
+ 60.times do
257
+ d2.emit({'target' => '200'})
258
+ d2.emit({'target' => '300 200'})
259
+ end
260
+ end
261
+ d2.instance.flush_emit(120)
262
+ emits = d2.emits
263
+ assert_equal 1, emits.length
264
+ data = emits[0]
265
+ assert_equal 'datacount', data[0] # tag
266
+ assert_equal 120, data[2]['ok_count']
267
+ assert_equal 1.0, data[2]['ok_rate']
268
+ assert_equal 100.0, data[2]['ok_percentage']
269
+ assert_equal 0, data[2]['redirect_count']
270
+ assert_equal 0.0, data[2]['redirect_rate']
271
+ assert_equal 0.0, data[2]['redirect_percentage']
272
+ assert_equal 0, data[2]['unmatched_count']
273
+ assert_equal 0.0, data[2]['unmatched_rate']
274
+ assert_equal 0.0, data[2]['unmatched_percentage']
275
+ end
276
+
277
+ end
metadata ADDED
@@ -0,0 +1,136 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fluent-plugin-pghstore
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - WAKAYAMA Shirou
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-03-30 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rspec
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: fluentd
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: pg
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
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: fluentd
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
+ - !ruby/object:Gem::Dependency
79
+ name: pg
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :runtime
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ description: Output to PostgreSQL database which has a hstore extension
95
+ email:
96
+ - shirou.faw@gmail.com
97
+ executables: []
98
+ extensions: []
99
+ extra_rdoc_files: []
100
+ files:
101
+ - .gitignore
102
+ - Gemfile
103
+ - LICENSE.txt
104
+ - README.rdoc
105
+ - Rakefile
106
+ - example.conf
107
+ - fluent-plugin-pghstore.gemspec
108
+ - lib/fluent/plugin/out_pghstore.rb
109
+ - test/helper.rb
110
+ - test/plugin/test_out_pghstore.rb
111
+ - test/plugin/test_out_pghstore.rb.bak
112
+ homepage: https://github.com/r_rudi/fluent-plugin-pghstore
113
+ licenses: []
114
+ post_install_message:
115
+ rdoc_options: []
116
+ require_paths:
117
+ - lib
118
+ required_ruby_version: !ruby/object:Gem::Requirement
119
+ none: false
120
+ requirements:
121
+ - - ! '>='
122
+ - !ruby/object:Gem::Version
123
+ version: '0'
124
+ required_rubygems_version: !ruby/object:Gem::Requirement
125
+ none: false
126
+ requirements:
127
+ - - ! '>='
128
+ - !ruby/object:Gem::Version
129
+ version: '0'
130
+ requirements: []
131
+ rubyforge_project: fluent-plugin-pghstore
132
+ rubygems_version: 1.8.21
133
+ signing_key:
134
+ specification_version: 3
135
+ summary: Output to PostgreSQL database which has a hstore extension
136
+ test_files: []