fluentd 0.12.40 → 0.14.0

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.

Files changed (252) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE.md +6 -0
  3. data/.gitignore +2 -0
  4. data/.travis.yml +33 -21
  5. data/CONTRIBUTING.md +1 -0
  6. data/ChangeLog +810 -237
  7. data/README.md +0 -25
  8. data/Rakefile +2 -1
  9. data/Vagrantfile +17 -0
  10. data/appveyor.yml +35 -0
  11. data/example/filter_stdout.conf +5 -5
  12. data/example/in_forward.conf +2 -2
  13. data/example/in_http.conf +2 -2
  14. data/example/in_out_forward.conf +17 -0
  15. data/example/in_syslog.conf +2 -2
  16. data/example/in_tail.conf +2 -2
  17. data/example/in_tcp.conf +2 -2
  18. data/example/in_udp.conf +2 -2
  19. data/example/out_copy.conf +4 -4
  20. data/example/out_file.conf +2 -2
  21. data/example/out_forward.conf +2 -2
  22. data/example/out_forward_buf_file.conf +23 -0
  23. data/example/v0_12_filter.conf +8 -8
  24. data/fluent.conf +29 -0
  25. data/fluentd.gemspec +18 -11
  26. data/lib/fluent/agent.rb +60 -58
  27. data/lib/fluent/command/cat.rb +1 -1
  28. data/lib/fluent/command/debug.rb +7 -5
  29. data/lib/fluent/command/fluentd.rb +97 -2
  30. data/lib/fluent/compat/call_super_mixin.rb +67 -0
  31. data/lib/fluent/compat/filter.rb +50 -0
  32. data/lib/fluent/compat/formatter.rb +109 -0
  33. data/lib/fluent/compat/input.rb +50 -0
  34. data/lib/fluent/compat/output.rb +617 -0
  35. data/lib/fluent/compat/output_chain.rb +60 -0
  36. data/lib/fluent/compat/parser.rb +163 -0
  37. data/lib/fluent/compat/propagate_default.rb +62 -0
  38. data/lib/fluent/config.rb +23 -20
  39. data/lib/fluent/config/configure_proxy.rb +119 -70
  40. data/lib/fluent/config/dsl.rb +5 -18
  41. data/lib/fluent/config/element.rb +72 -8
  42. data/lib/fluent/config/error.rb +0 -3
  43. data/lib/fluent/config/literal_parser.rb +0 -2
  44. data/lib/fluent/config/parser.rb +4 -4
  45. data/lib/fluent/config/section.rb +39 -28
  46. data/lib/fluent/config/types.rb +2 -13
  47. data/lib/fluent/config/v1_parser.rb +1 -3
  48. data/lib/fluent/configurable.rb +48 -16
  49. data/lib/fluent/daemon.rb +15 -0
  50. data/lib/fluent/engine.rb +26 -52
  51. data/lib/fluent/env.rb +6 -4
  52. data/lib/fluent/event.rb +58 -11
  53. data/lib/fluent/event_router.rb +5 -5
  54. data/lib/fluent/filter.rb +2 -50
  55. data/lib/fluent/formatter.rb +4 -293
  56. data/lib/fluent/input.rb +2 -32
  57. data/lib/fluent/label.rb +2 -2
  58. data/lib/fluent/load.rb +3 -2
  59. data/lib/fluent/log.rb +107 -38
  60. data/lib/fluent/match.rb +0 -36
  61. data/lib/fluent/mixin.rb +117 -7
  62. data/lib/fluent/msgpack_factory.rb +62 -0
  63. data/lib/fluent/output.rb +7 -612
  64. data/lib/fluent/output_chain.rb +23 -0
  65. data/lib/fluent/parser.rb +4 -800
  66. data/lib/fluent/plugin.rb +100 -121
  67. data/lib/fluent/plugin/bare_output.rb +63 -0
  68. data/lib/fluent/plugin/base.rb +121 -0
  69. data/lib/fluent/plugin/buf_file.rb +101 -182
  70. data/lib/fluent/plugin/buf_memory.rb +9 -92
  71. data/lib/fluent/plugin/buffer.rb +473 -0
  72. data/lib/fluent/plugin/buffer/chunk.rb +135 -0
  73. data/lib/fluent/plugin/buffer/file_chunk.rb +339 -0
  74. data/lib/fluent/plugin/buffer/memory_chunk.rb +100 -0
  75. data/lib/fluent/plugin/exec_util.rb +80 -75
  76. data/lib/fluent/plugin/file_util.rb +33 -28
  77. data/lib/fluent/plugin/file_wrapper.rb +120 -0
  78. data/lib/fluent/plugin/filter.rb +51 -0
  79. data/lib/fluent/plugin/filter_grep.rb +13 -40
  80. data/lib/fluent/plugin/filter_record_transformer.rb +22 -18
  81. data/lib/fluent/plugin/formatter.rb +93 -0
  82. data/lib/fluent/plugin/formatter_csv.rb +48 -0
  83. data/lib/fluent/plugin/formatter_hash.rb +32 -0
  84. data/lib/fluent/plugin/formatter_json.rb +47 -0
  85. data/lib/fluent/plugin/formatter_ltsv.rb +42 -0
  86. data/lib/fluent/plugin/formatter_msgpack.rb +32 -0
  87. data/lib/fluent/plugin/formatter_out_file.rb +45 -0
  88. data/lib/fluent/plugin/formatter_single_value.rb +34 -0
  89. data/lib/fluent/plugin/formatter_stdout.rb +39 -0
  90. data/lib/fluent/plugin/in_debug_agent.rb +4 -0
  91. data/lib/fluent/plugin/in_dummy.rb +22 -18
  92. data/lib/fluent/plugin/in_exec.rb +18 -8
  93. data/lib/fluent/plugin/in_forward.rb +36 -79
  94. data/lib/fluent/plugin/in_gc_stat.rb +4 -0
  95. data/lib/fluent/plugin/in_http.rb +21 -18
  96. data/lib/fluent/plugin/in_monitor_agent.rb +15 -48
  97. data/lib/fluent/plugin/in_object_space.rb +6 -1
  98. data/lib/fluent/plugin/in_stream.rb +7 -3
  99. data/lib/fluent/plugin/in_syslog.rb +46 -95
  100. data/lib/fluent/plugin/in_tail.rb +51 -595
  101. data/lib/fluent/plugin/in_tcp.rb +8 -1
  102. data/lib/fluent/plugin/in_udp.rb +8 -14
  103. data/lib/fluent/plugin/input.rb +33 -0
  104. data/lib/fluent/plugin/multi_output.rb +95 -0
  105. data/lib/fluent/plugin/out_buffered_null.rb +59 -0
  106. data/lib/fluent/plugin/out_copy.rb +11 -7
  107. data/lib/fluent/plugin/out_exec.rb +15 -11
  108. data/lib/fluent/plugin/out_exec_filter.rb +18 -10
  109. data/lib/fluent/plugin/out_file.rb +34 -5
  110. data/lib/fluent/plugin/out_forward.rb +19 -9
  111. data/lib/fluent/plugin/out_null.rb +0 -14
  112. data/lib/fluent/plugin/out_roundrobin.rb +11 -7
  113. data/lib/fluent/plugin/out_stdout.rb +5 -7
  114. data/lib/fluent/plugin/out_stream.rb +3 -1
  115. data/lib/fluent/plugin/output.rb +979 -0
  116. data/lib/fluent/plugin/owned_by_mixin.rb +42 -0
  117. data/lib/fluent/plugin/parser.rb +244 -0
  118. data/lib/fluent/plugin/parser_apache.rb +24 -0
  119. data/lib/fluent/plugin/parser_apache2.rb +84 -0
  120. data/lib/fluent/plugin/parser_apache_error.rb +21 -0
  121. data/lib/fluent/plugin/parser_csv.rb +31 -0
  122. data/lib/fluent/plugin/parser_json.rb +79 -0
  123. data/lib/fluent/plugin/parser_ltsv.rb +50 -0
  124. data/lib/fluent/plugin/parser_multiline.rb +102 -0
  125. data/lib/fluent/plugin/parser_nginx.rb +24 -0
  126. data/lib/fluent/plugin/parser_none.rb +36 -0
  127. data/lib/fluent/plugin/parser_syslog.rb +82 -0
  128. data/lib/fluent/plugin/parser_tsv.rb +37 -0
  129. data/lib/fluent/plugin/socket_util.rb +120 -114
  130. data/lib/fluent/plugin/storage.rb +84 -0
  131. data/lib/fluent/plugin/storage_local.rb +116 -0
  132. data/lib/fluent/plugin/string_util.rb +16 -13
  133. data/lib/fluent/plugin_helper.rb +39 -0
  134. data/lib/fluent/plugin_helper/child_process.rb +298 -0
  135. data/lib/fluent/plugin_helper/compat_parameters.rb +99 -0
  136. data/lib/fluent/plugin_helper/event_emitter.rb +80 -0
  137. data/lib/fluent/plugin_helper/event_loop.rb +118 -0
  138. data/lib/fluent/plugin_helper/retry_state.rb +177 -0
  139. data/lib/fluent/plugin_helper/storage.rb +308 -0
  140. data/lib/fluent/plugin_helper/thread.rb +147 -0
  141. data/lib/fluent/plugin_helper/timer.rb +85 -0
  142. data/lib/fluent/plugin_id.rb +63 -0
  143. data/lib/fluent/process.rb +21 -30
  144. data/lib/fluent/registry.rb +21 -9
  145. data/lib/fluent/root_agent.rb +115 -40
  146. data/lib/fluent/supervisor.rb +330 -320
  147. data/lib/fluent/system_config.rb +42 -18
  148. data/lib/fluent/test.rb +6 -1
  149. data/lib/fluent/test/base.rb +23 -3
  150. data/lib/fluent/test/driver/base.rb +247 -0
  151. data/lib/fluent/test/driver/event_feeder.rb +98 -0
  152. data/lib/fluent/test/driver/filter.rb +35 -0
  153. data/lib/fluent/test/driver/input.rb +31 -0
  154. data/lib/fluent/test/driver/output.rb +78 -0
  155. data/lib/fluent/test/driver/test_event_router.rb +45 -0
  156. data/lib/fluent/test/filter_test.rb +0 -1
  157. data/lib/fluent/test/formatter_test.rb +2 -1
  158. data/lib/fluent/test/input_test.rb +23 -17
  159. data/lib/fluent/test/output_test.rb +28 -39
  160. data/lib/fluent/test/parser_test.rb +1 -1
  161. data/lib/fluent/time.rb +104 -1
  162. data/lib/fluent/{status.rb → unique_id.rb} +15 -24
  163. data/lib/fluent/version.rb +1 -1
  164. data/lib/fluent/winsvc.rb +72 -0
  165. data/test/compat/test_calls_super.rb +164 -0
  166. data/test/config/test_config_parser.rb +83 -0
  167. data/test/config/test_configurable.rb +547 -274
  168. data/test/config/test_configure_proxy.rb +146 -29
  169. data/test/config/test_dsl.rb +3 -181
  170. data/test/config/test_element.rb +274 -0
  171. data/test/config/test_literal_parser.rb +1 -1
  172. data/test/config/test_section.rb +79 -7
  173. data/test/config/test_system_config.rb +21 -0
  174. data/test/config/test_types.rb +3 -26
  175. data/test/helper.rb +78 -8
  176. data/test/plugin/test_bare_output.rb +118 -0
  177. data/test/plugin/test_base.rb +75 -0
  178. data/test/plugin/test_buf_file.rb +420 -521
  179. data/test/plugin/test_buf_memory.rb +32 -194
  180. data/test/plugin/test_buffer.rb +981 -0
  181. data/test/plugin/test_buffer_chunk.rb +110 -0
  182. data/test/plugin/test_buffer_file_chunk.rb +770 -0
  183. data/test/plugin/test_buffer_memory_chunk.rb +265 -0
  184. data/test/plugin/test_filter.rb +255 -0
  185. data/test/plugin/test_filter_grep.rb +2 -73
  186. data/test/plugin/test_filter_record_transformer.rb +24 -68
  187. data/test/plugin/test_filter_stdout.rb +6 -6
  188. data/test/plugin/test_in_debug_agent.rb +2 -0
  189. data/test/plugin/test_in_dummy.rb +11 -17
  190. data/test/plugin/test_in_exec.rb +6 -25
  191. data/test/plugin/test_in_forward.rb +112 -151
  192. data/test/plugin/test_in_gc_stat.rb +2 -0
  193. data/test/plugin/test_in_http.rb +106 -157
  194. data/test/plugin/test_in_object_space.rb +21 -5
  195. data/test/plugin/test_in_stream.rb +14 -13
  196. data/test/plugin/test_in_syslog.rb +30 -275
  197. data/test/plugin/test_in_tail.rb +95 -234
  198. data/test/plugin/test_in_tcp.rb +14 -0
  199. data/test/plugin/test_in_udp.rb +21 -13
  200. data/test/plugin/test_input.rb +122 -0
  201. data/test/plugin/test_multi_output.rb +180 -0
  202. data/test/plugin/test_out_buffered_null.rb +79 -0
  203. data/test/plugin/test_out_copy.rb +15 -2
  204. data/test/plugin/test_out_exec.rb +75 -25
  205. data/test/plugin/test_out_exec_filter.rb +74 -8
  206. data/test/plugin/test_out_file.rb +61 -7
  207. data/test/plugin/test_out_forward.rb +92 -15
  208. data/test/plugin/test_out_roundrobin.rb +1 -0
  209. data/test/plugin/test_out_stdout.rb +22 -13
  210. data/test/plugin/test_out_stream.rb +18 -0
  211. data/test/plugin/test_output.rb +515 -0
  212. data/test/plugin/test_output_as_buffered.rb +1540 -0
  213. data/test/plugin/test_output_as_buffered_overflow.rb +247 -0
  214. data/test/plugin/test_output_as_buffered_retries.rb +808 -0
  215. data/test/plugin/test_output_as_buffered_secondary.rb +776 -0
  216. data/test/plugin/test_output_as_standard.rb +362 -0
  217. data/test/plugin/test_owned_by.rb +35 -0
  218. data/test/plugin/test_storage.rb +167 -0
  219. data/test/plugin/test_storage_local.rb +8 -0
  220. data/test/plugin_helper/test_child_process.rb +599 -0
  221. data/test/plugin_helper/test_compat_parameters.rb +175 -0
  222. data/test/plugin_helper/test_event_emitter.rb +51 -0
  223. data/test/plugin_helper/test_event_loop.rb +52 -0
  224. data/test/plugin_helper/test_retry_state.rb +399 -0
  225. data/test/plugin_helper/test_storage.rb +411 -0
  226. data/test/plugin_helper/test_thread.rb +164 -0
  227. data/test/plugin_helper/test_timer.rb +100 -0
  228. data/test/scripts/exec_script.rb +0 -6
  229. data/test/scripts/fluent/plugin/out_test.rb +3 -0
  230. data/test/test_config.rb +13 -4
  231. data/test/test_event.rb +24 -13
  232. data/test/test_event_router.rb +8 -7
  233. data/test/test_event_time.rb +187 -0
  234. data/test/test_formatter.rb +13 -51
  235. data/test/test_input.rb +1 -1
  236. data/test/test_log.rb +239 -16
  237. data/test/test_mixin.rb +1 -1
  238. data/test/test_output.rb +53 -66
  239. data/test/test_parser.rb +105 -323
  240. data/test/test_plugin_helper.rb +81 -0
  241. data/test/test_root_agent.rb +4 -52
  242. data/test/test_supervisor.rb +272 -0
  243. data/test/test_unique_id.rb +47 -0
  244. metadata +180 -54
  245. data/lib/fluent/buffer.rb +0 -365
  246. data/lib/fluent/plugin/filter_parser.rb +0 -107
  247. data/lib/fluent/plugin/in_status.rb +0 -76
  248. data/lib/fluent/test/helpers.rb +0 -86
  249. data/test/plugin/data/log/foo/bar2 +0 -0
  250. data/test/plugin/test_filter_parser.rb +0 -744
  251. data/test/plugin/test_in_status.rb +0 -38
  252. data/test/test_buffer.rb +0 -624
