fluentd 0.12.37 → 0.12.38
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/ChangeLog +19 -0
- data/lib/fluent/agent.rb +50 -2
- data/lib/fluent/engine.rb +9 -6
- data/lib/fluent/parser.rb +2 -2
- data/lib/fluent/plugin/filter_grep.rb +39 -12
- data/lib/fluent/plugin/in_syslog.rb +68 -29
- data/lib/fluent/version.rb +1 -1
- data/test/plugin/test_filter_grep.rb +73 -2
- data/test/plugin/test_in_syslog.rb +140 -1
- data/test/test_parser.rb +18 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8fc381ec2e8ffc7a3f6e196b597a324f3e6e553e
|
4
|
+
data.tar.gz: 2f1832c98553174c7fe96f87832898e669f985cb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cabc4f4b85ff50f0421b63f3ddceb2046a8354fac5097af1cbee43b32124e110ce8b12bf23fc55682c91266a63643ae7f38d142af146f903a4b049b162eb3073
|
7
|
+
data.tar.gz: bd375fc4feee2fa831c4bb03d1ed3118c3807434e250a0be635dadf5cac1654cdab666b069b1754d07d45c91c0207785ca083424968071c7baadb5d6080cb222
|
data/ChangeLog
CHANGED
@@ -1,5 +1,24 @@
|
|
1
1
|
# v0.12
|
2
2
|
|
3
|
+
## Release 0.12.38 - 2017/07/13
|
4
|
+
|
5
|
+
### New features / Enhancement
|
6
|
+
|
7
|
+
* in_syslog: Add Add allow_without_priority and default_priority parameters
|
8
|
+
https://github.com/fluent/fluentd/pull/1608
|
9
|
+
* in_syslog: More characters are available in tag part of syslog format
|
10
|
+
https://github.com/fluent/fluentd/pull/1609
|
11
|
+
* in_syslog: Add resolve_hostname and source_address_key parameters
|
12
|
+
https://github.com/fluent/fluentd/pull/1615
|
13
|
+
* filter_grep: Support new configuration format by config_section
|
14
|
+
https://github.com/fluent/fluentd/pull/1627
|
15
|
+
|
16
|
+
### Bug fixes
|
17
|
+
|
18
|
+
* log: Capture more fluentd log events during shutdown
|
19
|
+
https://github.com/fluent/fluentd/pull/1618
|
20
|
+
https://github.com/fluent/fluentd/pull/1625
|
21
|
+
|
3
22
|
## Release 0.12.37 - 2017/06/21
|
4
23
|
|
5
24
|
### New features / Enhancement
|
data/lib/fluent/agent.rb
CHANGED
@@ -38,6 +38,11 @@ module Fluent
|
|
38
38
|
@started_outputs = []
|
39
39
|
@started_filters = []
|
40
40
|
|
41
|
+
@outputs_for_log_event = []
|
42
|
+
@filters_for_log_event = []
|
43
|
+
@started_outputs_for_log_event = []
|
44
|
+
@started_filters_for_log_event = []
|
45
|
+
|
41
46
|
@log = Engine.log
|
42
47
|
@event_router = EventRouter.new(NoMatchMatch.new(log), self)
|
43
48
|
@error_collector = nil
|
@@ -70,16 +75,47 @@ module Fluent
|
|
70
75
|
@outputs.each { |o|
|
71
76
|
o.start
|
72
77
|
@started_outputs << o
|
78
|
+
@started_outputs_for_log_event << o if @outputs_for_log_event.include?(o)
|
73
79
|
}
|
74
80
|
|
75
81
|
@filters.each { |f|
|
76
82
|
f.start
|
77
83
|
@started_filters << f
|
84
|
+
@started_filters_for_log_event << f if @filters_for_log_event.include?(f)
|
78
85
|
}
|
79
86
|
end
|
80
87
|
|
81
88
|
def shutdown
|
82
|
-
@started_filters.map { |f|
|
89
|
+
(@started_filters - @started_filters_for_log_event).map { |f|
|
90
|
+
Thread.new do
|
91
|
+
begin
|
92
|
+
log.info "shutting down filter#{@context.nil? ? '' : " in #{@context}"}", type: Plugin.lookup_name_from_class(f.class), plugin_id: f.plugin_id
|
93
|
+
f.shutdown
|
94
|
+
rescue => e
|
95
|
+
log.warn "unexpected error while shutting down filter plugins", plugin: f.class, plugin_id: f.plugin_id, error_class: e.class, error: e
|
96
|
+
log.warn_backtrace
|
97
|
+
end
|
98
|
+
end
|
99
|
+
}.each { |t| t.join }
|
100
|
+
|
101
|
+
# Output plugin as filter emits records at shutdown so emit problem still exist.
|
102
|
+
# This problem will be resolved after actual filter mechanizm.
|
103
|
+
(@started_outputs - @started_outputs_for_log_event).map { |o|
|
104
|
+
Thread.new do
|
105
|
+
begin
|
106
|
+
log.info "shutting down output#{@context.nil? ? '' : " in #{@context}"}", type: Plugin.lookup_name_from_class(o.class), plugin_id: o.plugin_id
|
107
|
+
o.shutdown
|
108
|
+
rescue => e
|
109
|
+
log.warn "unexpected error while shutting down output plugins", plugin: o.class, plugin_id: o.plugin_id, error_class: e.class, error: e
|
110
|
+
log.warn_backtrace
|
111
|
+
end
|
112
|
+
end
|
113
|
+
}.each { |t| t.join }
|
114
|
+
|
115
|
+
## execute callback from Engine to flush log event queue before shutting down corresponding filters and outputs
|
116
|
+
yield if block_given?
|
117
|
+
|
118
|
+
@started_filters_for_log_event.map { |f|
|
83
119
|
Thread.new do
|
84
120
|
begin
|
85
121
|
log.info "shutting down filter#{@context.nil? ? '' : " in #{@context}"}", type: Plugin.lookup_name_from_class(f.class), plugin_id: f.plugin_id
|
@@ -93,7 +129,7 @@ module Fluent
|
|
93
129
|
|
94
130
|
# Output plugin as filter emits records at shutdown so emit problem still exist.
|
95
131
|
# This problem will be resolved after actual filter mechanizm.
|
96
|
-
@
|
132
|
+
@started_outputs_for_log_event.map { |o|
|
97
133
|
Thread.new do
|
98
134
|
begin
|
99
135
|
log.info "shutting down output#{@context.nil? ? '' : " in #{@context}"}", type: Plugin.lookup_name_from_class(o.class), plugin_id: o.plugin_id
|
@@ -134,6 +170,10 @@ module Fluent
|
|
134
170
|
@outputs << output
|
135
171
|
@event_router.add_rule(pattern, output)
|
136
172
|
|
173
|
+
if match_event_log_tag?(pattern)
|
174
|
+
@outputs_for_log_event << output
|
175
|
+
end
|
176
|
+
|
137
177
|
output
|
138
178
|
end
|
139
179
|
|
@@ -146,9 +186,17 @@ module Fluent
|
|
146
186
|
@filters << filter
|
147
187
|
@event_router.add_rule(pattern, filter)
|
148
188
|
|
189
|
+
if match_event_log_tag?(pattern)
|
190
|
+
@filters_for_log_event << filter
|
191
|
+
end
|
192
|
+
|
149
193
|
filter
|
150
194
|
end
|
151
195
|
|
196
|
+
def match_event_log_tag?(pattern)
|
197
|
+
EventRouter::Rule.new(pattern, nil).match?($log.tag)
|
198
|
+
end
|
199
|
+
|
152
200
|
# For handling invalid record
|
153
201
|
def emit_error_event(tag, time, record, error)
|
154
202
|
end
|
data/lib/fluent/engine.rb
CHANGED
@@ -165,7 +165,6 @@ module Fluent
|
|
165
165
|
$log.disable_events(Thread.current)
|
166
166
|
|
167
167
|
while sleep(LOG_EMIT_INTERVAL)
|
168
|
-
break if @log_event_loop_stop
|
169
168
|
next if @log_event_queue.empty?
|
170
169
|
|
171
170
|
# NOTE: thead-safe of slice! depends on GVL
|
@@ -179,6 +178,7 @@ module Fluent
|
|
179
178
|
$log.error "failed to emit fluentd's log event", tag: tag, event: record, error_class: e.class, error: e
|
180
179
|
end
|
181
180
|
}
|
181
|
+
break if @log_event_loop_stop
|
182
182
|
end
|
183
183
|
end
|
184
184
|
|
@@ -209,10 +209,13 @@ module Fluent
|
|
209
209
|
$log.error_backtrace
|
210
210
|
ensure
|
211
211
|
$log.info "shutting down fluentd"
|
212
|
-
shutdown
|
213
212
|
if @log_emit_thread
|
214
|
-
|
215
|
-
|
213
|
+
shutdown do
|
214
|
+
@log_event_loop_stop = true
|
215
|
+
@log_emit_thread.join
|
216
|
+
end
|
217
|
+
else
|
218
|
+
shutdown
|
216
219
|
end
|
217
220
|
end
|
218
221
|
end
|
@@ -237,8 +240,8 @@ module Fluent
|
|
237
240
|
@root_agent.start
|
238
241
|
end
|
239
242
|
|
240
|
-
def shutdown
|
241
|
-
@root_agent.shutdown
|
243
|
+
def shutdown(&block)
|
244
|
+
@root_agent.shutdown(&block)
|
242
245
|
end
|
243
246
|
end
|
244
247
|
|
data/lib/fluent/parser.rb
CHANGED
@@ -537,9 +537,9 @@ module Fluent
|
|
537
537
|
|
538
538
|
class SyslogParser < Parser
|
539
539
|
# From existence TextParser pattern
|
540
|
-
REGEXP = /^(?<time>[^ ]*\s*[^ ]* [^ ]*) (?<host>[^ ]*) (?<ident>[
|
540
|
+
REGEXP = /^(?<time>[^ ]*\s*[^ ]* [^ ]*) (?<host>[^ ]*) (?<ident>[^ :\[]*)(?:\[(?<pid>[0-9]+)\])?(?:[^\:]*\:)? *(?<message>.*)$/
|
541
541
|
# From in_syslog default pattern
|
542
|
-
REGEXP_WITH_PRI = /^\<(?<pri>[0-9]+)\>(?<time>[^ ]* {1,2}[^ ]* [^ ]*) (?<host>[^ ]*) (?<ident>[
|
542
|
+
REGEXP_WITH_PRI = /^\<(?<pri>[0-9]+)\>(?<time>[^ ]* {1,2}[^ ]* [^ ]*) (?<host>[^ ]*) (?<ident>[^ :\[]*)(?:\[(?<pid>[0-9]+)\])?(?:[^\:]*\:)? *(?<message>.*)$/
|
543
543
|
REGEXP_RFC5424 = /\A^(?<time>[^ ]+) (?<host>[^ ]+) (?<ident>[^ ]+) (?<pid>[-0-9]+) (?<msgid>[^ ]+) (?<extradata>(\[(.*)\]|[^ ])) (?<message>.+)$\z/
|
544
544
|
REGEXP_RFC5424_WITH_PRI = /\A^\<(?<pri>[0-9]{1,3})\>[1-9]\d{0,2} (?<time>[^ ]+) (?<host>[^ ]+) (?<ident>[^ ]+) (?<pid>[-0-9]+) (?<msgid>[^ ]+) (?<extradata>(\[(.*)\]|[^ ])) (?<message>.+)$\z/
|
545
545
|
REGEXP_DETECT_RFC5424 = /^\<.*\>[1-9]\d{0,2}/
|
@@ -28,32 +28,59 @@ module Fluent
|
|
28
28
|
|
29
29
|
REGEXP_MAX_NUM = 20
|
30
30
|
|
31
|
-
(1..REGEXP_MAX_NUM).each {|i| config_param :"regexp#{i}", :string, default: nil }
|
32
|
-
(1..REGEXP_MAX_NUM).each {|i| config_param :"exclude#{i}", :string, default: nil }
|
31
|
+
(1..REGEXP_MAX_NUM).each {|i| config_param :"regexp#{i}", :string, default: nil, deprecated: "Use <regexp> section" }
|
32
|
+
(1..REGEXP_MAX_NUM).each {|i| config_param :"exclude#{i}", :string, default: nil, deprecated: "Use <exclude> section" }
|
33
|
+
|
34
|
+
config_section :regexp, param_name: :regexps, multi: true do
|
35
|
+
desc "The field name to which the regular expression is applied."
|
36
|
+
config_param :key, :string
|
37
|
+
desc "The regular expression."
|
38
|
+
config_param :pattern do |value|
|
39
|
+
Regexp.compile(value)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
config_section :exclude, param_name: :excludes, multi: true do
|
44
|
+
desc "The field name to which the regular expression is applied."
|
45
|
+
config_param :key, :string
|
46
|
+
desc "The regular expression."
|
47
|
+
config_param :pattern do |value|
|
48
|
+
Regexp.compile(value)
|
49
|
+
end
|
50
|
+
end
|
33
51
|
|
34
52
|
# for test
|
35
|
-
attr_reader :
|
36
|
-
attr_reader :
|
53
|
+
attr_reader :_regexps
|
54
|
+
attr_reader :_excludes
|
37
55
|
|
38
56
|
def configure(conf)
|
39
57
|
super
|
40
58
|
|
41
|
-
@
|
59
|
+
@_regexps = {}
|
42
60
|
(1..REGEXP_MAX_NUM).each do |i|
|
43
61
|
next unless conf["regexp#{i}"]
|
44
62
|
key, regexp = conf["regexp#{i}"].split(/ /, 2)
|
45
63
|
raise ConfigError, "regexp#{i} does not contain 2 parameters" unless regexp
|
46
|
-
raise ConfigError, "regexp#{i} contains a duplicated key, #{key}" if @
|
47
|
-
@
|
64
|
+
raise ConfigError, "regexp#{i} contains a duplicated key, #{key}" if @_regexps[key]
|
65
|
+
@_regexps[key] = Regexp.compile(regexp)
|
48
66
|
end
|
49
67
|
|
50
|
-
@
|
68
|
+
@_excludes = {}
|
51
69
|
(1..REGEXP_MAX_NUM).each do |i|
|
52
70
|
next unless conf["exclude#{i}"]
|
53
71
|
key, exclude = conf["exclude#{i}"].split(/ /, 2)
|
54
72
|
raise ConfigError, "exclude#{i} does not contain 2 parameters" unless exclude
|
55
|
-
raise ConfigError, "exclude#{i} contains a duplicated key, #{key}" if @
|
56
|
-
@
|
73
|
+
raise ConfigError, "exclude#{i} contains a duplicated key, #{key}" if @_excludes[key]
|
74
|
+
@_excludes[key] = Regexp.compile(exclude)
|
75
|
+
end
|
76
|
+
|
77
|
+
@regexps.each do |e|
|
78
|
+
raise Fluent::ConfigError, "Duplicate key: #{e.key}" if @_regexps.key?(e.key)
|
79
|
+
@_regexps[e.key] = e.pattern
|
80
|
+
end
|
81
|
+
@excludes.each do |e|
|
82
|
+
raise Fluent::ConfigError, "Duplicate key: #{e.key}" if @_excludes.key?(e.key)
|
83
|
+
@_excludes[e.key] = e.pattern
|
57
84
|
end
|
58
85
|
end
|
59
86
|
|
@@ -61,10 +88,10 @@ module Fluent
|
|
61
88
|
result = nil
|
62
89
|
begin
|
63
90
|
catch(:break_loop) do
|
64
|
-
@
|
91
|
+
@_regexps.each do |key, regexp|
|
65
92
|
throw :break_loop unless ::Fluent::StringUtil.match_regexp(regexp, record[key].to_s)
|
66
93
|
end
|
67
|
-
@
|
94
|
+
@_excludes.each do |key, exclude|
|
68
95
|
throw :break_loop if ::Fluent::StringUtil.match_regexp(exclude, record[key].to_s)
|
69
96
|
end
|
70
97
|
result = record
|
@@ -93,6 +93,10 @@ module Fluent
|
|
93
93
|
config_param :source_host_key, :string, default: 'source_host'.freeze, deprecated: "use source_hostname_key instead"
|
94
94
|
desc "The field name of the client's hostname."
|
95
95
|
config_param :source_hostname_key, :string, default: nil
|
96
|
+
desc "The field name of the client's source address."
|
97
|
+
config_param :source_address_key, :string, default: nil
|
98
|
+
desc 'Try to resolve hostname from IP addresses or not.'
|
99
|
+
config_param :resolve_hostname, :bool, default: nil
|
96
100
|
desc 'The field name of the priority.'
|
97
101
|
config_param :priority_key, :string, default: nil
|
98
102
|
desc 'The field name of the facility.'
|
@@ -101,14 +105,28 @@ module Fluent
|
|
101
105
|
config_param :message_length_limit, :size, default: 2048
|
102
106
|
config_param :blocking_timeout, :time, default: 0.5
|
103
107
|
|
108
|
+
desc 'If true, accept syslog message without PRI part'
|
109
|
+
config_param :allow_without_priority, :bool, default: false
|
110
|
+
# 13 is the default value of rsyslog and syslog-ng
|
111
|
+
desc 'The default PRI value (0 - 191 are available)'
|
112
|
+
config_param :default_priority, :integer, default: 13
|
113
|
+
|
104
114
|
def configure(conf)
|
105
115
|
super
|
106
116
|
|
117
|
+
if @default_priority < 0 && @default_priority > 191
|
118
|
+
raise ConfigError, "default_priority must be 0 ~ 191"
|
119
|
+
end
|
120
|
+
|
121
|
+
if @allow_without_priority && conf['message_format'] == 'auto'
|
122
|
+
raise ConfigError, "message_format auto isn't allowed when allow_without_priority is true"
|
123
|
+
end
|
124
|
+
|
125
|
+
conf['with_priority'] = !@allow_without_priority
|
107
126
|
if conf.has_key?('format')
|
108
127
|
@parser = Plugin.new_parser(conf['format'])
|
109
128
|
@parser.configure(conf)
|
110
129
|
else
|
111
|
-
conf['with_priority'] = true
|
112
130
|
@parser = TextParser::SyslogParser.new
|
113
131
|
@parser.configure(conf)
|
114
132
|
@use_default = true
|
@@ -117,15 +135,25 @@ module Fluent
|
|
117
135
|
if @source_hostname_key.nil? && @include_source_host
|
118
136
|
@source_hostname_key = @source_host_key
|
119
137
|
end
|
138
|
+
if @source_hostname_key
|
139
|
+
if @resolve_hostname.nil?
|
140
|
+
@resolve_hostname = true
|
141
|
+
elsif !@resolve_hostname # user specifies "false" in configure
|
142
|
+
raise Fluent::ConfigError, "resolve_hostname must be true with source_hostname_key"
|
143
|
+
end
|
144
|
+
end
|
120
145
|
end
|
121
146
|
|
122
147
|
def start
|
123
|
-
callback = if @
|
124
|
-
method(:
|
148
|
+
callback = if @allow_without_priority
|
149
|
+
method(:receive_data_allow_without_priority)
|
125
150
|
else
|
126
|
-
|
151
|
+
if @use_default
|
152
|
+
method(:receive_data_default)
|
153
|
+
else
|
154
|
+
method(:receive_data_with_format)
|
155
|
+
end
|
127
156
|
end
|
128
|
-
|
129
157
|
@loop = Coolio::Loop.new
|
130
158
|
@handler = listen(callback)
|
131
159
|
@loop.attach(@handler)
|
@@ -149,7 +177,16 @@ module Fluent
|
|
149
177
|
|
150
178
|
private
|
151
179
|
|
152
|
-
|
180
|
+
## SyslogParser with PRI part
|
181
|
+
def receive_data_default(data, addr)
|
182
|
+
parse_text(data, addr)
|
183
|
+
rescue => e
|
184
|
+
log.error data.dump, error: e.to_s
|
185
|
+
log.error_backtrace
|
186
|
+
end
|
187
|
+
|
188
|
+
## PRI part parser + custom parser without PRI part
|
189
|
+
def receive_data_with_format(data, addr)
|
153
190
|
m = SYSLOG_REGEXP.match(data)
|
154
191
|
unless m
|
155
192
|
log.warn "invalid syslog message: #{data.dump}"
|
@@ -158,48 +195,50 @@ module Fluent
|
|
158
195
|
pri = m[1].to_i
|
159
196
|
text = m[2]
|
160
197
|
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
facility = FACILITY_MAP[pri >> 3]
|
168
|
-
priority = PRIORITY_MAP[pri & 0b111]
|
198
|
+
parse_text(text, addr, pri)
|
199
|
+
rescue => e
|
200
|
+
log.error data.dump, error: e.to_s
|
201
|
+
log.error_backtrace
|
202
|
+
end
|
169
203
|
|
170
|
-
|
171
|
-
|
172
|
-
|
204
|
+
## PRI part parser + SyslogParser without PRI part | custom parser without PRI part
|
205
|
+
def receive_data_allow_without_priority(data, addr)
|
206
|
+
m = SYSLOG_REGEXP.match(data)
|
207
|
+
if m
|
208
|
+
pri = m[1].to_i
|
209
|
+
text = m[2]
|
210
|
+
else
|
211
|
+
pri = @default_priority
|
212
|
+
text = data
|
213
|
+
end
|
173
214
|
|
174
|
-
|
175
|
-
emit(tag, time, record)
|
176
|
-
}
|
215
|
+
parse_text(text, addr, pri)
|
177
216
|
rescue => e
|
178
217
|
log.error data.dump, error: e.to_s
|
179
218
|
log.error_backtrace
|
180
219
|
end
|
181
220
|
|
182
|
-
def
|
183
|
-
@parser.parse(
|
221
|
+
def parse_text(text, addr, pri = nil)
|
222
|
+
@parser.parse(text) { |time, record|
|
184
223
|
unless time && record
|
185
|
-
log.warn "
|
224
|
+
log.warn "pattern not match: #{text.inspect}"
|
186
225
|
return
|
187
226
|
end
|
188
227
|
|
189
|
-
|
228
|
+
## from receive_data_default
|
229
|
+
pri = record.delete('pri'.freeze) unless pri
|
230
|
+
|
190
231
|
facility = FACILITY_MAP[pri >> 3]
|
191
232
|
priority = PRIORITY_MAP[pri & 0b111]
|
192
233
|
|
193
234
|
record[@priority_key] = priority if @priority_key
|
194
235
|
record[@facility_key] = facility if @facility_key
|
195
236
|
record[@source_hostname_key] = addr[2] if @source_hostname_key
|
237
|
+
record[@source_address_key] = addr[3] if @source_address_key
|
196
238
|
|
197
239
|
tag = "#{@tag}.#{facility}.#{priority}"
|
198
240
|
emit(tag, time, record)
|
199
241
|
}
|
200
|
-
rescue => e
|
201
|
-
log.error data.dump, error: e.to_s
|
202
|
-
log.error_backtrace
|
203
242
|
end
|
204
243
|
|
205
244
|
private
|
@@ -209,10 +248,10 @@ module Fluent
|
|
209
248
|
if @protocol_type == :udp
|
210
249
|
@usock = SocketUtil.create_udp_socket(@bind)
|
211
250
|
@usock.bind(@bind, @port)
|
212
|
-
SocketUtil::UdpHandler.new(@usock, log, @message_length_limit, callback,
|
251
|
+
SocketUtil::UdpHandler.new(@usock, log, @message_length_limit, callback, @resolve_hostname)
|
213
252
|
else
|
214
253
|
# syslog family add "\n" to each message and this seems only way to split messages in tcp stream
|
215
|
-
Coolio::TCPServer.new(@bind, @port, SocketUtil::TcpHandler, log, "\n", callback,
|
254
|
+
Coolio::TCPServer.new(@bind, @port, SocketUtil::TcpHandler, log, "\n", callback, @resolve_hostname)
|
216
255
|
end
|
217
256
|
end
|
218
257
|
|
data/lib/fluent/version.rb
CHANGED
@@ -22,12 +22,51 @@ class GrepFilterTest < Test::Unit::TestCase
|
|
22
22
|
|
23
23
|
test "regexpN can contain a space" do
|
24
24
|
d = create_driver(%[regexp1 message foo])
|
25
|
-
assert_equal(Regexp.compile(/ foo/), d.instance.
|
25
|
+
assert_equal(Regexp.compile(/ foo/), d.instance._regexps['message'])
|
26
26
|
end
|
27
27
|
|
28
28
|
test "excludeN can contain a space" do
|
29
29
|
d = create_driver(%[exclude1 message foo])
|
30
|
-
assert_equal(Regexp.compile(/ foo/), d.instance.
|
30
|
+
assert_equal(Regexp.compile(/ foo/), d.instance._excludes['message'])
|
31
|
+
end
|
32
|
+
|
33
|
+
sub_test_case "duplicate key" do
|
34
|
+
test "flat" do
|
35
|
+
conf = %[
|
36
|
+
regexp1 message test
|
37
|
+
regexp2 message test2
|
38
|
+
]
|
39
|
+
assert_raise(Fluent::ConfigError) do
|
40
|
+
create_driver(conf)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
test "section" do
|
44
|
+
conf = %[
|
45
|
+
<regexp>
|
46
|
+
key message
|
47
|
+
pattern test
|
48
|
+
</regexp>
|
49
|
+
<regexp>
|
50
|
+
key message
|
51
|
+
pattern test2
|
52
|
+
</regexp>
|
53
|
+
]
|
54
|
+
assert_raise(Fluent::ConfigError) do
|
55
|
+
create_driver(conf)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
test "mix" do
|
59
|
+
conf = %[
|
60
|
+
regexp1 message test
|
61
|
+
<regexp>
|
62
|
+
key message
|
63
|
+
pattern test
|
64
|
+
</regexp>
|
65
|
+
]
|
66
|
+
assert_raise(Fluent::ConfigError) do
|
67
|
+
create_driver(conf)
|
68
|
+
end
|
69
|
+
end
|
31
70
|
end
|
32
71
|
end
|
33
72
|
|
@@ -75,6 +114,38 @@ class GrepFilterTest < Test::Unit::TestCase
|
|
75
114
|
end
|
76
115
|
end
|
77
116
|
|
117
|
+
test 'regexps' do
|
118
|
+
conf = %[
|
119
|
+
<regexp>
|
120
|
+
key message
|
121
|
+
pattern WARN
|
122
|
+
</regexp>
|
123
|
+
]
|
124
|
+
es = emit(conf, messages)
|
125
|
+
assert_equal(3, es.instance_variable_get(:@record_array).size)
|
126
|
+
assert_block('only WARN logs') do
|
127
|
+
es.all? { |t, r|
|
128
|
+
!r['message'].include?('INFO')
|
129
|
+
}
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
test 'excludes' do
|
134
|
+
conf = %[
|
135
|
+
<exclude>
|
136
|
+
key message
|
137
|
+
pattern favicon
|
138
|
+
</exclude>
|
139
|
+
]
|
140
|
+
es = emit(conf, messages)
|
141
|
+
assert_equal(3, es.instance_variable_get(:@record_array).size)
|
142
|
+
assert_block('remove favicon logs') do
|
143
|
+
es.all? { |t, r|
|
144
|
+
!r['message'].include?('favicon')
|
145
|
+
}
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
78
149
|
sub_test_case 'with invalid sequence' do
|
79
150
|
def messages
|
80
151
|
[
|
@@ -35,6 +35,74 @@ class SyslogInputTest < Test::Unit::TestCase
|
|
35
35
|
}
|
36
36
|
end
|
37
37
|
|
38
|
+
sub_test_case 'source_hostname_key and source_address_key features' do
|
39
|
+
test 'resolve_hostname must be true with source_hostname_key' do
|
40
|
+
assert_raise(Fluent::ConfigError) {
|
41
|
+
create_driver(CONFIG + <<EOS)
|
42
|
+
resolve_hostname false
|
43
|
+
source_hostname_key hostname
|
44
|
+
EOS
|
45
|
+
}
|
46
|
+
end
|
47
|
+
|
48
|
+
LOCALHOST_HOSTNAME_GETTER = ->(){sock = UDPSocket.new(::Socket::AF_INET); sock.do_not_reverse_lookup = false; sock.connect("127.0.0.1", 2048); sock.peeraddr[2] }
|
49
|
+
LOCALHOST_HOSTNAME = LOCALHOST_HOSTNAME_GETTER.call
|
50
|
+
DUMMY_SOCK = Struct.new(:remote_host, :remote_addr, :remote_port).new(LOCALHOST_HOSTNAME, "127.0.0.1", 0)
|
51
|
+
data(
|
52
|
+
both: [:hostname, :address],
|
53
|
+
hostname: [:hostname],
|
54
|
+
address: [:address],
|
55
|
+
)
|
56
|
+
test 'source_hostname_key and source_address_key parameter feature should add record(s)' do |keys|
|
57
|
+
conf = CONFIG.dup
|
58
|
+
if keys.include?(:hostname)
|
59
|
+
conf << <<EOL
|
60
|
+
source_hostname_key source_hostname
|
61
|
+
EOL
|
62
|
+
end
|
63
|
+
if keys.include?(:address)
|
64
|
+
conf << <<EOL
|
65
|
+
source_address_key source_address
|
66
|
+
EOL
|
67
|
+
end
|
68
|
+
tests = create_test_case
|
69
|
+
d = create_driver(conf)
|
70
|
+
|
71
|
+
d.run do
|
72
|
+
u = UDPSocket.new
|
73
|
+
u.connect('127.0.0.1', PORT)
|
74
|
+
tests.each {|test|
|
75
|
+
u.send(test['msg'], 0)
|
76
|
+
}
|
77
|
+
sleep 1
|
78
|
+
end
|
79
|
+
|
80
|
+
d.emits.each { |tag, _time, record|
|
81
|
+
if keys.include?(:hostname)
|
82
|
+
assert_true record.has_key?('source_hostname')
|
83
|
+
assert_equal DUMMY_SOCK.remote_host, record['source_hostname']
|
84
|
+
unless keys.include?(:address)
|
85
|
+
assert_false record.has_key?('source_address')
|
86
|
+
end
|
87
|
+
end
|
88
|
+
if keys.include?(:address)
|
89
|
+
assert_true record.has_key?('source_address')
|
90
|
+
assert_equal DUMMY_SOCK.remote_addr, record['source_address']
|
91
|
+
unless keys.include?(:hostname)
|
92
|
+
assert_false record.has_key?('source_hostname')
|
93
|
+
end
|
94
|
+
end
|
95
|
+
}
|
96
|
+
end
|
97
|
+
|
98
|
+
data('resolve_hostname' => 'resolve_hostname true',
|
99
|
+
'source_hostname_key' => 'source_hostname_key source_host')
|
100
|
+
def test_configure_reslove_hostname(param)
|
101
|
+
d = create_driver([CONFIG, param].join("\n"))
|
102
|
+
assert_true d.instance.resolve_hostname
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
38
106
|
def test_time_format
|
39
107
|
configs = {'127.0.0.1' => CONFIG}
|
40
108
|
configs.merge!('::1' => IPv6_CONFIG) if ipv6_enabled?
|
@@ -213,6 +281,77 @@ class SyslogInputTest < Test::Unit::TestCase
|
|
213
281
|
compare_test_result(d.emits, tests, {facility: facility})
|
214
282
|
end
|
215
283
|
|
284
|
+
def test_allow_without_priority_with_default_format
|
285
|
+
d = create_driver([CONFIG, 'allow_without_priority true'].join("\n"))
|
286
|
+
|
287
|
+
tests = [
|
288
|
+
{'msg' => '<6>Sep 10 00:00:00 localhost logger: ' + 'x' * 100 + "\n", 'expected' => 'x' * 100},
|
289
|
+
{'msg' => 'Sep 10 00:00:00 localhost logger: ' + 'x' * 1024 + "\n", 'expected' => 'x' * 1024, 'tag' => 'syslog.user.notice'},
|
290
|
+
]
|
291
|
+
|
292
|
+
d.run do
|
293
|
+
u = UDPSocket.new
|
294
|
+
u.connect('127.0.0.1', PORT)
|
295
|
+
tests.each {|test|
|
296
|
+
u.send(test['msg'], 0)
|
297
|
+
}
|
298
|
+
sleep 1
|
299
|
+
end
|
300
|
+
|
301
|
+
assert_equal 2, d.emits.size
|
302
|
+
compare_test_result(d.emits, tests)
|
303
|
+
end
|
304
|
+
|
305
|
+
def test_allow_without_priority_with_json_format
|
306
|
+
d = create_driver([CONFIG, %[
|
307
|
+
allow_without_priority true
|
308
|
+
format json
|
309
|
+
]].join("\n"))
|
310
|
+
|
311
|
+
message = 'foo'
|
312
|
+
tests = [
|
313
|
+
{'msg' => '<6>' + {'message' => message}.to_json + "\n", 'expected' => message},
|
314
|
+
{'msg' => {'message' => message}.to_json + "\n", 'expected' => message, 'tag' => 'syslog.user.notice'},
|
315
|
+
]
|
316
|
+
|
317
|
+
d.run do
|
318
|
+
u = UDPSocket.new
|
319
|
+
u.connect('127.0.0.1', PORT)
|
320
|
+
tests.each {|test|
|
321
|
+
u.send(test['msg'], 0)
|
322
|
+
}
|
323
|
+
sleep 1
|
324
|
+
end
|
325
|
+
|
326
|
+
assert_equal 2, d.emits.size
|
327
|
+
compare_test_result(d.emits, tests)
|
328
|
+
end
|
329
|
+
|
330
|
+
def test_default_priority
|
331
|
+
d = create_driver([CONFIG, %[
|
332
|
+
allow_without_priority true
|
333
|
+
default_priority 100
|
334
|
+
]].join("\n"))
|
335
|
+
|
336
|
+
tests = [
|
337
|
+
{'msg' => '<6>Sep 10 00:00:00 localhost logger: ' + 'x' * 100 + "\n", 'expected' => 'x' * 100},
|
338
|
+
{'msg' => 'Sep 10 00:00:00 localhost logger: ' + 'x' * 1024 + "\n", 'expected' => 'x' * 1024, 'tag' => 'syslog.ntp.warn'},
|
339
|
+
]
|
340
|
+
|
341
|
+
d.run do
|
342
|
+
u = UDPSocket.new
|
343
|
+
u.connect('127.0.0.1', PORT)
|
344
|
+
tests.each {|test|
|
345
|
+
u.send(test['msg'], 0)
|
346
|
+
}
|
347
|
+
sleep 1
|
348
|
+
end
|
349
|
+
|
350
|
+
assert_equal 2, d.emits.size
|
351
|
+
compare_test_result(d.emits, tests)
|
352
|
+
|
353
|
+
end
|
354
|
+
|
216
355
|
def create_test_case(large_message = false)
|
217
356
|
# actual syslog message has "\n"
|
218
357
|
if large_message
|
@@ -231,7 +370,7 @@ class SyslogInputTest < Test::Unit::TestCase
|
|
231
370
|
|
232
371
|
def compare_test_result(events, tests, options = {})
|
233
372
|
events.each_index { |i|
|
234
|
-
assert_equal('syslog.kern.info', events[i][0]) # <6> means kern.info
|
373
|
+
assert_equal((tests[i]['tag'] || 'syslog.kern.info'), events[i][0]) # <6> means kern.info
|
235
374
|
assert_equal(tests[i]['expected'], events[i][2]['message'])
|
236
375
|
assert_equal(options[:host], events[i][2]['source_host']) if options[:host]
|
237
376
|
assert_equal(options[:priority], events[i][2]['priority']) if options[:priority]
|
data/test/test_parser.rb
CHANGED
@@ -374,6 +374,24 @@ module ParserTest
|
|
374
374
|
end
|
375
375
|
end
|
376
376
|
|
377
|
+
def test_parse_various_characters_for_tag
|
378
|
+
ident = '~!@#$%^&*()_+=-`]{};"\'/?\\,.<>'
|
379
|
+
@parser.configure({})
|
380
|
+
@parser.parse("Feb 28 12:00:00 192.168.0.1 #{ident}[11111]: [error] Syslog test") { |time, record|
|
381
|
+
assert_equal_event_time(event_time('Feb 28 12:00:00', format: '%b %d %H:%M:%S'), time)
|
382
|
+
assert_equal(@expected.merge('ident' => ident), record)
|
383
|
+
}
|
384
|
+
end
|
385
|
+
|
386
|
+
def test_parse_various_characters_for_tag_with_priority
|
387
|
+
ident = '~!@#$%^&*()_+=-`]{};"\'/?\\,.<>'
|
388
|
+
@parser.configure({'with_priority' => true})
|
389
|
+
@parser.parse("<6>Feb 28 12:00:00 192.168.0.1 #{ident}[11111]: [error] Syslog test") { |time, record|
|
390
|
+
assert_equal_event_time(event_time('Feb 28 12:00:00', format: '%b %d %H:%M:%S'), time)
|
391
|
+
assert_equal(@expected.merge('pri' => 6, 'ident' => ident), record)
|
392
|
+
}
|
393
|
+
end
|
394
|
+
|
377
395
|
class TestRFC5424Regexp < self
|
378
396
|
def test_parse_with_rfc5424_message
|
379
397
|
@parser.configure(
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fluentd
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.12.
|
4
|
+
version: 0.12.38
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sadayuki Furuhashi
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-07-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: msgpack
|