ffwd 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 +7 -0
- data/bin/ffwd +9 -0
- data/bin/fwc +15 -0
- data/lib/em/all.rb +68 -0
- data/lib/ffwd.rb +250 -0
- data/lib/ffwd/channel.rb +62 -0
- data/lib/ffwd/circular_buffer.rb +78 -0
- data/lib/ffwd/connection.rb +40 -0
- data/lib/ffwd/core.rb +173 -0
- data/lib/ffwd/core/emitter.rb +38 -0
- data/lib/ffwd/core/interface.rb +47 -0
- data/lib/ffwd/core/processor.rb +92 -0
- data/lib/ffwd/core/reporter.rb +32 -0
- data/lib/ffwd/debug.rb +76 -0
- data/lib/ffwd/debug/connection.rb +48 -0
- data/lib/ffwd/debug/monitor_session.rb +71 -0
- data/lib/ffwd/debug/tcp.rb +82 -0
- data/lib/ffwd/event.rb +65 -0
- data/lib/ffwd/event_emitter.rb +57 -0
- data/lib/ffwd/handler.rb +43 -0
- data/lib/ffwd/lifecycle.rb +92 -0
- data/lib/ffwd/logging.rb +139 -0
- data/lib/ffwd/metric.rb +55 -0
- data/lib/ffwd/metric_emitter.rb +50 -0
- data/lib/ffwd/plugin.rb +149 -0
- data/lib/ffwd/plugin/json_line.rb +47 -0
- data/lib/ffwd/plugin/json_line/connection.rb +118 -0
- data/lib/ffwd/plugin/log.rb +35 -0
- data/lib/ffwd/plugin/log/writer.rb +42 -0
- data/lib/ffwd/plugin_channel.rb +64 -0
- data/lib/ffwd/plugin_loader.rb +121 -0
- data/lib/ffwd/processor.rb +96 -0
- data/lib/ffwd/processor/count.rb +109 -0
- data/lib/ffwd/processor/histogram.rb +200 -0
- data/lib/ffwd/processor/rate.rb +116 -0
- data/lib/ffwd/producing_client.rb +181 -0
- data/lib/ffwd/protocol.rb +28 -0
- data/lib/ffwd/protocol/tcp.rb +126 -0
- data/lib/ffwd/protocol/tcp/bind.rb +64 -0
- data/lib/ffwd/protocol/tcp/connection.rb +107 -0
- data/lib/ffwd/protocol/tcp/flushing_connect.rb +135 -0
- data/lib/ffwd/protocol/tcp/plain_connect.rb +74 -0
- data/lib/ffwd/protocol/udp.rb +48 -0
- data/lib/ffwd/protocol/udp/bind.rb +64 -0
- data/lib/ffwd/protocol/udp/connect.rb +110 -0
- data/lib/ffwd/reporter.rb +65 -0
- data/lib/ffwd/retrier.rb +72 -0
- data/lib/ffwd/schema.rb +92 -0
- data/lib/ffwd/schema/default.rb +36 -0
- data/lib/ffwd/schema/spotify100.rb +58 -0
- data/lib/ffwd/statistics.rb +29 -0
- data/lib/ffwd/statistics/collector.rb +99 -0
- data/lib/ffwd/statistics/system_statistics.rb +255 -0
- data/lib/ffwd/tunnel.rb +27 -0
- data/lib/ffwd/tunnel/plugin.rb +47 -0
- data/lib/ffwd/tunnel/tcp.rb +60 -0
- data/lib/ffwd/tunnel/udp.rb +61 -0
- data/lib/ffwd/utils.rb +46 -0
- data/lib/ffwd/version.rb +18 -0
- data/lib/fwc.rb +206 -0
- metadata +163 -0
data/lib/ffwd/logging.rb
ADDED
@@ -0,0 +1,139 @@
|
|
1
|
+
# $LICENSE
|
2
|
+
# Copyright 2013-2014 Spotify AB. All rights reserved.
|
3
|
+
#
|
4
|
+
# The contents of this file are licensed under the Apache License, Version 2.0
|
5
|
+
# (the "License"); you may not use this file except in compliance with the
|
6
|
+
# License. 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, WITHOUT
|
12
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
13
|
+
# License for the specific language governing permissions and limitations under
|
14
|
+
# the License.
|
15
|
+
|
16
|
+
# Logging functionality.
|
17
|
+
#
|
18
|
+
# Defines FFWD::Logging which when included in either a class or module makes
|
19
|
+
# the 'log' field available both as a class and instance field.
|
20
|
+
#
|
21
|
+
# 'log' in turn is an object with the following fields available.
|
22
|
+
#
|
23
|
+
# 'debug' - Log a message of level DEBUG..
|
24
|
+
# 'info' - Log a message of level INFO.
|
25
|
+
# 'warning' - Log a message of level WARNING.
|
26
|
+
# 'error' - Log a message of level ERROR.
|
27
|
+
#
|
28
|
+
# Every function takes the message to log as the only parameter except 'error'
|
29
|
+
# which can take an exception as a secondary argument.
|
30
|
+
#
|
31
|
+
# If an exception is provided, a stacktrace will be printed to log.
|
32
|
+
require 'logger'
|
33
|
+
|
34
|
+
module FFWD
|
35
|
+
def self.log
|
36
|
+
@log ||= setup_log
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.log_reload
|
40
|
+
@log = setup_log
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.setup_log
|
44
|
+
if log_config[:file]
|
45
|
+
file = log_config[:file]
|
46
|
+
shift_age = log_config[:shift_age]
|
47
|
+
|
48
|
+
return ::Logger.new(file, shift_age=shift_age).tap do |l|
|
49
|
+
l.level = log_config[:level]
|
50
|
+
l.progname = log_config[:progname]
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
if log_config[:stream]
|
55
|
+
return ::Logger.new(log_config[:stream]).tap do |l|
|
56
|
+
l.level = log_config[:level]
|
57
|
+
l.progname = log_config[:progname]
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
raise "cannot setup loggin with options: #{log_config}"
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.log_config
|
65
|
+
return @log_config unless @log_config.nil?
|
66
|
+
|
67
|
+
@log_config = {
|
68
|
+
:file => nil,
|
69
|
+
:shift_age => 1,
|
70
|
+
:level => Logger::INFO,
|
71
|
+
:stream => STDOUT,
|
72
|
+
:progname => 'FFWD',
|
73
|
+
}
|
74
|
+
end
|
75
|
+
|
76
|
+
def self.log_disable
|
77
|
+
@log_disable = true
|
78
|
+
end
|
79
|
+
|
80
|
+
def self.log_disabled?
|
81
|
+
@log_disable || false
|
82
|
+
end
|
83
|
+
|
84
|
+
class ClassLogger
|
85
|
+
def initialize klass
|
86
|
+
@progname = klass.name
|
87
|
+
end
|
88
|
+
|
89
|
+
def debug message
|
90
|
+
FFWD.log.debug(@progname){message}
|
91
|
+
end
|
92
|
+
|
93
|
+
def info message
|
94
|
+
FFWD.log.info(@progname){message}
|
95
|
+
end
|
96
|
+
|
97
|
+
def warning message
|
98
|
+
FFWD.log.warn(@progname){message}
|
99
|
+
end
|
100
|
+
|
101
|
+
def error message, e=nil
|
102
|
+
FFWD.log.error(@progname){message}
|
103
|
+
|
104
|
+
return unless e
|
105
|
+
|
106
|
+
FFWD.log.error(@progname){"Caused by #{e.class}: #{e}"}
|
107
|
+
e.backtrace.each do |b|
|
108
|
+
FFWD.log.error(@progname){" #{b}"}
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
class FakeLogger
|
114
|
+
def debug message; end
|
115
|
+
def info message; end
|
116
|
+
def warning message; end
|
117
|
+
def error message, e=nil; end
|
118
|
+
end
|
119
|
+
|
120
|
+
module Logging
|
121
|
+
module ClassMethods
|
122
|
+
attr_accessor :log
|
123
|
+
end
|
124
|
+
|
125
|
+
def log
|
126
|
+
self.class.log
|
127
|
+
end
|
128
|
+
|
129
|
+
def self.included klass
|
130
|
+
klass.extend ClassMethods
|
131
|
+
|
132
|
+
if FFWD.log_disabled?
|
133
|
+
klass.log = FakeLogger.new
|
134
|
+
else
|
135
|
+
klass.log = ClassLogger.new klass
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
data/lib/ffwd/metric.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
# $LICENSE
|
2
|
+
# Copyright 2013-2014 Spotify AB. All rights reserved.
|
3
|
+
#
|
4
|
+
# The contents of this file are licensed under the Apache License, Version 2.0
|
5
|
+
# (the "License"); you may not use this file except in compliance with the
|
6
|
+
# License. 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, WITHOUT
|
12
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
13
|
+
# License for the specific language governing permissions and limitations under
|
14
|
+
# the License.
|
15
|
+
|
16
|
+
module FFWD
|
17
|
+
# Struct used to define all fields related to a metric.
|
18
|
+
MetricStruct = Struct.new(
|
19
|
+
# The time at which the metric was collected.
|
20
|
+
:time,
|
21
|
+
# The unique key of the metric.
|
22
|
+
:key,
|
23
|
+
# A numeric value associated with the metric.
|
24
|
+
:value,
|
25
|
+
# The host from which the metric originated.
|
26
|
+
:host,
|
27
|
+
# The source metric this metric was derived from (if any).
|
28
|
+
:source,
|
29
|
+
# Tags associated to the metric.
|
30
|
+
:tags,
|
31
|
+
# Attributes (extra fields) associated to the metric.
|
32
|
+
:attributes
|
33
|
+
)
|
34
|
+
|
35
|
+
# A convenience class for each individual metric.
|
36
|
+
class Metric < MetricStruct
|
37
|
+
def self.make opts={}
|
38
|
+
new(opts[:time], opts[:key], opts[:value], opts[:host], opts[:source],
|
39
|
+
opts[:tags], opts[:attributes])
|
40
|
+
end
|
41
|
+
|
42
|
+
# Convert metric to a sparse hash.
|
43
|
+
def to_h
|
44
|
+
d = {}
|
45
|
+
d[:time] = time.to_i if time
|
46
|
+
d[:key] = key if key
|
47
|
+
d[:value] = value if value
|
48
|
+
d[:host] = host if host
|
49
|
+
d[:source] = source if source
|
50
|
+
d[:tags] = tags.to_a if tags
|
51
|
+
d[:attributes] = attributes if attributes
|
52
|
+
d
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# $LICENSE
|
2
|
+
# Copyright 2013-2014 Spotify AB. All rights reserved.
|
3
|
+
#
|
4
|
+
# The contents of this file are licensed under the Apache License, Version 2.0
|
5
|
+
# (the "License"); you may not use this file except in compliance with the
|
6
|
+
# License. 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, WITHOUT
|
12
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
13
|
+
# License for the specific language governing permissions and limitations under
|
14
|
+
# the License.
|
15
|
+
|
16
|
+
require_relative 'utils'
|
17
|
+
require_relative 'metric'
|
18
|
+
|
19
|
+
module FFWD
|
20
|
+
# Used to emit metrics to an 'output' channel
|
21
|
+
#
|
22
|
+
# Can take two parts of a configuration 'base' and 'opts' to decide which
|
23
|
+
# metadata emitted metrics should be decorated with.
|
24
|
+
class MetricEmitter
|
25
|
+
def self.build output, base, opts
|
26
|
+
host = opts[:host] || base[:host] || FFWD.current_host
|
27
|
+
tags = FFWD.merge_sets base[:tags], opts[:tags]
|
28
|
+
attributes = FFWD.merge_hashes base[:attributes], opts[:attributes]
|
29
|
+
new output, host, tags, attributes
|
30
|
+
end
|
31
|
+
|
32
|
+
def initialize output, host, tags, attributes
|
33
|
+
@output = output
|
34
|
+
@host = host
|
35
|
+
@tags = tags
|
36
|
+
@attributes = attributes
|
37
|
+
end
|
38
|
+
|
39
|
+
def emit m
|
40
|
+
m[:time] ||= Time.now
|
41
|
+
m[:host] ||= @host if @host
|
42
|
+
m[:tags] = FFWD.merge_sets @tags, m[:tags]
|
43
|
+
m[:attributes] = FFWD.merge_hashes @attributes, m[:attributes]
|
44
|
+
|
45
|
+
@output.metric Metric.make(m)
|
46
|
+
rescue => e
|
47
|
+
log.error "Failed to emit metric", e
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
data/lib/ffwd/plugin.rb
ADDED
@@ -0,0 +1,149 @@
|
|
1
|
+
# $LICENSE
|
2
|
+
# Copyright 2013-2014 Spotify AB. All rights reserved.
|
3
|
+
#
|
4
|
+
# The contents of this file are licensed under the Apache License, Version 2.0
|
5
|
+
# (the "License"); you may not use this file except in compliance with the
|
6
|
+
# License. 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, WITHOUT
|
12
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
13
|
+
# License for the specific language governing permissions and limitations under
|
14
|
+
# the License.
|
15
|
+
|
16
|
+
require_relative 'logging'
|
17
|
+
|
18
|
+
module FFWD
|
19
|
+
module Plugin
|
20
|
+
class Loaded
|
21
|
+
attr_reader :source, :name
|
22
|
+
|
23
|
+
def initialize source, name, options
|
24
|
+
@source = source
|
25
|
+
@name = name
|
26
|
+
@mod = options[:mod]
|
27
|
+
@setup_input_method = load_method @mod, options[:setup_input_method_name]
|
28
|
+
@setup_output_method = load_method @mod, options[:setup_output_method_name]
|
29
|
+
@setup_tunnel_method = load_method @mod, options[:setup_tunnel_method_name]
|
30
|
+
end
|
31
|
+
|
32
|
+
def capabilities
|
33
|
+
capabilities = []
|
34
|
+
|
35
|
+
if not @setup_input_method.nil?
|
36
|
+
capabilities << "input"
|
37
|
+
end
|
38
|
+
|
39
|
+
if not @setup_output_method.nil?
|
40
|
+
capabilities << "output"
|
41
|
+
end
|
42
|
+
|
43
|
+
if not @setup_tunnel_method.nil?
|
44
|
+
capabilities << "tunnel"
|
45
|
+
end
|
46
|
+
|
47
|
+
return capabilities
|
48
|
+
end
|
49
|
+
|
50
|
+
def can?(kind)
|
51
|
+
not get(kind).nil?
|
52
|
+
end
|
53
|
+
|
54
|
+
def get(kind)
|
55
|
+
return @setup_input_method if kind == :input
|
56
|
+
return @setup_output_method if kind == :output
|
57
|
+
return @setup_tunnel_method if kind == :tunnel
|
58
|
+
return nil
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
def load_method mod, method_name
|
64
|
+
return nil unless mod.respond_to? method_name
|
65
|
+
return mod.method method_name
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
class Setup
|
70
|
+
attr_reader :name, :config
|
71
|
+
|
72
|
+
def initialize name, setup, config
|
73
|
+
@name = name
|
74
|
+
@setup = setup
|
75
|
+
@config = config
|
76
|
+
end
|
77
|
+
|
78
|
+
def setup *args
|
79
|
+
@setup.call @config, *args
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def self.discovered
|
84
|
+
@@discovered ||= {}
|
85
|
+
end
|
86
|
+
|
87
|
+
def self.loaded
|
88
|
+
@@loaded ||= {}
|
89
|
+
end
|
90
|
+
|
91
|
+
module ClassMethods
|
92
|
+
def register_plugin(name, opts={})
|
93
|
+
options = {:mod => self}
|
94
|
+
|
95
|
+
options[:setup_input_method_name] = (opts[:setup_input_method] || :setup_input)
|
96
|
+
options[:setup_output_method_name] = (opts[:setup_output_method] || :setup_output)
|
97
|
+
options[:setup_tunnel_method_name] = (opts[:setup_tunnel_method] || :setup_tunnel)
|
98
|
+
|
99
|
+
FFWD::Plugin.discovered[name] = options
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def self.included mod
|
104
|
+
mod.extend ClassMethods
|
105
|
+
end
|
106
|
+
|
107
|
+
def self.category
|
108
|
+
'plugin'
|
109
|
+
end
|
110
|
+
|
111
|
+
def self.load_discovered source
|
112
|
+
FFWD::Plugin.discovered.each do |name, options|
|
113
|
+
FFWD::Plugin.loaded[name] = Loaded.new source, name, options
|
114
|
+
end
|
115
|
+
|
116
|
+
FFWD::Plugin.discovered.clear
|
117
|
+
end
|
118
|
+
|
119
|
+
def self.load_plugins log, kind_name, config, kind
|
120
|
+
result = []
|
121
|
+
|
122
|
+
if config.nil?
|
123
|
+
return result
|
124
|
+
end
|
125
|
+
|
126
|
+
config.each_with_index do |plugin_config, index|
|
127
|
+
d = "#{kind_name} plugin ##{index}"
|
128
|
+
|
129
|
+
if (name = plugin_config[:type]).nil?
|
130
|
+
log.error "#{d}: Missing :type attribute for '#{kind_name}'"
|
131
|
+
end
|
132
|
+
|
133
|
+
if (plugin = FFWD::Plugin.loaded[name]).nil?
|
134
|
+
log.error "#{d}: Not an available plugin '#{name}'"
|
135
|
+
next
|
136
|
+
end
|
137
|
+
|
138
|
+
unless plugin.can?(kind)
|
139
|
+
log.error "#{d}: Not an #{kind_name} plugin '#{name}'"
|
140
|
+
next
|
141
|
+
end
|
142
|
+
|
143
|
+
result << Setup.new(name, plugin.get(kind), plugin_config)
|
144
|
+
end
|
145
|
+
|
146
|
+
return result
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# $LICENSE
|
2
|
+
# Copyright 2013-2014 Spotify AB. All rights reserved.
|
3
|
+
#
|
4
|
+
# The contents of this file are licensed under the Apache License, Version 2.0
|
5
|
+
# (the "License"); you may not use this file except in compliance with the
|
6
|
+
# License. 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, WITHOUT
|
12
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
13
|
+
# License for the specific language governing permissions and limitations under
|
14
|
+
# the License.
|
15
|
+
|
16
|
+
require 'eventmachine'
|
17
|
+
|
18
|
+
require 'ffwd/protocol'
|
19
|
+
require 'ffwd/plugin'
|
20
|
+
require 'ffwd/logging'
|
21
|
+
|
22
|
+
require_relative 'json_line/connection'
|
23
|
+
|
24
|
+
module FFWD::Plugin::JsonLine
|
25
|
+
include FFWD::Plugin
|
26
|
+
include FFWD::Logging
|
27
|
+
|
28
|
+
register_plugin "json_line"
|
29
|
+
|
30
|
+
DEFAULT_HOST = "localhost"
|
31
|
+
DEFAULT_PORT = 19000
|
32
|
+
|
33
|
+
def self.setup_input opts, core
|
34
|
+
opts[:host] ||= DEFAULT_HOST
|
35
|
+
opts[:port] ||= DEFAULT_PORT
|
36
|
+
buffer_limit = opts["buffer_limit"] || 1000
|
37
|
+
protocol = FFWD.parse_protocol(opts[:protocol] || "tcp")
|
38
|
+
protocol.bind opts, core, log, Connection, buffer_limit
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.setup_tunnel opts, core, tunnel
|
42
|
+
opts[:port] ||= DEFAULT_PORT
|
43
|
+
buffer_limit = opts["buffer_limit"] || 1000
|
44
|
+
protocol = FFWD.parse_protocol(opts[:protocol] || "tcp")
|
45
|
+
protocol.tunnel opts, core, tunnel, log, Connection, buffer_limit
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
# $LICENSE
|
2
|
+
# Copyright 2013-2014 Spotify AB. All rights reserved.
|
3
|
+
#
|
4
|
+
# The contents of this file are licensed under the Apache License, Version 2.0
|
5
|
+
# (the "License"); you may not use this file except in compliance with the
|
6
|
+
# License. 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, WITHOUT
|
12
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
13
|
+
# License for the specific language governing permissions and limitations under
|
14
|
+
# the License.
|
15
|
+
|
16
|
+
require 'eventmachine'
|
17
|
+
|
18
|
+
require 'ffwd/logging'
|
19
|
+
require 'ffwd/connection'
|
20
|
+
|
21
|
+
module FFWD::Plugin::JsonLine
|
22
|
+
class Connection < FFWD::Connection
|
23
|
+
include FFWD::Logging
|
24
|
+
include EM::Protocols::LineText2
|
25
|
+
|
26
|
+
EVENT_FIELDS = [
|
27
|
+
["key", :key],
|
28
|
+
["value", :value],
|
29
|
+
["host", :host],
|
30
|
+
["state", :state],
|
31
|
+
["description", :description],
|
32
|
+
["ttl", :ttl],
|
33
|
+
["tags", :tags],
|
34
|
+
["attributes", :attributes],
|
35
|
+
]
|
36
|
+
|
37
|
+
METRIC_FIELDS = [
|
38
|
+
["proc", :proc],
|
39
|
+
["key", :key],
|
40
|
+
["value", :value],
|
41
|
+
["tags", :tags],
|
42
|
+
["attributes", :attributes]
|
43
|
+
]
|
44
|
+
|
45
|
+
def self.plugin_type
|
46
|
+
"json_line_in"
|
47
|
+
end
|
48
|
+
|
49
|
+
def initialize bind, core, buffer_limit
|
50
|
+
@bind = bind
|
51
|
+
@core = core
|
52
|
+
@buffer_limit = buffer_limit
|
53
|
+
end
|
54
|
+
|
55
|
+
def receive_line data
|
56
|
+
data = JSON.load(data)
|
57
|
+
|
58
|
+
unless type = data["type"]
|
59
|
+
log.error "Field 'type' missing from received line"
|
60
|
+
return
|
61
|
+
end
|
62
|
+
|
63
|
+
if type == "metric"
|
64
|
+
@core.input.metric read_metric(data)
|
65
|
+
@bind.increment :received_metric
|
66
|
+
return
|
67
|
+
end
|
68
|
+
|
69
|
+
if type == "event"
|
70
|
+
@core.input.event read_event(data)
|
71
|
+
@bind.increment :received_event
|
72
|
+
return
|
73
|
+
end
|
74
|
+
|
75
|
+
log.error "No such type: #{type}"
|
76
|
+
rescue => e
|
77
|
+
log.error "Failed to receive line", e
|
78
|
+
end
|
79
|
+
|
80
|
+
def read_tags d, source
|
81
|
+
return if (tags = d["tags"]).nil?
|
82
|
+
d[:tags] = tags.to_set
|
83
|
+
end
|
84
|
+
|
85
|
+
def read_time d, source
|
86
|
+
return if (time = d["time"]).nil?
|
87
|
+
d[:time] = Time.at time
|
88
|
+
end
|
89
|
+
|
90
|
+
def read_metric data
|
91
|
+
d = {}
|
92
|
+
|
93
|
+
read_tags d, data["tags"]
|
94
|
+
read_time d, data["time"]
|
95
|
+
|
96
|
+
METRIC_FIELDS.each do |from, to|
|
97
|
+
next if (v = data[from]).nil?
|
98
|
+
d[to] = v
|
99
|
+
end
|
100
|
+
|
101
|
+
d
|
102
|
+
end
|
103
|
+
|
104
|
+
def read_event data
|
105
|
+
d = {}
|
106
|
+
|
107
|
+
read_tags d, data["tags"]
|
108
|
+
read_time d, data["time"]
|
109
|
+
|
110
|
+
EVENT_FIELDS.each do |from, to|
|
111
|
+
next if (v = data[from]).nil?
|
112
|
+
d[to] = v
|
113
|
+
end
|
114
|
+
|
115
|
+
d
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|