fluent-plugin-norikra 0.0.9 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,246 +0,0 @@
1
- class Fluent::NorikraOutput
2
- class Query
3
- attr_accessor :name, :expression, :tag, :interval
4
-
5
- def initialize(name, expression, tag, interval)
6
- @name = name
7
- @expression = expression
8
- @tag = tag
9
- @interval = interval
10
- end
11
- end
12
-
13
- class QueryGenerator
14
- attr_reader :fetch_interval
15
-
16
- def initialize(name_template, expression_template, tag_template, opts={})
17
- @name_template = name_template || ''
18
- @expression_template = expression_template || ''
19
- @tag_template = tag_template || ''
20
- if @name_template.empty? || @expression_template.empty?
21
- raise Fluent::ConfigError, "query's name/expression must be specified"
22
- end
23
- @fetch_interval = case
24
- when opts['fetch_interval']
25
- Fluent::Config.time_value(opts['fetch_interval'])
26
- when @expression_template =~ /\.win:time_batch\(([^\)]+)\)/
27
- y,mon,w,d,h,m,s,msec = self.class.parse_time_period($1)
28
- (h * 3600 + m * 60 + s) / 5
29
- else
30
- 60
31
- end
32
- end
33
-
34
- def generate(name, escaped)
35
- Fluent::NorikraOutput::Query.new(
36
- self.class.replace_target(name, @name_template),
37
- self.class.replace_target(escaped, @expression_template),
38
- self.class.replace_target(name, @tag_template),
39
- @fetch_interval
40
- )
41
- end
42
-
43
- def self.replace_target(t, str)
44
- str.gsub('${target}', t)
45
- end
46
-
47
- def self.parse_time_period(string)
48
- #### http://esper.codehaus.org/esper-4.9.0/doc/reference/en-US/html/epl_clauses.html#epl-syntax-time-periods
49
- # time-period : [year-part] [month-part] [week-part] [day-part] [hour-part] [minute-part] [seconds-part] [milliseconds-part]
50
- # year-part : (number|variable_name) ("years" | "year")
51
- # month-part : (number|variable_name) ("months" | "month")
52
- # week-part : (number|variable_name) ("weeks" | "week")
53
- # day-part : (number|variable_name) ("days" | "day")
54
- # hour-part : (number|variable_name) ("hours" | "hour")
55
- # minute-part : (number|variable_name) ("minutes" | "minute" | "min")
56
- # seconds-part : (number|variable_name) ("seconds" | "second" | "sec")
57
- # milliseconds-part : (number|variable_name) ("milliseconds" | "millisecond" | "msec")
58
- m = /^\s*(\d+ years?)? ?(\d+ months?)? ?(\d+ weeks?)? ?(\d+ days?)? ?(\d+ hours?)? ?(\d+ (?:min|minute|minutes))? ?(\d+ (?:sec|second|seconds))? ?(\d+ (?:msec|millisecond|milliseconds))?/.match(string)
59
- years = (m[1] || '').split(' ',2).first.to_i
60
- months = (m[2] || '').split(' ',2).first.to_i
61
- weeks = (m[3] || '').split(' ',2).first.to_i
62
- days = (m[4] || '').split(' ',2).first.to_i
63
- hours = (m[5] || '').split(' ',2).first.to_i
64
- minutes = (m[6] || '').split(' ',2).first.to_i
65
- seconds = (m[7] || '').split(' ',2).first.to_i
66
- msecs = (m[8] || '').split(' ',2).first.to_i
67
- return [years, months, weeks, days, hours, minutes, seconds, msecs]
68
- end
69
- end
70
-
71
- class RecordFilter
72
- attr_reader :default_policy, :include_fields, :include_regexp, :exclude_fields, :exclude_regexp
73
-
74
- def initialize(include='', include_regexp='', exclude='', exclude_regexp='')
75
- include ||= ''
76
- include_regexp ||= ''
77
- exclude ||= ''
78
- exclude_regexp ||= ''
79
-
80
- @default_policy = nil
81
- if include == '*' && exclude == '*'
82
- raise Fluent::ConfigError, "invalid configuration, both of 'include' and 'exclude' are '*'"
83
- end
84
- if include.empty? && include_regexp.empty? && exclude.empty? && exclude_regexp.empty? # assuming "include *"
85
- @default_policy = :include
86
- elsif exclude.empty? && exclude_regexp.empty? || exclude == '*' # assuming "exclude *"
87
- @default_policy = :exclude
88
- elsif include.empty? && include_regexp.empty? || include == '*' # assuming "include *"
89
- @default_policy = :include
90
- else
91
- raise Fluent::ConfigError, "unknown default policy. specify 'include *' or 'exclude *'"
92
- end
93
-
94
- @include_fields = nil
95
- @include_regexp = nil
96
- @exclude_fields = nil
97
- @exclude_regexp = nil
98
-
99
- if @default_policy == :exclude
100
- @include_fields = include.split(',')
101
- @include_regexp = Regexp.new(include_regexp) unless include_regexp.empty?
102
- if @include_fields.empty? && @include_regexp.nil?
103
- raise Fluent::ConfigError, "no one fields specified. specify 'include' or 'include_regexp'"
104
- end
105
- else
106
- @exclude_fields = exclude.split(',')
107
- @exclude_regexp = Regexp.new(exclude_regexp) unless exclude_regexp.empty?
108
- end
109
- end
110
-
111
- def filter(record)
112
- if @default_policy == :include
113
- if @exclude_fields.empty? && @exclude_regexp.nil?
114
- record
115
- else
116
- record = record.dup
117
- record.keys.each do |f|
118
- record.delete(f) if @exclude_fields.include?(f) || @exclude_regexp && @exclude_regexp.match(f)
119
- end
120
- record
121
- end
122
- else # default policy exclude
123
- data = {}
124
- record.keys.each do |f|
125
- data[f] = record[f] if @include_fields.include?(f) || @include_regexp && @include_regexp.match(f)
126
- end
127
- data
128
- end
129
- end
130
- end
131
-
132
- class ConfigSection
133
- attr_accessor :target, :target_matcher, :auto_field, :filter_params, :field_definitions, :query_generators
134
-
135
- def initialize(section)
136
- @target = nil
137
- @target_matcher = nil
138
- if section.name == 'default'
139
- # nil
140
- elsif section.name == 'target'
141
- # unescaped target name (tag style with dots)
142
- @target = section.arg
143
- @target_matcher = Fluent::GlobMatchPattern.new(section.arg)
144
- else
145
- raise ArgumentError, "invalid section for this class, #{section.name}: ConfigSection"
146
- end
147
-
148
- @auto_field = Fluent::Config.bool_value(section['auto_field'])
149
-
150
- @filter_params = {
151
- :include => section['include'],
152
- :include_regexp => section['include_regexp'],
153
- :exclude => section['exclude'],
154
- :exclude_regexp => section['exclude_regexp']
155
- }
156
- @field_definitions = {
157
- :string => (section['field_string'] || '').split(','),
158
- :boolean => (section['field_boolean'] || '').split(','),
159
- :int => (section['field_int'] || '').split(','),
160
- :long => (section['field_long'] || '').split(','),
161
- :float => (section['field_float'] || '').split(','),
162
- :double => (section['field_double'] || '').split(',')
163
- }
164
- @query_generators = []
165
- section.elements.each do |element|
166
- if element.name == 'query'
167
- opt = {}
168
- if element.has_key?('fetch_interval')
169
- opt['fetch_interval'] = element['fetch_interval'].to_i
170
- end
171
- @query_generators.push(QueryGenerator.new(element['name'], element['expression'], element['tag'], opt))
172
- end
173
- end
174
- end
175
-
176
- def +(other)
177
- if other.nil?
178
- other = self.class.new(Fluent::Config::Element.new('target', 'dummy', {}, []))
179
- end
180
- r = self.class.new(Fluent::Config::Element.new('target', (other.target ? other.target : self.target), {}, []))
181
- r.auto_field = (other.auto_field.nil? ? self.auto_field : other.auto_field)
182
-
183
- others_filter = {}
184
- other.filter_params.keys.each do |k|
185
- others_filter[k] = other.filter_params[k] if other.filter_params[k]
186
- end
187
- r.filter_params = self.filter_params.merge(others_filter)
188
- r.field_definitions = {
189
- :string => self.field_definitions[:string] + other.field_definitions[:string],
190
- :boolean => self.field_definitions[:boolean] + other.field_definitions[:boolean],
191
- :int => self.field_definitions[:int] + other.field_definitions[:int],
192
- :long => self.field_definitions[:long] + other.field_definitions[:long],
193
- :float => self.field_definitions[:float] + other.field_definitions[:float],
194
- :double => self.field_definitions[:double] + other.field_definitions[:double]
195
- }
196
- r.query_generators = self.query_generators + other.query_generators
197
- r
198
- end
199
- end
200
-
201
- class Target
202
- attr_accessor :name, :auto_field, :fields, :queries
203
- attr_reader :escaped_name
204
-
205
- def self.escape(src)
206
- if src.nil? || src.empty?
207
- return 'FluentdGenerated'
208
- end
209
-
210
- dst = src.gsub(/[^_a-zA-Z0-9]/, '_')
211
- unless dst =~ /^[a-zA-Z]([_a-zA-Z0-9]*[a-zA-Z0-9])?$/
212
- unless dst =~ /^[a-zA-Z]/
213
- dst = 'Fluentd' + dst
214
- end
215
- unless dst =~ /[a-zA-Z0-9]$/
216
- dst = dst + 'Generated'
217
- end
218
- end
219
- dst
220
- end
221
-
222
- def initialize(target, config)
223
- @name = target
224
- @escaped_name = self.class.escape(@name)
225
- @auto_field = config.auto_field.nil? ? true : config.auto_field
226
-
227
- @filter = RecordFilter.new(*([:include, :include_regexp, :exclude, :exclude_regexp].map{|s| config.filter_params[s]}))
228
- @fields = config.field_definitions
229
- @queries = config.query_generators.map{|g| g.generate(@name, @escaped_name)}
230
- end
231
-
232
- def filter(record)
233
- @filter.filter(record)
234
- end
235
-
236
- def reserve_fields
237
- f = {}
238
- @fields.keys.each do |type_sym|
239
- @fields[type_sym].each do |fieldname|
240
- f[fieldname] = type_sym.to_s
241
- end
242
- end
243
- f
244
- end
245
- end
246
- end
@@ -1,5 +1,11 @@
1
+ require_relative 'norikra/output'
2
+
3
+ require 'norikra-client'
4
+
1
5
  module Fluent