@@ -0,0 +1,23 @@
1
+ #
2
+ # Fluentd
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+
17
+ require 'fluent/compat/output_chain'
18
+
19
+ module Fluent
20
+ OutputChain = Fluent::Compat::OutputChain
21
+ CopyOutputChain = Fluent::Compat::CopyOutputChain
22
+ NullOutputChain = Fluent::Compat::NullOutputChain
23
+ end
@@ -14,806 +14,10 @@
14
14
  # limitations under the License.
15
15
  #
16
16
 
17
- require 'time'
18
- require 'json'
19
-
20
- require 'yajl'
21
-
22
- require 'fluent/config/error'
23
- require 'fluent/config/element'
24
- require 'fluent/configurable'
25
- require 'fluent/env'
26
- require 'fluent/engine'
27
- require 'fluent/registry'
28
- require 'fluent/time'
17
+ require 'fluent/compat/parser'
29
18
 
30
19
  module Fluent
31
- class ParserError < StandardError
32
- end
33
-
34
- class Parser
35
- include Configurable
36
-
37
- # SET false BEFORE CONFIGURE, to return nil when time not parsed
38
- # 'configure()' may raise errors for unexpected configurations
39
- attr_accessor :estimate_current_event
40
-
41
- config_param :keep_time_key, :bool, default: false
42
-
43
- def initialize
44
- super
45
- @estimate_current_event = true
46
- end
47
-
48
- def configure(conf)
49
- super
50
- end
51
-
52
- def parse(text)
53
- raise NotImplementedError, "Implement this method in child class"
54
- end
55
-
56
- # Keep backward compatibility for existing plugins
57
- def call(*a, &b)
58
- parse(*a, &b)
59
- end
60
- end
61
-
62
- class TextParser
63
- # Keep backward compatibility for existing plugins
64
- ParserError = ::Fluent::ParserError
65
-
66
- class TimeParser
67
- def initialize(time_format)
68
- @cache1_key = nil
69
- @cache1_time = nil
70
- @cache2_key = nil
71
- @cache2_time = nil
72
- @parser =
73
- if time_format
74
- if time_format == '%iso8601'
75
- Proc.new { |value| Time.iso8601(value) }
76
- else
77
- Proc.new { |value| Time.strptime(value, time_format) }
78
- end
79
- else
80
- Time.method(:parse)
81
- end
82
- end
83
-
84
- def parse(value)
85
- unless value.is_a?(String)
86
- raise ParserError, "value must be string: #{value}"
87
- end
88
-
89
- if @cache1_key == value
90
- return @cache1_time
91
- elsif @cache2_key == value
92
- return @cache2_time
93
- else
94
- begin
95
- time = @parser.call(value).to_i
96
- rescue => e
97
- raise ParserError, "invalid time format: value = #{value}, error_class = #{e.class.name}, error = #{e.message}"
98
- end
99
- @cache1_key = @cache2_key
100
- @cache1_time = @cache2_time
101
- @cache2_key = value
102
- @cache2_time = time
103
- return time
104
- end
105
- end
106
- end
107
-
108
- module TypeConverter
109
- Converters = {
110
- 'string' => lambda { |v| v.to_s },
111
- 'integer' => lambda { |v| v.to_i },
112
- 'float' => lambda { |v| v.to_f },
113
- 'bool' => lambda { |v|
114
- case v.downcase
115
- when 'true', 'yes', '1'
116
- true
117
- else
118
- false
119
- end
120
- },
121
- 'time' => lambda { |v, time_parser|
122
- time_parser.parse(v)
123
- },
124
- 'array' => lambda { |v, delimiter|
125
- v.to_s.split(delimiter)
126
- }
127
- }
128
-
129
- def self.included(klass)
130
- klass.instance_eval {
131
- config_param :types, :string, default: nil
132
- config_param :types_delimiter, :string, default: ','
133
- config_param :types_label_delimiter, :string, default: ':'
134
- }
135
- end
136
-
137
- def configure(conf)
138
- super
139
-
140
- @type_converters = parse_types_parameter unless @types.nil?
141
- end
142
-
143
- private
144
-
145
- def convert_type(name, value)
146
- converter = @type_converters[name]
147
- converter.nil? ? value : converter.call(value)
148
- end
149
-
150
- def parse_types_parameter
151
- converters = {}
152
-
153
- @types.split(@types_delimiter).each { |pattern_name|
154
- name, type, format = pattern_name.split(@types_label_delimiter, 3)
155
- raise ConfigError, "Type is needed" if type.nil?
156
-
157
- case type
158
- when 'time'
159
- t_parser = TimeParser.new(format)
160
- converters[name] = lambda { |v|
161
- Converters[type].call(v, t_parser)
162
- }
163
- when 'array'
164
- delimiter = format || ','
165
- converters[name] = lambda { |v|
166
- Converters[type].call(v, delimiter)
167
- }
168
- else
169
- converters[name] = Converters[type]
170
- end
171
- }
172
-
173
- converters
174
- end
175
- end
176
-
177
- class RegexpParser < Parser
178
- include TypeConverter
179
-
180
- config_param :time_key, :string, default: 'time'
181
- config_param :time_format, :string, default: nil
182
-
183
- def initialize(regexp, conf={})
184
- super()
185
- @regexp = regexp
186
- unless conf.empty?
187
- conf = Config::Element.new('default_regexp_conf', '', conf, []) unless conf.is_a?(Config::Element)
188
- configure(conf)
189
- end
190
-
191
- @time_parser = TimeParser.new(@time_format)
192
- @mutex = Mutex.new
193
- end
194
-
195
- def configure(conf)
196
- super
197
- @time_parser = TimeParser.new(@time_format)
198
- end
199
-
200
- def patterns
201
- {'format' => @regexp, 'time_format' => @time_format}
202
- end
203
-
204
- def parse(text)
205
- m = @regexp.match(text)
206
- unless m
207
- if block_given?
208
- yield nil, nil
209
- return
210
- else
211
- return nil, nil
212
- end
213
- end
214
-
215
- time = nil
216
- record = {}
217
-
218
- m.names.each {|name|
219
- if value = m[name]
220
- case name
221
- when @time_key
222
- time = @mutex.synchronize { @time_parser.parse(value) }
223
- if @keep_time_key
224
- record[name] = if @type_converters.nil?
225
- value
226
- else
227
- convert_type(name, value)
228
- end
229
- end
230
- else
231
- record[name] = if @type_converters.nil?
232
- value
233
- else
234
- convert_type(name, value)
235
- end
236
- end
237
- end
238
- }
239
-
240
- if @estimate_current_event
241
- time ||= Engine.now
242
- end
243
-
244
- if block_given?
245
- yield time, record
246
- else # keep backward compatibility. will be removed at v1
247
- return time, record
248
- end
249
- end
250
- end
251
-
252
- class JSONParser < Parser
253
- config_param :time_key, :string, default: 'time'
254
- config_param :time_format, :string, default: nil
255
- config_param :json_parser, :string, default: 'oj'
256
-
257
- def configure(conf)
258
- super
259
-
260
- unless @time_format.nil?
261
- @time_parser = TimeParser.new(@time_format)
262
- @mutex = Mutex.new
263
- end
264
-
265
- begin
266
- raise LoadError unless @json_parser == 'oj'
267
- require 'oj'
268
- Oj.default_options = Fluent::DEFAULT_OJ_OPTIONS
269
- @load_proc = Oj.method(:load)
270
- @error_class = Oj::ParseError
271
- rescue LoadError
272
- @load_proc = Yajl.method(:load)
273
- @error_class = Yajl::ParseError
274
- end
275
- end
276
-
277
- def parse(text)
278
- record = @load_proc.call(text)
279
-
280
- value = @keep_time_key ? record[@time_key] : record.delete(@time_key)
281
- if value
282
- if @time_format
283
- time = @mutex.synchronize { @time_parser.parse(value) }
284
- else
285
- begin
286
- time = value.to_i
287
- rescue => e
288
- raise ParserError, "invalid time value: value = #{value}, error_class = #{e.class.name}, error = #{e.message}"
289
- end
290
- end
291
- else
292
- if @estimate_current_event
293
- time = Engine.now
294
- else
295
- time = nil
296
- end
297
- end
298
-
299
- if block_given?
300
- yield time, record
301
- else
302
- return time, record
303
- end
304
- rescue @error_class
305
- if block_given?
306
- yield nil, nil
307
- else
308
- return nil, nil
309
- end
310
- end
311
- end
312
-
313
- class ValuesParser < Parser
314
- include TypeConverter
315
-
316
- config_param :keys, default: [] do |val|
317
- if val.start_with?('[') # This check is enough because keys parameter is simple. No '[' started column name.
318
- JSON.load(val)
319
- else
320
- val.split(",")
321
- end
322
- end
323
- config_param :time_key, :string, default: nil
324
- config_param :time_format, :string, default: nil
325
- config_param :null_value_pattern, :string, default: nil
326
- config_param :null_empty_string, :bool, default: false
327
-
328
- def configure(conf)
329
- super
330
-
331
- if @time_key && !@keys.include?(@time_key) && @estimate_current_event
332
- raise ConfigError, "time_key (#{@time_key.inspect}) is not included in keys (#{@keys.inspect})"
333
- end
334
-
335
- if @time_format && !@time_key
336
- raise ConfigError, "time_format parameter is ignored because time_key parameter is not set. at #{conf.inspect}"
337
- end
338
-
339
- @time_parser = TimeParser.new(@time_format)
340
-
341
- if @null_value_pattern
342
- @null_value_pattern = Regexp.new(@null_value_pattern)
343
- end
344
-
345
- @mutex = Mutex.new
346
- end
347
-
348
- def values_map(values)
349
- record = Hash[keys.zip(values.map { |value| convert_value_to_nil(value) })]
350
-
351
- if @time_key
352
- value = @keep_time_key ? record[@time_key] : record.delete(@time_key)
353
- time = if value.nil?
354
- if @estimate_current_event
355
- Engine.now
356
- else
357
- nil
358
- end
359
- else
360
- @mutex.synchronize { @time_parser.parse(value) }
361
- end
362
- elsif @estimate_current_event
363
- time = Engine.now
364
- else
365
- time = nil
366
- end
367
-
368
- convert_field_type!(record) if @type_converters
369
-
370
- return time, record
371
- end
372
-
373
- private
374
-
375
- def convert_field_type!(record)
376
- @type_converters.each_key { |key|
377
- if value = record[key]
378
- record[key] = convert_type(key, value)
379
- end
380
- }
381
- end
382
-
383
- def convert_value_to_nil(value)
384
- if value and @null_empty_string
385
- value = (value == '') ? nil : value
386
- end
387
- if value and @null_value_pattern
388
- value = ::Fluent::StringUtil.match_regexp(@null_value_pattern, value) ? nil : value
389
- end
390
- value
391
- end
392
- end
393
-
394
- class TSVParser < ValuesParser
395
- config_param :delimiter, :string, default: "\t"
396
-
397
- def configure(conf)
398
- super
399
- @key_num = @keys.length
400
- end
401
-
402
- def parse(text)
403
- if block_given?
404
- yield values_map(text.split(@delimiter, @key_num))
405
- else
406
- return values_map(text.split(@delimiter, @key_num))
407
- end
408
- end
409
- end
410
-
411
- class LabeledTSVParser < ValuesParser
412
- config_param :delimiter, :string, default: "\t"
413
- config_param :label_delimiter, :string, default: ":"
414
- config_param :time_key, :string, default: "time"
415
-
416
- def configure(conf)
417
- conf['keys'] = conf['time_key'] || 'time'
418
- super(conf)
419
- end
420
-
421
- def parse(text)
422
- @keys = []
423
- values = []
424
-
425
- text.split(delimiter).each do |pair|
426
- key, value = pair.split(label_delimiter, 2)
427
- @keys.push(key)
428
- values.push(value)
429
- end
430
-
431
- if block_given?
432
- yield values_map(values)
433
- else
434
- return values_map(values)
435
- end
436
- end
437
- end
438
-
439
- class CSVParser < ValuesParser
440
- def initialize
441
- super
442
- require 'csv'
443
- end
444
-
445
- def parse(text)
446
- if block_given?
447
- yield values_map(CSV.parse_line(text))
448
- else
449
- return values_map(CSV.parse_line(text))
450
- end
451
- end
452
- end
453
-
454
- class NoneParser < Parser
455
- config_param :message_key, :string, default: 'message'
456
-
457
- def parse(text)
458
- record = {}
459
- record[@message_key] = text
460
- time = @estimate_current_event ? Engine.now : nil
461
- if block_given?
462
- yield time, record
463
- else
464
- return time, record
465
- end
466
- end
467
- end
468
-
469
- class ApacheParser < Parser
470
- REGEXP = /^(?<host>[^ ]*) [^ ]* (?<user>[^ ]*) \[(?<time>[^\]]*)\] "(?<method>\S+)(?: +(?<path>(?:[^\"]|\\.)*?)(?: +\S*)?)?" (?<code>[^ ]*) (?<size>[^ ]*)(?: "(?<referer>(?:[^\"]|\\.)*)" "(?<agent>(?:[^\"]|\\.)*)")?$/
471
- TIME_FORMAT = "%d/%b/%Y:%H:%M:%S %z"
472
-
473
- def initialize
474
- super
475
- @time_parser = TimeParser.new(TIME_FORMAT)
476
- @mutex = Mutex.new
477
- end
478
-
479
- def patterns
480
- {'format' => REGEXP, 'time_format' => TIME_FORMAT}
481
- end
482
-
483
- def parse(text)
484
- m = REGEXP.match(text)
485
- unless m
486
- if block_given?
487
- yield nil, nil
488
- return
489
- else
490
- return nil, nil
491
- end
492
- end
493
-
494
- host = m['host']
495
- host = (host == '-') ? nil : host
496
-
497
- user = m['user']
498
- user = (user == '-') ? nil : user
499
-
500
- time = m['time']
501
- time = @mutex.synchronize { @time_parser.parse(time) }
502
-
503
- method = m['method']
504
- path = m['path']
505
-
506
- code = m['code'].to_i
507
- code = nil if code == 0
508
-
509
- size = m['size']
510
- size = (size == '-') ? nil : size.to_i
511
-
512
- referer = m['referer']
513
- referer = (referer == '-') ? nil : referer
514
-
515
- agent = m['agent']
516
- agent = (agent == '-') ? nil : agent
517
-
518
- record = {
519
- "host" => host,
520
- "user" => user,
521
- "method" => method,
522
- "path" => path,
523
- "code" => code,
524
- "size" => size,
525
- "referer" => referer,
526
- "agent" => agent,
527
- }
528
- record["time"] = m['time'] if @keep_time_key
529
-
530
- if block_given?
531
- yield time, record
532
- else
533
- return time, record
534
- end
535
- end
536
- end
537
-
538
- class SyslogParser < Parser
539
- # From existence TextParser pattern
540
- REGEXP = /^(?<time>[^ ]*\s*[^ ]* [^ ]*) (?<host>[^ ]*) (?<ident>[^ :\[]*)(?:\[(?<pid>[0-9]+)\])?(?:[^\:]*\:)? *(?<message>.*)$/
541
- # From in_syslog default pattern
542
- REGEXP_WITH_PRI = /^\<(?<pri>[0-9]+)\>(?<time>[^ ]* {1,2}[^ ]* [^ ]*) (?<host>[^ ]*) (?<ident>[^ :\[]*)(?:\[(?<pid>[0-9]+)\])?(?:[^\:]*\:)? *(?<message>.*)$/
543
- REGEXP_RFC5424 = /\A^(?<time>[^ ]+) (?<host>[^ ]+) (?<ident>[^ ]+) (?<pid>[-0-9]+) (?<msgid>[^ ]+) (?<extradata>(\[(.*)\]|[^ ])) (?<message>.+)$\z/
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
- REGEXP_DETECT_RFC5424 = /^\<.*\>[1-9]\d{0,2}/
546
-
547
- config_param :time_format, :string, default: "%b %d %H:%M:%S"
548
- config_param :with_priority, :bool, default: false
549
- config_param :message_format, :enum, list: [:rfc3164, :rfc5424, :auto], default: :rfc3164
550
- config_param :rfc5424_time_format, :string, default: "%Y-%m-%dT%H:%M:%S.%L%z"
551
-
552
- def initialize
553
- super
554
- @mutex = Mutex.new
555
- end
556
-
557
- def configure(conf)
558
- super
559
-
560
- @time_parser_rfc3164 = @time_parser_rfc5424 = nil
561
- @regexp = case @message_format
562
- when :rfc3164
563
- class << self
564
- alias_method :parse, :parse_plain
565
- end
566
- @with_priority ? REGEXP_WITH_PRI : REGEXP
567
- when :rfc5424
568
- class << self
569
- alias_method :parse, :parse_plain
570
- end
571
- @time_format = @rfc5424_time_format unless conf.has_key?('time_format')
572
- @with_priority ? REGEXP_RFC5424_WITH_PRI : REGEXP_RFC5424
573
- when :auto
574
- class << self
575
- alias_method :parse, :parse_auto
576
- end
577
- @time_parser_rfc3164 = TextParser::TimeParser.new(@time_format)
578
- @time_parser_rfc5424 = TextParser::TimeParser.new(@rfc5424_time_format)
579
- nil
580
- end
581
- @time_parser = TextParser::TimeParser.new(@time_format)
582
- end
583
-
584
- def patterns
585
- {'format' => @regexp, 'time_format' => @time_format}
586
- end
587
-
588
- def parse(text)
589
- # This is overwritten in configure
590
- end
591
-
592
- def parse_auto(text, &block)
593
- if REGEXP_DETECT_RFC5424.match(text)
594
- @regexp = @with_priority ? REGEXP_RFC5424_WITH_PRI : REGEXP_RFC5424
595
- @time_parser = @time_parser_rfc5424
596
- else
597
- @regexp = @with_priority ? REGEXP_WITH_PRI : REGEXP
598
- @time_parser = @time_parser_rfc3164
599
- end
600
- parse_plain(text, &block)
601
- end
602
-
603
- def parse_plain(text, &block)
604
- m = @regexp.match(text)
605
- unless m
606
- if block_given?
607
- yield nil, nil
608
- return
609
- else
610
- return nil, nil
611
- end
612
- end
613
-
614
- time = nil
615
- record = {}
616
-
617
- m.names.each { |name|
618
- if value = m[name]
619
- case name
620
- when "pri"
621
- record['pri'] = value.to_i
622
- when "time"
623
- time = @mutex.synchronize { @time_parser.parse(value.gsub(/ +/, ' ')) }
624
- record[name] = value if @keep_time_key
625
- else
626
- record[name] = value
627
- end
628
- end
629
- }
630
-
631
- if @estimate_current_event
632
- time ||= Engine.now
633
- end
634
-
635
- if block_given?
636
- yield time, record
637
- else
638
- return time, record
639
- end
640
- end
641
- end
642
-
643
- class MultilineParser < Parser
644
- config_param :format_firstline, :string, default: nil
645
-
646
- FORMAT_MAX_NUM = 20
647
-
648
- def configure(conf)
649
- super
650
-
651
- formats = parse_formats(conf).compact.map { |f| f[1..-2] }.join
652
- begin
653
- @regex = Regexp.new(formats, Regexp::MULTILINE)
654
- if @regex.named_captures.empty?
655
- raise "No named captures"
656
- end
657
- @parser = RegexpParser.new(@regex, conf)
658
- rescue => e
659
- raise ConfigError, "Invalid regexp '#{formats}': #{e}"
660
- end
661
-
662
- if @format_firstline
663
- check_format_regexp(@format_firstline, 'format_firstline')
664
- @firstline_regex = Regexp.new(@format_firstline[1..-2])
665
- end
666
- end
667
-
668
- def parse(text, &block)
669
- if block
670
- @parser.call(text, &block)
671
- else
672
- @parser.call(text)
673
- end
674
- end
675
-
676
- def has_firstline?
677
- !!@format_firstline
678
- end
679
-
680
- def firstline?(text)
681
- @firstline_regex.match(text)
682
- end
683
-
684
- private
685
-
686
- def parse_formats(conf)
687
- check_format_range(conf)
688
-
689
- prev_format = nil
690
- (1..FORMAT_MAX_NUM).map { |i|
691
- format = conf["format#{i}"]
692
- if (i > 1) && prev_format.nil? && !format.nil?
693
- raise ConfigError, "Jump of format index found. format#{i - 1} is missing."
694
- end
695
- prev_format = format
696
- next if format.nil?
697
-
698
- check_format_regexp(format, "format#{i}")
699
- format
700
- }
701
- end
702
-
703
- def check_format_range(conf)
704
- invalid_formats = conf.keys.select { |k|
705
- m = k.match(/^format(\d+)$/)
706
- m ? !((1..FORMAT_MAX_NUM).include?(m[1].to_i)) : false
707
- }
708
- unless invalid_formats.empty?
709
- raise ConfigError, "Invalid formatN found. N should be 1 - #{FORMAT_MAX_NUM}: " + invalid_formats.join(",")
710
- end
711
- end
712
-
713
- def check_format_regexp(format, key)
714
- if format[0] == '/' && format[-1] == '/'
715
- begin
716
- Regexp.new(format[1..-2], Regexp::MULTILINE)
717
- rescue => e
718
- raise ConfigError, "Invalid regexp in #{key}: #{e}"
719
- end
720
- else
721
- raise ConfigError, "format should be Regexp, need //, in #{key}: '#{format}'"
722
- end
723
- end
724
- end
725
-
726
- TEMPLATE_REGISTRY = Registry.new(:config_type, 'fluent/plugin/parser_')
727
- {
728
- 'apache' => Proc.new { RegexpParser.new(/^(?<host>[^ ]*) [^ ]* (?<user>[^ ]*) \[(?<time>[^\]]*)\] "(?<method>\S+)(?: +(?<path>[^ ]*) +\S*)?" (?<code>[^ ]*) (?<size>[^ ]*)(?: "(?<referer>[^\"]*)" "(?<agent>[^\"]*)")?$/, {'time_format'=>"%d/%b/%Y:%H:%M:%S %z"}) },
729
- 'apache_error' => Proc.new { RegexpParser.new(/^\[[^ ]* (?<time>[^\]]*)\] \[(?<level>[^\]]*)\](?: \[pid (?<pid>[^\]]*)\])?( \[client (?<client>[^\]]*)\])? (?<message>.*)$/) },
730
- 'apache2' => Proc.new { ApacheParser.new },
731
- 'syslog' => Proc.new { SyslogParser.new },
732
- 'json' => Proc.new { JSONParser.new },
733
- 'tsv' => Proc.new { TSVParser.new },
734
- 'ltsv' => Proc.new { LabeledTSVParser.new },
735
- 'csv' => Proc.new { CSVParser.new },
736
- 'nginx' => Proc.new { RegexpParser.new(/^(?<remote>[^ ]*) (?<host>[^ ]*) (?<user>[^ ]*) \[(?<time>[^\]]*)\] "(?<method>\S+)(?: +(?<path>[^\"]*?)(?: +\S*)?)?" (?<code>[^ ]*) (?<size>[^ ]*)(?: "(?<referer>[^\"]*)" "(?<agent>[^\"]*)")?$/, {'time_format'=>"%d/%b/%Y:%H:%M:%S %z"}) },
737
- 'none' => Proc.new { NoneParser.new },
738
- 'multiline' => Proc.new { MultilineParser.new },
739
- }.each { |name, factory|
740
- TEMPLATE_REGISTRY.register(name, factory)
741
- }
742
-
743
- def self.register_template(name, regexp_or_proc, time_format=nil)
744
- if regexp_or_proc.is_a?(Class)
745
- factory = Proc.new { regexp_or_proc.new }
746
- elsif regexp_or_proc.is_a?(Regexp)
747
- regexp = regexp_or_proc
748
- factory = Proc.new { RegexpParser.new(regexp, {'time_format'=>time_format}) }
749
- else
750
- factory = regexp_or_proc
751
- end
752
-
753
- TEMPLATE_REGISTRY.register(name, factory)
754
- end
755
-
756
- def self.lookup(format)
757
- if format.nil?
758
- raise ConfigError, "'format' parameter is required"
759
- end
760
-
761
- if format[0] == ?/ && format[format.length-1] == ?/
762
- # regexp
763
- begin
764
- regexp = Regexp.new(format[1..-2])
765
- if regexp.named_captures.empty?
766
- raise "No named captures"
767
- end
768
- rescue
769
- raise ConfigError, "Invalid regexp '#{format[1..-2]}': #{$!}"
770
- end
771
-
772
- RegexpParser.new(regexp)
773
- else
774
- # built-in template
775
- begin
776
- factory = TEMPLATE_REGISTRY.lookup(format)
777
- rescue ConfigError => e # keep same error message
778
- raise ConfigError, "Unknown format template '#{format}'"
779
- end
780
-
781
- factory.call
782
- end
783
- end
784
-
785
- def initialize
786
- @parser = nil
787
- @estimate_current_event = nil
788
- end
789
-
790
- attr_reader :parser
791
-
792
- # SET false BEFORE CONFIGURE, to return nil when time not parsed
793
- # 'configure()' may raise errors for unexpected configurations
794
- attr_accessor :estimate_current_event
795
-
796
- def configure(conf, required=true)
797
- format = conf['format']
798
-
799
- @parser = TextParser.lookup(format)
800
- if ! @estimate_current_event.nil? && @parser.respond_to?(:'estimate_current_event=')
801
- @parser.estimate_current_event = @estimate_current_event
802
- end
803
-
804
- if @parser.respond_to?(:configure)
805
- @parser.configure(conf)
806
- end
807
-
808
- return true
809
- end
810
-
811
- def parse(text, &block)
812
- if block
813
- @parser.parse(text, &block)
814
- else # keep backward compatibility. Will be removed at v1
815
- return @parser.parse(text)
816
- end
817
- end
818
- end
20
+ ParserError = Fluent::Compat::Parser::ParserError
21
+ Parser = Fluent::Compat::Parser
22
+ TextParser = Fluent::Compat::TextParser
819
23
  end