fluentd 1.11.4-x64-mingw32 → 1.12.3-x64-mingw32
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of fluentd might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.deepsource.toml +13 -0
- data/.github/ISSUE_TEMPLATE/bug_report.md +1 -1
- data/.github/ISSUE_TEMPLATE/config.yml +5 -0
- data/.github/workflows/linux-test.yaml +36 -0
- data/.github/workflows/macos-test.yaml +30 -0
- data/.github/workflows/stale-actions.yml +22 -0
- data/.github/workflows/windows-test.yaml +35 -0
- data/.gitlab-ci.yml +41 -19
- data/CHANGELOG.md +166 -0
- data/MAINTAINERS.md +5 -2
- data/README.md +7 -4
- data/bin/fluent-cap-ctl +7 -0
- data/bin/fluent-ctl +7 -0
- data/fluentd.gemspec +7 -5
- data/lib/fluent/capability.rb +87 -0
- data/lib/fluent/command/bundler_injection.rb +1 -1
- data/lib/fluent/command/ca_generate.rb +6 -3
- data/lib/fluent/command/cap_ctl.rb +174 -0
- data/lib/fluent/command/cat.rb +0 -1
- data/lib/fluent/command/ctl.rb +177 -0
- data/lib/fluent/command/fluentd.rb +4 -0
- data/lib/fluent/command/plugin_config_formatter.rb +18 -2
- data/lib/fluent/command/plugin_generator.rb +31 -1
- data/lib/fluent/compat/parser.rb +2 -2
- data/lib/fluent/config/section.rb +2 -2
- data/lib/fluent/config/types.rb +2 -2
- data/lib/fluent/env.rb +4 -0
- data/lib/fluent/event.rb +3 -13
- data/lib/fluent/load.rb +0 -1
- data/lib/fluent/plugin.rb +5 -0
- data/lib/fluent/plugin/buffer.rb +2 -21
- data/lib/fluent/plugin/file_wrapper.rb +39 -3
- data/lib/fluent/plugin/formatter.rb +24 -0
- data/lib/fluent/plugin/formatter_csv.rb +1 -1
- data/lib/fluent/plugin/formatter_hash.rb +3 -1
- data/lib/fluent/plugin/formatter_json.rb +3 -1
- data/lib/fluent/plugin/formatter_ltsv.rb +7 -5
- data/lib/fluent/plugin/formatter_out_file.rb +6 -4
- data/lib/fluent/plugin/formatter_single_value.rb +4 -2
- data/lib/fluent/plugin/formatter_tsv.rb +4 -2
- data/lib/fluent/plugin/in_http.rb +24 -3
- data/lib/fluent/plugin/in_monitor_agent.rb +1 -1
- data/lib/fluent/plugin/in_tail.rb +129 -41
- data/lib/fluent/plugin/in_tail/position_file.rb +39 -14
- data/lib/fluent/plugin/in_tcp.rb +1 -0
- data/lib/fluent/plugin/out_copy.rb +18 -5
- data/lib/fluent/plugin/out_exec_filter.rb +3 -3
- data/lib/fluent/plugin/out_forward.rb +61 -28
- data/lib/fluent/plugin/out_http.rb +28 -3
- data/lib/fluent/plugin/output.rb +18 -10
- data/lib/fluent/plugin/parser_csv.rb +2 -2
- data/lib/fluent/plugin/parser_syslog.rb +2 -2
- data/lib/fluent/plugin/storage_local.rb +4 -4
- data/lib/fluent/plugin_helper/http_server/compat/server.rb +1 -1
- data/lib/fluent/plugin_helper/inject.rb +4 -2
- data/lib/fluent/plugin_helper/retry_state.rb +4 -0
- data/lib/fluent/plugin_helper/server.rb +4 -2
- data/lib/fluent/plugin_helper/socket_option.rb +2 -2
- data/lib/fluent/supervisor.rb +153 -48
- data/lib/fluent/system_config.rb +2 -1
- data/lib/fluent/time.rb +58 -1
- data/lib/fluent/version.rb +1 -1
- data/lib/fluent/winsvc.rb +22 -4
- data/templates/new_gem/fluent-plugin.gemspec.erb +3 -3
- data/templates/plugin_config_formatter/param.md-table.erb +10 -0
- data/test/command/test_binlog_reader.rb +22 -6
- data/test/command/test_cap_ctl.rb +100 -0
- data/test/command/test_ctl.rb +57 -0
- data/test/command/test_fluentd.rb +38 -0
- data/test/command/test_plugin_config_formatter.rb +124 -2
- data/test/config/test_configurable.rb +1 -1
- data/test/plugin/in_tail/test_position_file.rb +46 -26
- data/test/plugin/test_file_wrapper.rb +105 -0
- data/test/plugin/test_filter_stdout.rb +6 -1
- data/test/plugin/test_formatter_hash.rb +6 -3
- data/test/plugin/test_formatter_json.rb +14 -4
- data/test/plugin/test_formatter_ltsv.rb +13 -5
- data/test/plugin/test_formatter_out_file.rb +35 -14
- data/test/plugin/test_formatter_single_value.rb +12 -6
- data/test/plugin/test_formatter_tsv.rb +12 -4
- data/test/plugin/test_in_exec.rb +1 -1
- data/test/plugin/test_in_http.rb +25 -0
- data/test/plugin/test_in_tail.rb +503 -42
- data/test/plugin/test_out_copy.rb +87 -0
- data/test/plugin/test_out_file.rb +23 -18
- data/test/plugin/test_out_forward.rb +94 -6
- data/test/plugin/test_out_http.rb +20 -1
- data/test/plugin/test_output.rb +15 -3
- data/test/plugin/test_output_as_buffered_backup.rb +2 -0
- data/test/plugin/test_parser_csv.rb +14 -0
- data/test/plugin/test_parser_syslog.rb +16 -2
- data/test/plugin/test_sd_file.rb +1 -1
- data/test/plugin_helper/service_discovery/test_manager.rb +1 -1
- data/test/plugin_helper/test_child_process.rb +5 -2
- data/test/plugin_helper/test_compat_parameters.rb +7 -2
- data/test/plugin_helper/test_http_server_helper.rb +4 -2
- data/test/plugin_helper/test_inject.rb +29 -0
- data/test/plugin_helper/test_server.rb +26 -7
- data/test/test_capability.rb +74 -0
- data/test/test_event.rb +16 -0
- data/test/test_formatter.rb +64 -10
- data/test/test_output.rb +8 -3
- data/test/test_supervisor.rb +150 -1
- data/test/test_time_parser.rb +109 -0
- metadata +87 -33
- data/.travis.yml +0 -57
- data/appveyor.yml +0 -28
@@ -163,6 +163,10 @@ op.on('--conf-encoding ENCODING', "specify configuration file encoding") { |s|
|
|
163
163
|
opts[:conf_encoding] = s
|
164
164
|
}
|
165
165
|
|
166
|
+
op.on('--disable-shared-socket', "Don't open shared socket for multiple workers") { |b|
|
167
|
+
opts[:disable_shared_socket] = b
|
168
|
+
}
|
169
|
+
|
166
170
|
if Fluent.windows?
|
167
171
|
require 'windows/library'
|
168
172
|
include Windows::Library
|
@@ -29,7 +29,8 @@ class FluentPluginConfigFormatter
|
|
29
29
|
AVAILABLE_FORMATS = [:markdown, :txt, :json]
|
30
30
|
SUPPORTED_TYPES = [
|
31
31
|
"input", "output", "filter",
|
32
|
-
"buffer", "parser", "formatter", "storage"
|
32
|
+
"buffer", "parser", "formatter", "storage",
|
33
|
+
"service_discovery"
|
33
34
|
]
|
34
35
|
|
35
36
|
DOCS_BASE_URL = "https://docs.fluentd.org/v/1.0"
|
@@ -43,6 +44,7 @@ class FluentPluginConfigFormatter
|
|
43
44
|
@verbose = false
|
44
45
|
@libs = []
|
45
46
|
@plugin_dirs = []
|
47
|
+
@table = false
|
46
48
|
@options = {}
|
47
49
|
|
48
50
|
prepare_option_parser
|
@@ -161,9 +163,20 @@ class FluentPluginConfigFormatter
|
|
161
163
|
else
|
162
164
|
sections, params = base_section.partition {|_name, value| value[:section] }
|
163
165
|
end
|
166
|
+
if @table && (not params.empty?)
|
167
|
+
dumped << "### Configuration\n\n"
|
168
|
+
dumped << "|parameter|type|description|default|\n"
|
169
|
+
dumped << "|---|---|---|---|\n"
|
170
|
+
end
|
164
171
|
params.each do |name, config|
|
165
172
|
next if name == :section
|
166
|
-
template_name = @compact
|
173
|
+
template_name = if @compact
|
174
|
+
"param.md-compact.erb"
|
175
|
+
elsif @table
|
176
|
+
"param.md-table.erb"
|
177
|
+
else
|
178
|
+
"param.md.erb"
|
179
|
+
end
|
167
180
|
template = template_path(template_name).read
|
168
181
|
dumped <<
|
169
182
|
if ERB.instance_method(:initialize).parameters.assoc(:key) # Ruby 2.6+
|
@@ -256,6 +269,9 @@ BANNER
|
|
256
269
|
@parser.on("-p", "--plugin=DIR", "Add plugin directory") do |s|
|
257
270
|
@plugin_dirs << s
|
258
271
|
end
|
272
|
+
@parser.on("-t", "--table", "Use table syntax to dump parameters") do
|
273
|
+
@table = true
|
274
|
+
end
|
259
275
|
end
|
260
276
|
|
261
277
|
def parse_options!
|
@@ -105,7 +105,7 @@ Generate a project skeleton for creating a Fluentd plugin
|
|
105
105
|
|
106
106
|
Arguments:
|
107
107
|
\ttype: #{SUPPORTED_TYPES.join(",")}
|
108
|
-
\tname: Your plugin name
|
108
|
+
\tname: Your plugin name (fluent-plugin- prefix will be added to <name>)
|
109
109
|
|
110
110
|
Options:
|
111
111
|
BANNER
|
@@ -151,6 +151,36 @@ BANNER
|
|
151
151
|
underscore_name
|
152
152
|
end
|
153
153
|
|
154
|
+
def gem_file_path
|
155
|
+
File.expand_path(File.join(File.dirname(__FILE__),
|
156
|
+
"../../../",
|
157
|
+
"Gemfile"))
|
158
|
+
end
|
159
|
+
|
160
|
+
def lock_file_path
|
161
|
+
File.expand_path(File.join(File.dirname(__FILE__),
|
162
|
+
"../../../",
|
163
|
+
"Gemfile.lock"))
|
164
|
+
end
|
165
|
+
|
166
|
+
def locked_gem_version(gem_name)
|
167
|
+
d = Bundler::Definition.build(gem_file_path, lock_file_path, false)
|
168
|
+
d.locked_gems.dependencies[gem_name].requirement.requirements.first.last.version
|
169
|
+
end
|
170
|
+
|
171
|
+
def rake_version
|
172
|
+
locked_gem_version("rake")
|
173
|
+
end
|
174
|
+
|
175
|
+
def test_unit_version
|
176
|
+
locked_gem_version("test-unit")
|
177
|
+
end
|
178
|
+
|
179
|
+
def bundler_version
|
180
|
+
d = Bundler::Definition.build(gem_file_path, lock_file_path, false)
|
181
|
+
d.locked_gems.bundler_version.version
|
182
|
+
end
|
183
|
+
|
154
184
|
def class_name
|
155
185
|
"#{capitalized_name}#{type.capitalize}"
|
156
186
|
end
|
data/lib/fluent/compat/parser.rb
CHANGED
@@ -244,10 +244,10 @@ module Fluent
|
|
244
244
|
end
|
245
245
|
|
246
246
|
def convert_value_to_nil(value)
|
247
|
-
if value
|
247
|
+
if value && @null_empty_string
|
248
248
|
value = (value == '') ? nil : value
|
249
249
|
end
|
250
|
-
if value
|
250
|
+
if value && @null_value_pattern
|
251
251
|
value = ::Fluent::StringUtil.match_regexp(@null_value_pattern, value) ? nil : value
|
252
252
|
end
|
253
253
|
value
|
@@ -179,7 +179,7 @@ module Fluent
|
|
179
179
|
end
|
180
180
|
|
181
181
|
if section_params[varname].nil?
|
182
|
-
unless proxy.defaults.has_key?(varname)
|
182
|
+
unless proxy.defaults.has_key?(varname) && proxy.defaults[varname].nil?
|
183
183
|
logger.error "config error in:\n#{conf}" if logger
|
184
184
|
raise ConfigError, "'#{name}' parameter is required but nil is specified"
|
185
185
|
end
|
@@ -247,7 +247,7 @@ module Fluent
|
|
247
247
|
def self.check_unused_section(proxy, conf, plugin_class)
|
248
248
|
elems = conf.respond_to?(:elements) ? conf.elements : []
|
249
249
|
elems.each { |e|
|
250
|
-
next if plugin_class.nil? && Fluent::Config::V1Parser::ELEM_SYMBOLS.include?(e.name) # skip pre-defined non-plugin elements because it
|
250
|
+
next if plugin_class.nil? && Fluent::Config::V1Parser::ELEM_SYMBOLS.include?(e.name) # skip pre-defined non-plugin elements because it doesn't have proxy section
|
251
251
|
next if e.unused_in && e.unused_in.empty? # the section is used at least once
|
252
252
|
|
253
253
|
if proxy.sections.any? { |name, subproxy| e.name == subproxy.name.to_s || e.name == subproxy.alias.to_s }
|
data/lib/fluent/config/types.rb
CHANGED
@@ -186,7 +186,7 @@ module Fluent
|
|
186
186
|
return nil if val.nil?
|
187
187
|
|
188
188
|
param = if val.is_a?(String)
|
189
|
-
val.start_with?('{') ? JSON.
|
189
|
+
val.start_with?('{') ? JSON.parse(val) : Hash[val.strip.split(/\s*,\s*/).map{|v| v.split(':', 2)}]
|
190
190
|
else
|
191
191
|
val
|
192
192
|
end
|
@@ -213,7 +213,7 @@ module Fluent
|
|
213
213
|
return nil if val.nil?
|
214
214
|
|
215
215
|
param = if val.is_a?(String)
|
216
|
-
val.start_with?('[') ? JSON.
|
216
|
+
val.start_with?('[') ? JSON.parse(val) : val.strip.split(/\s*,\s*/)
|
217
217
|
else
|
218
218
|
val
|
219
219
|
end
|
data/lib/fluent/env.rb
CHANGED
data/lib/fluent/event.rb
CHANGED
@@ -254,19 +254,9 @@ module Fluent
|
|
254
254
|
end
|
255
255
|
|
256
256
|
def each(unpacker: nil, &block)
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
end
|
261
|
-
else
|
262
|
-
@unpacked_times = []
|
263
|
-
@unpacked_records = []
|
264
|
-
(unpacker || Fluent::MessagePackFactory.msgpack_unpacker).feed_each(@data) do |time, record|
|
265
|
-
@unpacked_times << time
|
266
|
-
@unpacked_records << record
|
267
|
-
block.call(time, record)
|
268
|
-
end
|
269
|
-
@size = @unpacked_times.size
|
257
|
+
ensure_unpacked!(unpacker: unpacker)
|
258
|
+
@unpacked_times.each_with_index do |time, i|
|
259
|
+
block.call(time, @unpacked_records[i])
|
270
260
|
end
|
271
261
|
nil
|
272
262
|
end
|
data/lib/fluent/load.rb
CHANGED
data/lib/fluent/plugin.rb
CHANGED
@@ -121,6 +121,11 @@ module Fluent
|
|
121
121
|
new_impl('sd', SD_REGISTRY, type, parent)
|
122
122
|
end
|
123
123
|
|
124
|
+
class << self
|
125
|
+
# This should be defined for fluent-plugin-config-formatter type arguments.
|
126
|
+
alias_method :new_service_discovery, :new_sd
|
127
|
+
end
|
128
|
+
|
124
129
|
def self.new_parser(type, parent: nil)
|
125
130
|
if type[0] == '/' && type[-1] == '/'
|
126
131
|
# This usage is not recommended for new API... create RegexpParser directly
|
data/lib/fluent/plugin/buffer.rb
CHANGED
@@ -143,33 +143,14 @@ module Fluent
|
|
143
143
|
end
|
144
144
|
end
|
145
145
|
|
146
|
-
# timekey should be unixtime as usual.
|
147
|
-
# So, unixtime should be bigger than 2^30 - 1 (= 1073741823) nowadays.
|
148
|
-
# We should check object_id stability to use object_id as optimization for comparing operations.
|
149
|
-
# e.g.)
|
150
|
-
# irb> Time.parse("2020/07/31 18:30:00+09:00").to_i
|
151
|
-
# => 1596187800
|
152
|
-
# irb> Time.parse("2020/07/31 18:30:00+09:00").to_i > 2**30 -1
|
153
|
-
# => true
|
154
|
-
def self.enable_optimize?
|
155
|
-
a1 = 2**30 - 1
|
156
|
-
a2 = 2**30 - 1
|
157
|
-
b1 = 2**62 - 1
|
158
|
-
b2 = 2**62 - 1
|
159
|
-
(a1.object_id == a2.object_id) && (b1.object_id == b2.object_id)
|
160
|
-
end
|
161
|
-
|
162
146
|
# This is an optimization code. Current Struct's implementation is comparing all data.
|
163
147
|
# https://github.com/ruby/ruby/blob/0623e2b7cc621b1733a760b72af246b06c30cf96/struct.c#L1200-L1203
|
164
148
|
# Actually this overhead is very small but this class is generated *per chunk* (and used in hash object).
|
165
149
|
# This means that this class is one of the most called object in Fluentd.
|
166
150
|
# See https://github.com/fluent/fluentd/pull/2560
|
167
|
-
# But, this optimization has a side effect on Windows and 32bit environment(s) due to differing object_id.
|
168
|
-
# This difference causes flood of buffer files.
|
169
|
-
# So, this optimization should be enabled on `enable_optimize?` as true platforms.
|
170
151
|
def hash
|
171
|
-
timekey.
|
172
|
-
end
|
152
|
+
timekey.hash
|
153
|
+
end
|
173
154
|
end
|
174
155
|
|
175
156
|
# for tests
|
@@ -46,6 +46,42 @@ module Fluent
|
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
49
|
+
class Win32Error < StandardError
|
50
|
+
require 'windows/error'
|
51
|
+
include Windows::Error
|
52
|
+
|
53
|
+
attr_reader :errcode, :msg
|
54
|
+
|
55
|
+
def initialize(errcode, msg = nil)
|
56
|
+
@errcode = errcode
|
57
|
+
@msg = msg
|
58
|
+
end
|
59
|
+
|
60
|
+
def format_english_message(errcode)
|
61
|
+
buf = 0.chr * 260
|
62
|
+
flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY
|
63
|
+
english_lang_id = 1033 # The result of MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US)
|
64
|
+
FormatMessageA.call(flags, 0, errcode, english_lang_id, buf, buf.size, 0)
|
65
|
+
buf.force_encoding(Encoding.default_external).strip
|
66
|
+
end
|
67
|
+
|
68
|
+
def to_s
|
69
|
+
msg = super
|
70
|
+
msg << ": code: #{@errcode}, #{format_english_message(@errcode)}"
|
71
|
+
msg << " - #{@msg}" if @msg
|
72
|
+
msg
|
73
|
+
end
|
74
|
+
|
75
|
+
def inspect
|
76
|
+
"#<#{to_s}>"
|
77
|
+
end
|
78
|
+
|
79
|
+
def ==(other)
|
80
|
+
return false if other.class != Win32Error
|
81
|
+
@errcode == other.errcode && @msg == other.msg
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
49
85
|
# To open and get stat with setting FILE_SHARE_DELETE
|
50
86
|
class WindowsFile
|
51
87
|
require 'windows/file'
|
@@ -77,11 +113,11 @@ module Fluent
|
|
77
113
|
@file_handle = CreateFile.call(@path, access, sharemode,
|
78
114
|
0, creationdisposition, FILE_ATTRIBUTE_NORMAL, 0)
|
79
115
|
if @file_handle == INVALID_HANDLE_VALUE
|
80
|
-
err =
|
116
|
+
err = Win32::API.last_error
|
81
117
|
if err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND || err == ERROR_ACCESS_DENIED
|
82
|
-
raise
|
118
|
+
raise Errno::ENOENT
|
83
119
|
end
|
84
|
-
raise
|
120
|
+
raise Win32Error.new(err, path)
|
85
121
|
end
|
86
122
|
end
|
87
123
|
|
@@ -46,5 +46,29 @@ module Fluent
|
|
46
46
|
@proc.call(tag, time, record)
|
47
47
|
end
|
48
48
|
end
|
49
|
+
|
50
|
+
module Newline
|
51
|
+
module Mixin
|
52
|
+
include Fluent::Configurable
|
53
|
+
|
54
|
+
DEFAULT_NEWLINE = if Fluent.windows?
|
55
|
+
:crlf
|
56
|
+
else
|
57
|
+
:lf
|
58
|
+
end
|
59
|
+
|
60
|
+
config_param :newline, :enum, list: [:lf, :crlf], default: DEFAULT_NEWLINE
|
61
|
+
|
62
|
+
def configure(conf)
|
63
|
+
super
|
64
|
+
@newline = case newline
|
65
|
+
when :lf
|
66
|
+
"\n".freeze
|
67
|
+
when :crlf
|
68
|
+
"\r\n".freeze
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
49
73
|
end
|
50
74
|
end
|
@@ -27,7 +27,7 @@ module Fluent
|
|
27
27
|
helpers :record_accessor
|
28
28
|
|
29
29
|
config_param :delimiter, default: ',' do |val|
|
30
|
-
['\t', 'TAB'].include?(val) ? "\t" : val
|
30
|
+
['\t', 'TAB'].include?(val) ? "\t".freeze : val.freeze
|
31
31
|
end
|
32
32
|
config_param :force_quotes, :bool, default: true
|
33
33
|
# "array" looks good for type of :fields, but this implementation removes tailing comma
|
@@ -19,13 +19,15 @@ require 'fluent/plugin/formatter'
|
|
19
19
|
module Fluent
|
20
20
|
module Plugin
|
21
21
|
class HashFormatter < Formatter
|
22
|
+
include Fluent::Plugin::Newline::Mixin
|
23
|
+
|
22
24
|
Plugin.register_formatter('hash', self)
|
23
25
|
|
24
26
|
config_param :add_newline, :bool, default: true
|
25
27
|
|
26
28
|
def format(tag, time, record)
|
27
29
|
line = record.to_s
|
28
|
-
line <<
|
30
|
+
line << @newline if @add_newline
|
29
31
|
line
|
30
32
|
end
|
31
33
|
end
|
@@ -20,6 +20,8 @@ require 'fluent/env'
|
|
20
20
|
module Fluent
|
21
21
|
module Plugin
|
22
22
|
class JSONFormatter < Formatter
|
23
|
+
include Fluent::Plugin::Newline::Mixin
|
24
|
+
|
23
25
|
Plugin.register_formatter('json', self)
|
24
26
|
|
25
27
|
config_param :json_parser, :string, default: 'oj'
|
@@ -44,7 +46,7 @@ module Fluent
|
|
44
46
|
end
|
45
47
|
|
46
48
|
def format(tag, time, record)
|
47
|
-
"#{@dump_proc.call(record)}
|
49
|
+
"#{@dump_proc.call(record)}#{@newline}"
|
48
50
|
end
|
49
51
|
|
50
52
|
def format_without_nl(tag, time, record)
|
@@ -19,22 +19,24 @@ require 'fluent/plugin/formatter'
|
|
19
19
|
module Fluent
|
20
20
|
module Plugin
|
21
21
|
class LabeledTSVFormatter < Formatter
|
22
|
+
include Fluent::Plugin::Newline::Mixin
|
23
|
+
|
22
24
|
Plugin.register_formatter('ltsv', self)
|
23
25
|
|
24
26
|
# http://ltsv.org/
|
25
27
|
|
26
|
-
config_param :delimiter, :string, default: "\t"
|
27
|
-
config_param :label_delimiter, :string, default: ":"
|
28
|
+
config_param :delimiter, :string, default: "\t".freeze
|
29
|
+
config_param :label_delimiter, :string, default: ":".freeze
|
30
|
+
config_param :replacement, :string, default: " ".freeze
|
28
31
|
config_param :add_newline, :bool, default: true
|
29
32
|
|
30
|
-
# TODO: escaping for \t in values
|
31
33
|
def format(tag, time, record)
|
32
34
|
formatted = ""
|
33
35
|
record.each do |label, value|
|
34
36
|
formatted << @delimiter if formatted.length.nonzero?
|
35
|
-
formatted << "#{label}#{@label_delimiter}#{value}"
|
37
|
+
formatted << "#{label}#{@label_delimiter}#{value.to_s.gsub(@delimiter, @replacement)}"
|
36
38
|
end
|
37
|
-
formatted <<
|
39
|
+
formatted << @newline if @add_newline
|
38
40
|
formatted
|
39
41
|
end
|
40
42
|
end
|
@@ -21,15 +21,17 @@ require 'yajl'
|
|
21
21
|
module Fluent
|
22
22
|
module Plugin
|
23
23
|
class OutFileFormatter < Formatter
|
24
|
+
include Fluent::Plugin::Newline::Mixin
|
25
|
+
|
24
26
|
Plugin.register_formatter('out_file', self)
|
25
27
|
|
26
28
|
config_param :output_time, :bool, default: true
|
27
29
|
config_param :output_tag, :bool, default: true
|
28
30
|
config_param :delimiter, default: "\t" do |val|
|
29
31
|
case val
|
30
|
-
when /SPACE/i then ' '
|
31
|
-
when /COMMA/i then ','
|
32
|
-
else "\t"
|
32
|
+
when /SPACE/i then ' '.freeze
|
33
|
+
when /COMMA/i then ','.freeze
|
34
|
+
else "\t".freeze
|
33
35
|
end
|
34
36
|
end
|
35
37
|
config_set_default :time_type, :string
|
@@ -44,7 +46,7 @@ module Fluent
|
|
44
46
|
header = ''
|
45
47
|
header << "#{@timef.format(time)}#{@delimiter}" if @output_time
|
46
48
|
header << "#{tag}#{@delimiter}" if @output_tag
|
47
|
-
"#{header}#{Yajl.dump(record)}
|
49
|
+
"#{header}#{Yajl.dump(record)}#{@newline}"
|
48
50
|
end
|
49
51
|
end
|
50
52
|
end
|