2
6
  class NorikraOutput < Fluent::BufferedOutput
7
+ include Fluent::NorikraPlugin::OutputMixin
8
+
3
9
  Fluent::Plugin.register_output('norikra', self)
4
10
 
5
11
  config_set_default :flush_interval, 1 # 1sec
@@ -10,11 +16,8 @@ module Fluent
10
16
  config_param :send_timeout, :integer, :default => nil
11
17
  config_param :receive_timeout, :integer, :default => nil
12
18
 
13
- #<server>
14
- attr_reader :execute_server, :execute_server_path
15
-
19
+ #for OutputMixin
16
20
  config_param :remove_tag_prefix, :string, :default => nil
17
-
18
21
  config_param :target_map_tag, :bool, :default => false
19
22
  config_param :target_map_key, :string, :default => nil
20
23
  config_param :target_string, :string, :default => nil
@@ -22,15 +25,6 @@ module Fluent
22
25
  # <default>
23
26
  # <target TARGET>
24
27
 
25
- # <events>
26
- attr_reader :event_method, :event_tag_generator, :event_sweep_interval
27
-
28
- def initialize
29
- super
30
- require_relative 'norikra_target'
31
- require 'norikra/client'
32
- end
33
-
34
28
  def configure(conf)
35
29
  super
36
30
 
