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.
- checksums.yaml +4 -4
- data/README.md +174 -125
- data/example/blank.conf +2 -3
- data/example/blank.rb +15 -0
- data/example/blank2.conf +1 -1
- data/example/example1.conf +6 -7
- data/example/test1.conf +4 -5
- data/example/test1.rb +40 -0
- data/example/test2.conf +5 -6
- data/example/test_in_out.rb +48 -0
- data/fluent-plugin-norikra.gemspec +1 -1
- data/lib/fluent/plugin/in_norikra.rb +75 -0
- data/lib/fluent/plugin/norikra/config_section.rb +67 -0
- data/lib/fluent/plugin/norikra/fetch_request.rb +72 -0
- data/lib/fluent/plugin/norikra/input.rb +109 -0
- data/lib/fluent/plugin/norikra/output.rb +213 -0
- data/lib/fluent/plugin/norikra/query.rb +13 -0
- data/lib/fluent/plugin/norikra/query_generator.rb +61 -0
- data/lib/fluent/plugin/norikra/record_filter.rb +62 -0
- data/lib/fluent/plugin/norikra/target.rb +47 -0
- data/lib/fluent/plugin/norikra_target.rb +0 -246
- data/lib/fluent/plugin/out_norikra.rb +15 -364
- data/lib/fluent/plugin/out_norikra_filter.rb +172 -0
- data/test/helper.rb +2 -0
- data/test/plugin/test_in_norikra.rb +14 -0
- data/test/plugin/test_out_norikra.rb +5 -1
- data/test/plugin/test_out_norikra_filter.rb +15 -0
- data/test/test_config_section.rb +80 -25
- data/test/test_query.rb +6 -2
- data/test/test_query_generator.rb +9 -4
- data/test/test_record_filter.rb +2 -2
- data/test/test_target.rb +11 -13
- metadata +19 -2
@@ -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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
157
|
-
|
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
|
260
|
-
|
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
|