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
@@ -0,0 +1,40 @@
|
|
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
|
+
module FFWD
|
19
|
+
# Connections are used by input plugins in the protocol stack.
|
20
|
+
#
|
21
|
+
# The sole purpose this exists is to incorporate a datasink functionality
|
22
|
+
# in the EM::Connection.
|
23
|
+
#
|
24
|
+
# The datasink is used by tunnels to 'hook into' outgoing data.
|
25
|
+
class Connection < EM::Connection
|
26
|
+
def datasink= sink
|
27
|
+
@datasink = sink
|
28
|
+
end
|
29
|
+
|
30
|
+
# send_data indirection.
|
31
|
+
def send_data data
|
32
|
+
if @datasink
|
33
|
+
@datasink.send_data data
|
34
|
+
return
|
35
|
+
end
|
36
|
+
|
37
|
+
super data
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/lib/ffwd/core.rb
ADDED
@@ -0,0 +1,173 @@
|
|
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 'json'
|
17
|
+
require 'eventmachine'
|
18
|
+
|
19
|
+
require_relative 'channel'
|
20
|
+
require_relative 'debug'
|
21
|
+
require_relative 'lifecycle'
|
22
|
+
require_relative 'logging'
|
23
|
+
require_relative 'plugin_channel'
|
24
|
+
require_relative 'processor'
|
25
|
+
require_relative 'protocol'
|
26
|
+
require_relative 'statistics'
|
27
|
+
require_relative 'utils'
|
28
|
+
|
29
|
+
require_relative 'core/emitter'
|
30
|
+
require_relative 'core/interface'
|
31
|
+
require_relative 'core/processor'
|
32
|
+
require_relative 'core/reporter'
|
33
|
+
|
34
|
+
module FFWD
|
35
|
+
class Core
|
36
|
+
include FFWD::Lifecycle
|
37
|
+
include FFWD::Logging
|
38
|
+
|
39
|
+
def initialize plugins, opts={}
|
40
|
+
@tunnel_plugins = plugins[:tunnel] || []
|
41
|
+
@input_plugins = plugins[:input] || []
|
42
|
+
@output_plugins = plugins[:output] || []
|
43
|
+
|
44
|
+
@statistics_opts = opts[:statistics]
|
45
|
+
@debug_opts = opts[:debug]
|
46
|
+
@core_opts = opts[:core] || {}
|
47
|
+
@processors = FFWD::Processor.load_processors(opts[:processor] || {})
|
48
|
+
|
49
|
+
@output_channel = FFWD::PluginChannel.build 'output'
|
50
|
+
@input_channel = FFWD::PluginChannel.build 'input'
|
51
|
+
|
52
|
+
@system_channel = Channel.new log, "system_channel"
|
53
|
+
|
54
|
+
memory_config = (@core_opts[:memory] || {})
|
55
|
+
@memory_limit = (memory_config[:limit] || 1000).to_f.round(3)
|
56
|
+
@memory_limit95 = @memory_limit * 0.95
|
57
|
+
|
58
|
+
if @memory_limit < 0
|
59
|
+
raise "memory limit must be non-negative number"
|
60
|
+
end
|
61
|
+
|
62
|
+
@emitter = Core::Emitter.build @output_channel, @core_opts
|
63
|
+
@processor = Core::Processor.build @input_channel, @emitter, @processors
|
64
|
+
|
65
|
+
@debug = nil
|
66
|
+
|
67
|
+
if @debug_opts
|
68
|
+
@debug = FFWD::Debug.setup @debug_opts
|
69
|
+
@debug.monitor "core.input", @input_channel, FFWD::Debug::Input
|
70
|
+
@debug.monitor "core.output", @output_channel, FFWD::Debug::Output
|
71
|
+
@debug.depend_on self
|
72
|
+
end
|
73
|
+
|
74
|
+
# Configuration for statistics module.
|
75
|
+
@statistics = nil
|
76
|
+
|
77
|
+
if config = @statistics_opts
|
78
|
+
@statistics = FFWD::Statistics.setup @emitter, @system_channel, config
|
79
|
+
@statistics.depend_on self
|
80
|
+
end
|
81
|
+
|
82
|
+
@interface = Core::Interface.new(
|
83
|
+
@input_channel, @output_channel,
|
84
|
+
@tunnel_plugins, @statistics, @debug, @processors, @core_opts
|
85
|
+
)
|
86
|
+
|
87
|
+
@interface.depend_on self
|
88
|
+
|
89
|
+
@input_instances = @input_plugins.map do |plugin|
|
90
|
+
plugin.setup @interface
|
91
|
+
end
|
92
|
+
|
93
|
+
@output_instances = @output_plugins.map do |plugin|
|
94
|
+
plugin.setup @interface
|
95
|
+
end
|
96
|
+
|
97
|
+
unless @statistics.nil?
|
98
|
+
reporters = [@input_channel, @output_channel, @processor]
|
99
|
+
reporters += @input_instances.select{|i| FFWD.is_reporter?(i)}
|
100
|
+
reporters += @output_instances.select{|i| FFWD.is_reporter?(i)}
|
101
|
+
@statistics.register "core", Core::Reporter.new(reporters)
|
102
|
+
end
|
103
|
+
|
104
|
+
# Make the core-related channels depend on core.
|
105
|
+
# They will then be orchestrated with core when it's being
|
106
|
+
# started/stopped.
|
107
|
+
@input_channel.depend_on self
|
108
|
+
@output_channel.depend_on self
|
109
|
+
end
|
110
|
+
|
111
|
+
# Main entry point.
|
112
|
+
#
|
113
|
+
# Since all components are governed by the lifecycle of core, it should
|
114
|
+
# mostly be a matter of calling 'start'.
|
115
|
+
def run
|
116
|
+
# What to do when we receive a shutdown signal?
|
117
|
+
shutdown_handler = proc do
|
118
|
+
# Hack to get out of trap context and into EM land.
|
119
|
+
EM.add_timer(0) do
|
120
|
+
log.info "Shutting down"
|
121
|
+
stop
|
122
|
+
EM.stop
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
EM.run do
|
127
|
+
Signal.trap("INT", &shutdown_handler)
|
128
|
+
Signal.trap("TERM", &shutdown_handler)
|
129
|
+
|
130
|
+
start
|
131
|
+
setup_memory_monitor
|
132
|
+
end
|
133
|
+
|
134
|
+
stopping do
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
private
|
139
|
+
|
140
|
+
# Sets up a memory monitor based of :core -> :memory -> :limit.
|
141
|
+
# Will warn at least once before shutting down.
|
142
|
+
def setup_memory_monitor
|
143
|
+
if @memory_limit == 0
|
144
|
+
log.warning "WARNING!!! YOU ARE RUNNING FFWD WITHOUT A MEMORY LIMIT, THIS COULD DAMAGE YOUR SYSTEM"
|
145
|
+
log.warning "To configure it, set the (:core -> :memory -> :limit) option to a non-zero number!"
|
146
|
+
return
|
147
|
+
end
|
148
|
+
|
149
|
+
log.info "Memory limited to #{@memory_limit} MB (:core -> :memory -> :limit)"
|
150
|
+
|
151
|
+
memory_one_warning = false
|
152
|
+
|
153
|
+
@system_channel.subscribe do |system|
|
154
|
+
memory = system[:memory]
|
155
|
+
|
156
|
+
mb = (memory[:resident].to_f / 1000000).round(3)
|
157
|
+
|
158
|
+
if memory_one_warning and mb > @memory_limit
|
159
|
+
log.error "Memory limit exceeded (#{mb}/#{@memory_limit} MB): SHUTTING DOWN"
|
160
|
+
EM.stop
|
161
|
+
next
|
162
|
+
end
|
163
|
+
|
164
|
+
if mb > @memory_limit95
|
165
|
+
log.warning "Memory limit almost reached (#{mb}/#{@memory_limit} MB)"
|
166
|
+
memory_one_warning = true
|
167
|
+
else
|
168
|
+
memory_one_warning = false
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
@@ -0,0 +1,38 @@
|
|
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
|
+
require_relative '../utils'
|
18
|
+
require_relative '../metric_emitter'
|
19
|
+
require_relative '../event_emitter'
|
20
|
+
|
21
|
+
module FFWD
|
22
|
+
class Core; end
|
23
|
+
|
24
|
+
class Core::Emitter
|
25
|
+
attr_reader :event, :metric
|
26
|
+
|
27
|
+
def self.build output, opts={}
|
28
|
+
event = EventEmitter.build output, opts, opts[:event] || {}
|
29
|
+
metric = MetricEmitter.build output, opts, opts[:metric] || {}
|
30
|
+
new(event, metric)
|
31
|
+
end
|
32
|
+
|
33
|
+
def initialize event, metric
|
34
|
+
@event = event
|
35
|
+
@metric = metric
|
36
|
+
end
|
37
|
+
end
|
38
|
+
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_relative '../lifecycle'
|
17
|
+
|
18
|
+
module FFWD
|
19
|
+
class Core; end
|
20
|
+
|
21
|
+
class Core::Interface
|
22
|
+
include FFWD::Lifecycle
|
23
|
+
|
24
|
+
attr_reader :input, :output
|
25
|
+
attr_reader :tunnel_plugins, :statistics, :debug, :processors
|
26
|
+
attr_reader :tags, :attributes
|
27
|
+
|
28
|
+
def initialize(input, output, tunnel_plugins, statistics, debug,
|
29
|
+
processors, opts)
|
30
|
+
@input = input
|
31
|
+
@output = output
|
32
|
+
@tunnel_plugins = tunnel_plugins
|
33
|
+
@statistics = statistics
|
34
|
+
@debug = debug
|
35
|
+
@processors = processors
|
36
|
+
@opts = opts
|
37
|
+
@tags = opts[:tags] || []
|
38
|
+
@attributes = opts[:attributes] || {}
|
39
|
+
end
|
40
|
+
|
41
|
+
def reconnect input
|
42
|
+
self.class.new(
|
43
|
+
input, @output, @tunnel_plugins, @statistics, @debug, @processors,
|
44
|
+
@opts)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,92 @@
|
|
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 '../event_emitter'
|
17
|
+
require_relative '../lifecycle'
|
18
|
+
|
19
|
+
module FFWD
|
20
|
+
class Core; end
|
21
|
+
|
22
|
+
# Component responsible for receiving and internally route metrics and
|
23
|
+
# events.
|
24
|
+
#
|
25
|
+
# The term 'processor' is used because depending on the set of provided
|
26
|
+
# processors it might be determined that the received metric should be
|
27
|
+
# provided to one of them instead.
|
28
|
+
#
|
29
|
+
# If no processor matches, it is just passed straight through.
|
30
|
+
class Core::Processor
|
31
|
+
def self.build input, emitter, processors
|
32
|
+
processors = Hash[processors.map{|p| [p.name, p.setup(emitter)]}]
|
33
|
+
reporters = processors.select{|k, p| FFWD.is_reporter?(p)}.map{|k, p| p}
|
34
|
+
new(input, emitter, processors, reporters)
|
35
|
+
end
|
36
|
+
|
37
|
+
def initialize input, emitter, processors, reporters
|
38
|
+
@emitter = emitter
|
39
|
+
@processors = processors
|
40
|
+
@reporters = reporters
|
41
|
+
|
42
|
+
subs = []
|
43
|
+
|
44
|
+
@processors.each do |name, p|
|
45
|
+
p.depend_on input
|
46
|
+
end
|
47
|
+
|
48
|
+
input.starting do
|
49
|
+
subs << input.metric_subscribe do |m|
|
50
|
+
process_metric m
|
51
|
+
end
|
52
|
+
|
53
|
+
subs << input.event_subscribe do |e|
|
54
|
+
process_event e
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
input.stopping do
|
59
|
+
subs.each(&:unsubscribe).clear
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def report!
|
64
|
+
@reporters.each do |reporter|
|
65
|
+
reporter.report! do |d|
|
66
|
+
yield d
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
def process_metric m
|
74
|
+
m[:time] ||= Time.now
|
75
|
+
|
76
|
+
unless p = m[:proc]
|
77
|
+
return @emitter.metric.emit m
|
78
|
+
end
|
79
|
+
|
80
|
+
unless p = @processors[p]
|
81
|
+
return @emitter.metric.emit m
|
82
|
+
end
|
83
|
+
|
84
|
+
p.process m
|
85
|
+
end
|
86
|
+
|
87
|
+
def process_event e
|
88
|
+
e[:time] ||= Time.now
|
89
|
+
@emitter.event.emit e
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,32 @@
|
|
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
|
+
class Core; end
|
18
|
+
|
19
|
+
class Core::Reporter
|
20
|
+
def initialize reporters
|
21
|
+
@reporters = reporters
|
22
|
+
end
|
23
|
+
|
24
|
+
def report!
|
25
|
+
@reporters.each do |reporter|
|
26
|
+
reporter.report! do |d|
|
27
|
+
yield d
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/ffwd/debug.rb
ADDED
@@ -0,0 +1,76 @@
|
|
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 'json'
|
17
|
+
require 'eventmachine'
|
18
|
+
|
19
|
+
require_relative 'logging'
|
20
|
+
require_relative 'event'
|
21
|
+
require_relative 'metric'
|
22
|
+
require_relative 'retrier'
|
23
|
+
require_relative 'lifecycle'
|
24
|
+
|
25
|
+
require_relative 'debug/tcp'
|
26
|
+
|
27
|
+
module FFWD::Debug
|
28
|
+
module Input
|
29
|
+
def self.serialize_event event
|
30
|
+
event = Hash[event]
|
31
|
+
|
32
|
+
if tags = event[:tags]
|
33
|
+
event[:tags] = tags.to_a
|
34
|
+
end
|
35
|
+
|
36
|
+
event
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.serialize_metric metric
|
40
|
+
metric = Hash[metric]
|
41
|
+
|
42
|
+
if tags = metric[:tags]
|
43
|
+
metric[:tags] = tags.to_a
|
44
|
+
end
|
45
|
+
|
46
|
+
metric
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
module Output
|
51
|
+
def self.serialize_event event
|
52
|
+
event.to_h
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.serialize_metric metric
|
56
|
+
metric.to_h
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
DEFAULT_REBIND_TIMEOUT = 10
|
61
|
+
DEFAULT_HOST = "localhost"
|
62
|
+
DEFAULT_PORT = 19001
|
63
|
+
|
64
|
+
def self.setup opts={}
|
65
|
+
host = opts[:host] || DEFAULT_HOST
|
66
|
+
port = opts[:port] || DEFAULT_PORT
|
67
|
+
rebind_timeout = opts[:rebind_timeout] || DEFAULT_REBIND_TIMEOUT
|
68
|
+
proto = FFWD.parse_protocol(opts[:protocol] || "tcp")
|
69
|
+
|
70
|
+
if proto == FFWD::TCP
|
71
|
+
return TCP.new host, port, rebind_timeout
|
72
|
+
end
|
73
|
+
|
74
|
+
throw Exception.new("Unsupported protocol '#{proto}'")
|
75
|
+
end
|
76
|
+
end
|