@@ -40,78 +34,17 @@ module Fluent
40
34
  if !@target_map_tag && @target_map_key.nil? && @target_string.nil?
41
35
  raise Fluent::ConfigError, 'target naming not specified (target_map_tag/target_map_key/target_string)'
42
36
  end
43
- @target_generator = case
44
- when @target_string
45
- lambda {|tag,record| @target_string}
46
- when @target_map_key
47
- lambda {|tag,record| record[@target_map_key]}
48
- when @target_map_tag
49
- lambda {|tag,record| tag.gsub(/^#{@remove_tag_prefix}(\.)?/, '')}
50
- else
51
- raise Fluent::ConfigError, "no one way specified to decide target"
52
- end
53
-
54
- # target map already prepared (opened, and related queries registered)
55
- @target_map = {} # 'target' => instance of Fluent::NorikraOutput::Target
56
-
57
- # for conversion from query_name to tag
58
- @query_map = {} # 'query_name' => instance of Fluent::NorikraOutput::Query
59
-
60
- @default_target = ConfigSection.new(Fluent::Config::Element.new('default', nil, {}, []))
61
- @config_targets = {}
62
37
 
63
- @execute_server = false
64
-
65
- event_section = nil
66
38
  conf.elements.each do |element|
67
39
  case element.name
68
- when 'default'
69
- @default_target = ConfigSection.new(element)
70
- when 'target'
71
- c = ConfigSection.new(element)
72
- @config_targets[c.target] = c
73
- when 'server'
74
- @execute_server = true
75
- @execute_jruby_path = element['jruby']
76
- @execute_server_path = element['path']
77
- @execute_server_opts = element['opts']
78
- when 'event', 'events'
79
- event_section = element
40
+ when 'default', 'target'
41
+ # ignore: processed in OutputMixin
80
42
  else
81
43
  raise Fluent::ConfigError, "unknown configuration section name for this plugin: #{element.name}"
82
44
  end
83
45
  end
84
46
 
85
- @event_method = @event_tag_generator = @event_sweep_interval = nil
86
- if event_section
87
- @event_method = case event_section['method']
88
- when 'sweep' then :sweep
89
- when 'listen'
90
- raise Fluent::ConfigError, "not implemeneted now"
91
- else
92
- raise Fluent::ConfigError, "unknown method #{event_section['method']}"
93
- end
94
- unless event_section['tag']
95
- raise Fluent::ConfigError, "<event> section needs 'tag' configuration"
96
- end
97
- tag_prefix = if event_section.has_key?('tag_prefix')
98
- event_section['tag_prefix'] + (event_section['tag_prefix'] =~ /\.$/ ? '' : '.')
99
- else
100
- ''
101
- end
102
- tag_by, tag_arg = event_section['tag'].split(/ +/, 2)
103
- @event_tag_generator = case tag_by
104
- when 'query_name' then lambda{|query_name,record| tag_prefix + query_name}
105
- when 'field' then lambda{|query_name,record| tag_prefix + record[tag_arg]}
106
- when 'string' then lambda{|query_name,record| tag_prefix + tag_arg}
107
- else
108
- raise Fluent::ConfigError, "unknown tag configuration specified:#{event_section['tag']}"
109
- end
110
- @event_sweep_interval = Fluent::Config.time_value(event_section['sweep_interval'] || '10s')
111
- end
112
-
113
- @mutex = Mutex.new
114
- @target_mutex = Mutex.new
47
+ setup_output(conf, false) # <query> disabled in <default> and <target TARGET>
115
48
  end
116
49
 
117
50
  def client(opts={})
@@ -124,298 +57,16 @@ module Fluent
124
57
 
125
58
  def start
126
59
  super
127
-
128
- @norikra_started = false
129
-
130
- if @execute_server
131
- @norikra_pid = nil
132
- @norikra_thread = Thread.new(&method(:server_starter))
133
- # @norikra_started will be set in server_starter
134
- else
135
- @norikra_pid = nil
136
- @norikra_thread = nil
137
- @norikra_started = true
138
- end
139
-
140
- # register worker thread
141
- @register_queue = []
142
- @registered_targets = {}
143
- @register_thread = Thread.new(&method(:register_worker))
144
-
145
- # fetch worker thread
146
- @fetch_queue = []
147
- @fetch_thread = Thread.new(&method(:fetch_worker))
148
-
149
- # for sweep
150
- if @event_method
151
- @fetch_queue.push(FetchRequest.new(nil, @event_sweep_interval))
152
- end
60
+ start_output
153
61
  end
154
62
 
155
63
  def shutdown
156
- @register_thread.kill
157
- @fetch_thread.kill
158
- Process.kill(:TERM, @norikra_pid) if @execute_server
159
-
160
- @register_thread.join
161
- @fetch_thread.join
162
-
163
- if @execute_server
164
- begin
165
- counter = 0
166
- while !Process.waitpid(@norikra_pid, Process::WNOHANG)
167
- sleep 1
168
- break if counter > 3
169
- end
170
- rescue Errno::ECHILD
171
- # norikra server process exited.
172
- end
173
- end
174
- end
175
-
176
- def server_starter
177
- $log.info "starting Norikra server process #{@host}:#{@port}"
178
- base_options = [@execute_server_path, 'start', '-H', @host, '-P', @port.to_s]
179
- cmd,options = if @execute_jruby_path
180
- [@execute_jruby_path, [@execute_server_path, 'start', '-H', @host, '-P', @port.to_s]]
181
- else
182
- [@execute_server_path, ['start', '-H', @host, '-P', @port.to_s]]
183
- end
184
- if @execute_server_opts
185
- options += @execute_server_opts.split(/ +/)
186
- end
187
- @norikra_pid = fork do
188
- ENV.keys.select{|k| k =~ /^(RUBY|GEM|BUNDLE|RBENV|RVM|rvm)/}.each {|k| ENV.delete(k)}
189
- exec([cmd, 'norikra(fluentd)'], *options)
190
- end
191
- connecting = true
192
- $log.info "trying to confirm norikra server status..."
193
- while connecting
194
- begin
195
- $log.debug "start to connect norikra server #{@host}:#{@port}"
196
- client(:connect_timeout => 1, :send_timeout => 1, :receive_timeout => 1).targets
197
- # discard result: no exceptions is success
198
- connecting = false
199
- next
200
- rescue HTTPClient::TimeoutError
201
- $log.debug "Norikra server test connection timeout. retrying..."
202
- rescue Errno::ECONNREFUSED
203
- $log.debug "Norikra server test connection refused. retrying..."
204
- rescue => e
205
- $log.error "unknown error in confirming norikra server, #{e.class}:#{e.message}"
206
- end
207
- sleep 3
208
- end
209
- $log.info "confirmed that norikra server #{@host}:#{@port} started."
210
- @norikra_started = true
211
- end
212
-
213
- def register_worker
214
- while sleep(0.25)
215
- next unless @norikra_started
216
-
217
- c = client()
218
-
219
- targets = @register_queue.shift(10)
220
- targets.each do |t|
221
- next if @target_map[t.name]
222
-
223
- $log.debug "Preparing norikra target #{t.name} on #{@host}:#{@port}"
224
- if prepare_target(c, t)
225
- $log.debug "success to prepare target #{t.name} on #{@host}:#{@port}"
226
- # success
227
- t.queries.each do |query|
228
- @query_map[query.name] = query
229
- insert_fetch_queue(FetchRequest.new(query)) unless query.tag.empty? || @event_method
230
- end
231
- @target_map[t.name] = t
232
- @registered_targets.delete(t.name)
233
- else
234
- $log.error "Failed to prepare norikra data for target:#{t.name}"
235
- @norikra_started.push(t)
236
- end
237
- end
238
- end
239
- end
240
-
241
- def fetch_worker
242
- while sleep(1)
243
- next unless @norikra_started
244
- next if @fetch_queue.first.nil? || @fetch_queue.first.time > Time.now
245
-
246
- now = Time.now
247
- while @fetch_queue.first.time <= now
248
- req = @fetch_queue.shift
249
- if req.query.nil?
250
- sweep()
251
- else
252
- fetch(req.query)
253
- end
254
- insert_fetch_queue(req)
255
- end
256
- end
64
+ stop_output
65
+ shutdown_output
257
66
  end
258
67
 
259
- def format_stream(tag, es)
260
- tobe_registered_target_names = []
261
-
262
- out = ''
263
-
264
- es.each do |time,record|
265
- target = @target_generator.call(tag, record)
266
-
267
- tgt = @target_mutex.synchronize do
268
- t = @target_map[target]
269
- unless t
270
- unless tobe_registered_target_names.include?(target)
271
- conf = @config_targets[target]
272
- unless conf
273
- @config_targets.values.each do |c|
274
- if c.target_matcher.match(target)
275
- conf = c
276
- break
277
- end
278
- end
279
- end
280
- t = Target.new(target, @default_target + conf)
281
- @registered_targets[target] = t
282
- @register_queue.push(t)
283
- tobe_registered_target_names.push(target)
284
- end
285
- t = @registered_targets[target]
286
- end
287
- t
288
- end
289
-
290
- event = tgt.filter(record)
291
-
292
- out << [tgt.escaped_name,event].to_msgpack
293
- end
294
-
295
- out
296
- end
297
-
298
- def prepared?(target_names)
299
- @norikra_started && target_names.reduce(true){|r,t| r && @target_map.values.any?{|target| target.escaped_name == t}}
300
- end
301
-
302
- def write(chunk)
303
- events_map = {} # target => [event]
304
- chunk.msgpack_each do |target, event|
305
- events_map[target] ||= []
306
- events_map[target].push(event)
307
- end
308
-
309
- unless prepared?(events_map.keys)
310
- raise RuntimeError, "norikra server is not ready for this targets: #{events_map.keys.join(',')}"
311
- end
312
-
313
- c = client()
314
-
315
- events_map.each do |target, events|
316
- c.send(target, events)
317
- end
318
- end
319
-
320
- def prepare_target(client, target)
321
- # target open and reserve fields
322
- $log.debug "Going to prepare about target"
323
- begin
324
- unless client.targets.include?(target.escaped_name)
325
- $log.debug "opening target #{target.escaped_name}"
326
- client.open(target.escaped_name, target.reserve_fields, target.auto_field)
327
- $log.debug "opening target #{target.escaped_name}, done."
328
- end
329
-
330
- reserving = target.reserve_fields
331
- reserved = []
332
- client.fields(target.escaped_name).each do |field|
333
- if reserving[field['name']]
334
- reserved.push(field['name'])
335
- if reserving[field['name']] != field['type']
336
- $log.warn "field type mismatch, reserving:#{reserving[field['name']]} but reserved:#{field['type']}"
337
- end
338
- end
339
- end
340
-
341
- reserving.each do |fieldname,type|
342
- client.reserve(target.escaped_name, fieldname, type) unless reserved.include?(fieldname)
343
- end
344
- rescue => e
345
- $log.error "failed to prepare target:#{target.escaped_name}", :norikra => "#{@host}:#{@port}", :error => e.class, :message => e.message
346
- return false
347
- end
348
-
349
- # query registration
350
- begin
351
- registered = Hash[client.queries.map{|q| [q['name'], q['expression']]}]
352
- target.queries.each do |query|
353
- if registered.has_key?(query.name) # query already registered
354
- if registered[query.name] != query.expression
355
- $log.warn "query name and expression mismatch, check norikra server status. target query name:#{query.name}"
356
- end
357
- next
358
- end
359
- client.register(query.name, query.expression)
360
- end
361
- rescue => e
362
- $log.warn "failed to register query", :norikra => "#{@host}:#{@port}", :error => e.class, :message => e.message
363
- end
364
- end
365
-
366
- class FetchRequest
367
- attr_accessor :time, :query
368
- def initialize(query, interval=nil)
369
- @query = query
370
- @interval = interval || query.interval
371
- @time = Time.now + @interval
372
- end
373
- def <=>(other)
374
- self.time <=> other.time
375
- end
376
- def next!
377
- @time = Time.now + @interval
378
- end
379
- end
380
-
381
- def insert_fetch_queue(request)
382
- @mutex.synchronize do
383
- request.next!
384
- # if @fetch_queue.size > 0
385
- # next_pos = @fetch_queue.bsearch{|req| req.time > request.time}
386
- # @fetch_queue.insert(next_pos, request)
387
- # else
388
- # @fetch_queue.push(request)
389
- # end
390
- @fetch_queue.push(request)
391
- @fetch_queue.sort!
392
- end
393
- rescue => e
394
- $log.error "unknown log encountered", :error_class => e.class, :message => e.message
395
- end
396
-
397
- def sweep
398
- begin
399
- client().sweep.each do |query_name, event_array|
400
- query = @query_map[query_name]
401
- event_array.each do |time,event|
402
- tag = (query && !query.tag.empty?) ? query.tag : @event_tag_generator.call(query_name, event)
403
- Fluent::Engine.emit(tag, time, event)
404
- end
405
- end
406
- rescue => e
407
- $log.error "failed to sweep", :norikra => "#{@host}:#{@port}", :error => e.class, :message => e.message
408
- end
409
- end
410
-
411
- def fetch(query)
412
- begin
413
- client().event(query.name).each do |time,event| # [[time(int from epoch), event], ...]
414
- Fluent::Engine.emit(query.tag, time, event)
415
- end
416
- rescue => e
417
- $log.error "failed to fetch for query:#{query.name}", :norikra => "#{@host}:#{@port}", :error => e.class, :message => e.message
418
- end
68
+ def fetchable?
69
+ true
419
70
  end
420
71
  end
421
72
  end