fluent-plugin-pgjson 0.0.9 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7196d7c7b7181d2837c5a7e037caaf228335c1cac0b60b8212848d5b354652e3
4
- data.tar.gz: a5c3f94dd289a27641c40daaa46a665b375afe9023ccbece49f44cd6338ff7fb
3
+ metadata.gz: a4583a2849d4add68b6735fd279bed9d975fc9f78e88043cf07dee81bbcbb4f4
4
+ data.tar.gz: 2b13f3c83f4b35f605450c304b01d1a2510f5928609847aa7036f2ad885ec362
5
5
  SHA512:
6
- metadata.gz: adc06d292c08d6bccc5b7ad4471abfbbe585af918044b306249f1c1f7ceb18eb3dd0eabbaedf2ddf04e62c88077d931288437be3faae7a272af731887d628e42
7
- data.tar.gz: 7f627fdf20323d838f2254f7f64b101e5937e47b6113dd2e380759549195c23f26abf852fffc0679cd925bcfbb126736e486433343887e24f87eab4bd319752b
6
+ metadata.gz: ee23b29a5a9d27a29be7bfa42e1ba4970e7876a2c422d535b9f47fb155a45c606646b5857a3865d4044bc7639a1966f4af6757f407d55ae47dac9026300f3c92
7
+ data.tar.gz: 7cb84bc39f1bfa14be686a31a6b14d3f47bf552c368b99ed4dbed8844ee6b726e514f5957d01a60009ecb03a9883871fb0d34c004f3cb3988a3e1bb3d6bec1e9
@@ -0,0 +1,17 @@
1
+ language: ruby
2
+
3
+ rvm:
4
+ - 2.2
5
+ - 2.3
6
+ - 2.4
7
+ - 2.5
8
+
9
+ addons:
10
+ postgresql: "9.6"
11
+
12
+ services:
13
+ - postgresql
14
+
15
+ before_script:
16
+ - psql -c "create role fluentd with LOGIN CREATEDB password 'fluentd';" -U postgres
17
+ - psql -c "create database pgjsontest owner fluentd encoding 'utf-8'" -U postgres
data/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
- source 'https://rubygems.org'
1
+ source "https://rubygems.org"
2
2
 
3
3
  # Specify your gem's dependencies in fluent-plugin-pgjson.gemspec
4
4
  gemspec
data/README.md CHANGED
@@ -4,19 +4,28 @@ Output Plugin for PostgreSQL Json Type.
4
4
 
5
5
  <b>Json type is availble in PostgreSQL version over 9.2</b>
6
6
 
7
+ ## Requirements
8
+
9
+ | fluent-plugin-pgjson | fluentd | Ruby |
10
+ |----------------------|------------|--------|
11
+ | >= 1.0.0 | >= v1.0.0 | >= 2.2 |
12
+ | < 1.0.0 | >= v0.12.0 | >= 1.9 |
13
+
7
14
  ## Installation
8
15
 
9
- `$ fluent-gem install fluent-plugin-pgjson`
16
+ ```
17
+ $ fluent-gem install fluent-plugin-pgjson
18
+ ```
10
19
 
11
20
  ## Schema
12
21
 
13
- Specified table must have this schema.
22
+ Specified table must have following schema:
14
23
 
15
- |col|type|
16
- |---|---|
17
- |{tag_col}|Text|
18
- |{time_col}|Timestamp WITH TIME ZONE|
19
- |{record_col}|Json|
24
+ | col | type |
25
+ |--------------|--------------------------|
26
+ | {tag_col} | Text |
27
+ | {time_col} | Timestamp WITH TIME ZONE |
28
+ | {record_col} | Json |
20
29
 
21
30
  ### Example
22
31
 
@@ -39,19 +48,13 @@ CREATE TABLE fluentd (
39
48
  );
40
49
  ```
41
50
 
42
- ### Configurable JSON Encoder
43
-
44
- Fluentd's standard JSON encoder is `yajl`.
45
- `yajl` is robust for invalid byte sequence.
46
- But this plugin's default value is `json` which is Ruby standard JSON encoder for backward compatibility.
47
-
48
51
  ## Configuration
49
52
 
50
53
  ### Example
51
54
 
52
55
  ```
