fluent-plugin-pghstore 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.
- data/.gitignore +11 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +13 -0
- data/README.rdoc +76 -0
- data/Rakefile +12 -0
- data/example.conf +13 -0
- data/fluent-plugin-pghstore.gemspec +27 -0
- data/lib/fluent/plugin/out_pghstore.rb +102 -0
- data/test/helper.rb +28 -0
- data/test/plugin/test_out_pghstore.rb +44 -0
- data/test/plugin/test_out_pghstore.rb.bak +277 -0
- metadata +136 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
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: []
|