53
56
  <match **>
54
- type pgjson
57
+ @type pgjson
55
58
  host localhost
56
59
  port 5432
57
60
  sslmode require
@@ -67,20 +70,27 @@ But this plugin's default value is `json` which is Ruby standard JSON encoder fo
67
70
 
68
71
  ### Parameter
69
72
 
70
- |parameter|description|default|
71
- |---|---|---|
72
- |host|postgres server hostname|localhost|
73
- |port|postgres server port number|5432|
74
- |sslmode|use ssl (disable/allow/prefer/require)|prefer||
75
- |database|database name to which records will be inserted||
76
- |table|table name to which records will be inserted||
77
- |user|user name used to connect database|nil|
78
- |password|password uset to connect database|nil|
79
- |time_col|column name to insert time|time|
80
- |tag_col|column name to insert tag|tag|
81
- |record_col|column name to insert record|record|
82
- |msgpack|use msgpack format for inserting records|false|
83
- |encoder|choose prefer JSON encoder (yajl/json)|json|
73
+ * **host** (string) (optional): The hostname of PostgreSQL server
74
+ * Default value: `localhost`.
75
+ * **port** (integer) (optional): The port of PostgreSQL server
76
+ * Default value: `5432`.
77
+ * **sslmode** (enum) (optional): Set the sslmode to enable Eavesdropping protection/MITM protection. See [PostgreSQL Documentation](https://www.postgresql.org/docs/10/static/libpq-ssl.html) for more details.
78
+ * Available values: disable, allow, prefer, require, verify-ca, verify-full
79
+ * Default value: `prefer`.
80
+ * **database** (string) (required): The database name to connect
81
+ * **table** (string) (required): The table name to insert records
82
+ * **user** (string) (optional): The user name to connect database
83
+ * **password** (string) (optional): The password to connect database
84
+ * **time_col** (string) (optional): The column name for the time
85
+ * Default value: `time`.
86
+ * **tag_col** (string) (optional): The column name for the tag
87
+ * Default value: `tag`.
88
+ * **record_col** (string) (optional): The column name for the record
89
+ * Default value: `record`.
90
+ * **msgpack** (bool) (optional): If true, insert records formatted as msgpack
91
+ * **encoder** (enum) (optional): JSON encoder (yajl/json)
92
+ * Available values: yajl, json
93
+ * Default value: `yajl`.
84
94
 
85
95
  ## Copyright
86
96
 
data/Rakefile CHANGED
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env rake
2
2
  require "bundler/gem_tasks"
3
3
 
4
- require 'rake/testtask'
4
+ require "rake/testtask"
5
5
  Rake::TestTask.new(:test) do |test|
6
- test.libs << 'lib' << 'test'
7
- test.pattern = 'test/**/test_*.rb'
6
+ test.libs << "lib" << "test"
7
+ test.pattern = "test/**/test_*.rb"
8
8
  test.verbose = true
9
9
  end
10
10
 
@@ -1,13 +1,12 @@
1
- # -*- encoding: utf-8 -*-
2
1
  $:.push File.expand_path("../lib", __FILE__)
3
2
 
4
3
  Gem::Specification.new do |s|
5
4
  s.name = "fluent-plugin-pgjson"
6
- s.version = "0.0.9"
5
+ s.version = "1.0.0"
7
6
  s.authors = ["OKUNO Akihiro"]
8
7
  s.email = ["choplin.choplin@gmail.com"]
9
- s.homepage = "https://github.com/choplin/fluent-plugin-pgjson"
10
- s.summary = %q{}
8
+ s.homepage = "https://github.com/fluent-plugins-nursery/fluent-plugin-pgjson"
9
+ s.summary = %q{Fluentd Output Plugin for PostgreSQL JSON Type.}
11
10
  s.description = %q{}
12
11
  s.license = "Apache-2.0"
13
12
 
@@ -16,7 +15,7 @@ Gem::Specification.new do |s|
16
15
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
17
16
  s.require_paths = ["lib"]
18
17
 
19
- s.add_runtime_dependency "fluentd"
18
+ s.add_runtime_dependency "fluentd", ">=1.0.0", "<2"
20
19
  s.add_runtime_dependency "pg"
21
20
  s.add_development_dependency "test-unit", ">= 3.1.0"
22
21
  s.add_development_dependency "rake", ">= 11.0"
@@ -1,121 +1,133 @@
1
- require 'fluent/plugin/output'
2
- require 'pg'
3
- require 'yajl'
4
- require 'json'
1
+ require "fluent/plugin/output"
2
+ require "pg"
3
+ require "yajl"
4
+ require "json"
5
5
 
6
6
  module Fluent::Plugin
7
+ class PgJsonOutput < Fluent::Plugin::Output
8
+ Fluent::Plugin.register_output("pgjson", self)
9
+
10
+ helpers :compat_parameters
11
+
12
+ DEFAULT_BUFFER_TYPE = "memory"
13
+
14
+ desc "The hostname of PostgreSQL server"
15
+ config_param :host, :string, default: "localhost"
16
+ desc "The port of PostgreSQL server"
17
+ config_param :port, :integer, default: 5432
18
+ desc "Set the sslmode to enable Eavesdropping protection/MITM protection"
19
+ config_param :sslmode, :enum, list: %i[disable allow prefer require verify-ca verify-full], default: :prefer
20
+ desc "The database name to connect"
21
+ config_param :database, :string
22
+ desc "The table name to insert records"
23
+ config_param :table, :string
24
+ desc "The user name to connect database"
25
+ config_param :user, :string, default: nil
26
+ desc "The password to connect database"
27
+ config_param :password, :string, default: nil, secret: true
28
+ desc "The column name for the time"
29
+ config_param :time_col, :string, default: "time"
30
+ desc "The column name for the tag"
31
+ config_param :tag_col, :string, default: "tag"
32
+ desc "The column name for the record"
33
+ config_param :record_col, :string, default: "record"
34
+ desc "If true, insert records formatted as msgpack"
35
+ config_param :msgpack, :bool, default: false
36
+ desc "JSON encoder (yajl/json)"
37
+ config_param :encoder, :enum, list: [:yajl, :json], default: :yajl
38
+
39
+ config_param :time_format, :string, default: "%F %T.%N %z"
40
+
41
+ config_section :buffer do
42
+ config_set_default :@type, DEFAULT_BUFFER_TYPE
43
+ config_set_default :chunk_keys, ["tag"]
44
+ end
7
45
 
8
- class PgJsonOutput < Fluent::Output
9
- Fluent::Plugin.register_output('pgjson', self)
10
-
11
- helpers :compat_parameters
12
-
13
- DEFAULT_BUFFER_TYPE = "memory"
14
-
15
- config_param :host , :string , :default => 'localhost'
16
- config_param :port , :integer , :default => 5432
17
- config_param :sslmode , :string , :default => 'prefer'
18
- config_param :database , :string
19
- config_param :table , :string
20
- config_param :user , :string , :default => nil
21
- config_param :password , :string , :default => nil , :secret => true
22
- config_param :time_col , :string , :default => 'time'
23
- config_param :tag_col , :string , :default => 'tag'
24
- config_param :record_col , :string , :default => 'record'
25
- config_param :msgpack , :bool , :default => false
26
- config_param :encoder , :enum, list: [:yajl, :json], :default => :json
27
- config_param :time_format, :string , :default => '%F %T.%N %z'
28
-
29
- config_section :buffer do
30
- config_set_default :@type, DEFAULT_BUFFER_TYPE
31
- config_set_default :chunk_keys, ['tag']
32
- end
33
-
34
- def initialize
35
- super
36
- @conn = nil
37
- end
38
-
39
- def configure(conf)
40
- compat_parameters_convert(conf, :buffer)
41
- super
42
- unless @chunk_key_tag
43
- raise Fluent::ConfigError, "'tag' in chunk_keys is required."
46
+ def initialize
47
+ super
48
+ @conn = nil
44
49
  end
45
- @encoder = case @encoder
46
- when :yajl
47
- Yajl
48
- when :json
49
- JSON
50
- end
51
- end
52
50
 
53
- def shutdown
54
- if ! @conn.nil? and ! @conn.finished?
55
- @conn.close()
51
+ def configure(conf)
52
+ compat_parameters_convert(conf, :buffer)
53
+ super
54
+ unless @chunk_key_tag
55
+ raise Fluent::ConfigError, "'tag' in chunk_keys is required."
56
+ end
57
+ @encoder = case @encoder
58
+ when :yajl
59
+ Yajl
60
+ when :json
61
+ JSON
62
+ end
56
63
  end
57
64
 
58
- super
59
- end
65
+ def shutdown
66
+ if ! @conn.nil? and ! @conn.finished?
67
+ @conn.close()
68
+ end
60
69
 
61
- def formatted_to_msgpack_binary
62
- true
63
- end
70
+ super
71
+ end
64
72
 
65
- def multi_workers_ready?
66
- true
67
- end
73
+ def formatted_to_msgpack_binary
74
+ true
75
+ end
68
76
 
69
- def format(tag, time, record)
70
- [Time.at(time).strftime(@time_format), record].to_msgpack
71
- end
77
+ def multi_workers_ready?
78
+ true
79
+ end
80
+
81
+ def format(tag, time, record)
82
+ [Time.at(time).strftime(@time_format), record].to_msgpack
83
+ end
72
84
 
73
- def write(chunk)
74
- init_connection
75
- @conn.exec("COPY #{@table} (#{@tag_col}, #{@time_col}, #{@record_col}) FROM STDIN WITH DELIMITER E'\\x01'")
76
- begin
77
- tag = chunk.metadata.tag
78
- chunk.msgpack_each do |time, record|
79
- @conn.put_copy_data "#{tag}\x01#{time}\x01#{record_value(record)}\n"
85
+ def write(chunk)
86
+ init_connection
87
+ @conn.exec("COPY #{@table} (#{@tag_col}, #{@time_col}, #{@record_col}) FROM STDIN WITH DELIMITER E'\\x01'")
88
+ begin
89
+ tag = chunk.metadata.tag
90
+ chunk.msgpack_each do |time, record|
91
+ @conn.put_copy_data "#{tag}\x01#{time}\x01#{record_value(record)}\n"
92
+ end
93
+ rescue => err
94
+ errmsg = "%s while copy data: %s" % [ err.class.name, err.message ]
95
+ @conn.put_copy_end( errmsg )
96
+ @conn.get_result
97
+ raise
98
+ else
99
+ @conn.put_copy_end
100
+ res = @conn.get_result
101
+ raise res.result_error_message if res.result_status!=PG::PGRES_COMMAND_OK
80
102
  end
81
- rescue => err
82
- errmsg = "%s while copy data: %s" % [ err.class.name, err.message ]
83
- @conn.put_copy_end( errmsg )
84
- @conn.get_result
85
- raise
86
- else
87
- @conn.put_copy_end
88
- res = @conn.get_result
89
- raise res.result_error_message if res.result_status!=PG::PGRES_COMMAND_OK
90
103
  end
91
- end
92
104
 
93
- private
94
- def init_connection
95
- if @conn.nil?
96
- $log.debug "connecting to PostgreSQL server #{@host}:#{@port}, database #{@database}..."
105
+ private
97
106
 
98
- begin
99
- @conn = PG::Connection.new(:dbname => @database, :host => @host, :port => @port, :sslmode => @sslmode, :user => @user, :password => @password)
100
- rescue
101
- if ! @conn.nil?
102
- @conn.close()
103
- @conn = nil
107
+ def init_connection
108
+ if @conn.nil?
109
+ log.debug "connecting to PostgreSQL server #{@host}:#{@port}, database #{@database}..."
110
+
111
+ begin
112
+ @conn = PG::Connection.new(dbname: @database, host: @host, port: @port, sslmode: @sslmode, user: @user, password: @password)
113
+ rescue
114
+ if ! @conn.nil?
115
+ @conn.close()
116
+ @conn = nil
117
+ end
118
+ raise "failed to initialize connection: #$!"
104
119
  end
105
- raise "failed to initialize connection: #$!"
106
120
  end
107
121
  end
108
- end
109
122
 
110
- def record_value(record)
111
- if @msgpack
112
- "\\#{@conn.escape_bytea(record.to_msgpack)}"
113
- else
114
- json = @encoder.dump(record)
115
- json.gsub!(/\\/){ '\\\\' }
116
- json
123
+ def record_value(record)
124
+ if @msgpack
125
+ "\\#{@conn.escape_bytea(record.to_msgpack)}"
126
+ else
127
+ json = @encoder.dump(record)
128
+ json.gsub!(/\\/){ '\\\\' }
129
+ json
130
+ end
117
131
  end
118
132
  end
119
133
  end
120
-
121
- end
@@ -1,7 +1,7 @@
1
- require 'bundler/setup'
2
- require 'test/unit'
1
+ require "bundler/setup"
2
+ require "test/unit"
3
3
 
4
- $LOAD_PATH.unshift(File.join(__dir__, '..', 'lib'))
4
+ $LOAD_PATH.unshift(File.join(__dir__, "..", "lib"))
5
5
  $LOAD_PATH.unshift(__dir__)
6
- require 'fluent/test'
7
- require 'fluent/plugin/out_pgjson'
6
+ require "fluent/test"
7
+ require "fluent/plugin/out_pgjson"
@@ -1,26 +1,26 @@
1
- require 'pg'
2
- require 'securerandom'
3
- require 'helper'
4
- require 'fluent/test/driver/output'
5
- require 'fluent/test/helpers'
1
+ require "pg"
2
+ require "securerandom"
3
+ require "helper"
4
+ require "fluent/test/driver/output"
5
+ require "fluent/test/helpers"
6
6
 
7
7
  class PgJsonOutputTest < Test::Unit::TestCase
8
8
  include Fluent::Test::Helpers
9
9
 
10
10
  HOST = "localhost"
11
11
  PORT = 5432
12
- DATABASE = "postgres"
12
+ DATABASE = "pgjsontest"
13
13
  TABLE = "test_fluentd_#{SecureRandom.hex}"
14
- USER = ENV["PSQL_USER"] || "postgres"
15
- PASSWORD = ENV["PSQL_PASSWORD"] || "postgres"
14
+ USER = "fluentd"
15
+ PASSWORD = "fluentd"
16
16
 
17
17
  TIME_COL = "time"
18
18
  TAG_COL = "tag"
19
19
  RECORD_COL = "record"
20
- ENCODER = JSON
20
+ ENCODER = Yajl
21
21
 
22
22
  CONFIG = %[
23
- type pgjson
23
+ @type pgjson
24
24
  host #{HOST}
25
25
  port #{PORT}
26
26
  database #{DATABASE}
@@ -58,20 +58,20 @@ class PgJsonOutputTest < Test::Unit::TestCase
58
58
  def test_invalid_chunk_keys
59
59
  assert_raise_message(/'tag' in chunk_keys is required./) do
60
60
  create_driver(Fluent::Config::Element.new(
61
- 'ROOT', '', {
62
- '@type' => 'pgjson',
63
- 'host' => "#{HOST}",
64
- 'port' => "#{PORT}",
65
- 'database' => "#{DATABASE}",
66
- 'table' => "#{TABLE}",
67
- 'user' => "#{USER}",
68
- 'password' => "#{PASSWORD}",
69
- 'time_col' => "#{TIME_COL}",
70
- 'tag_col' => "#{TAG_COL}",
71
- 'record_col' => "#{RECORD_COL}",
61
+ "ROOT", "", {
62
+ "@type" => "pgjson",
63
+ "host" => "#{HOST}",
64
+ "port" => "#{PORT}",
65
+ "database" => "#{DATABASE}",
66
+ "table" => "#{TABLE}",
67
+ "user" => "#{USER}",
68
+ "password" => "#{PASSWORD}",
69
+ "time_col" => "#{TIME_COL}",
70
+ "tag_col" => "#{TAG_COL}",
71
+ "record_col" => "#{RECORD_COL}",
72
72
  }, [
73
- Fluent::Config::Element.new('buffer', 'mykey', {
74
- 'chunk_keys' => 'mykey'
73
+ Fluent::Config::Element.new("buffer", "mykey", {
74
+ "chunk_keys" => "mykey"
75
75
  }, [])
76
76
  ]))
77
77
  end
@@ -79,7 +79,7 @@ class PgJsonOutputTest < Test::Unit::TestCase
79
79
 
80
80
  def test_write
81
81
  with_connection do |conn|
82
- tag = 'test'
82
+ tag = "test"
83
83
  time = event_time("2014-12-26 07:58:37 UTC")
84
84
  record = {"a"=>1}
85
85
 
@@ -98,7 +98,7 @@ class PgJsonOutputTest < Test::Unit::TestCase
98
98
 
99
99
  def test_escape_of_backslash
100
100
  with_connection do |conn|
101
- tag = 'test'
101
+ tag = "test"
102
102
  time = event_time("2014-12-26 07:58:37 UTC")
103
103
  record = {"a"=>"\"foo\""}
104
104
 
@@ -117,13 +117,13 @@ class PgJsonOutputTest < Test::Unit::TestCase
117
117
 
118
118
  def test_invalid_json
119
119
  with_connection do |conn|
120
- tag = 'test'
120
+ tag = "test"
121
121
  time = event_time("2014-12-26 07:58:37 UTC")
122
122
 
123
123
  d = create_driver(CONFIG)
124
124
  instance = d.instance
125
125
  def instance.record_value(record)
126
- 'invalid json'
126
+ "invalid json"
127
127
  end
128
128
 
129
129
  assert_raise RuntimeError do
@@ -139,7 +139,7 @@ class PgJsonOutputTest < Test::Unit::TestCase
139
139
  conn = nil
140
140
 
141
141
  assert_nothing_raised do
142
- conn = PG::Connection.new(:dbname => DATABASE, :host => HOST, :port => PORT, :user => USER, :password => PASSWORD)
142
+ conn = PG::Connection.new(dbname: DATABASE, host: HOST, port: PORT, user: USER, password: PASSWORD)
143
143
  end
144
144
 
145
145
  conn
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fluent-plugin-pgjson
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.9
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - OKUNO Akihiro
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-06-24 00:00:00.000000000 Z
11
+ date: 2018-08-23 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: 1.0.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: 1.0.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
@@ -74,6 +80,7 @@ extensions: []
74
80
  extra_rdoc_files: []
75
81
  files:
76
82
  - ".gitignore"
83
+ - ".travis.yml"
77
84
  - Gemfile
78
85
  - LICENSE
79
86
  - README.md
@@ -83,7 +90,7 @@ files:
83
90
  - lib/fluent/plugin/out_pgjson.rb
84
91
  - test/helper.rb
85
92
  - test/plugin/test_out.rb
86
- homepage: https://github.com/choplin/fluent-plugin-pgjson
93
+ homepage: https://github.com/fluent-plugins-nursery/fluent-plugin-pgjson
87
94
  licenses:
88
95
  - Apache-2.0
89
96
  metadata: {}
@@ -106,7 +113,5 @@ rubyforge_project:
106
113
  rubygems_version: 2.7.6
107
114
  signing_key:
108
115
  specification_version: 4
109
- summary: ''
110
- test_files:
111
- - test/helper.rb
112
- - test/plugin/test_out.rb
116
+ summary: Fluentd Output Plugin for PostgreSQL JSON Type.
117
+ test_files: []