ffwd 0.1.7 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/ffwd.rb +34 -10
- data/lib/ffwd/core.rb +13 -11
- data/lib/ffwd/core/emitter.rb +0 -2
- data/lib/ffwd/core/interface.rb +5 -2
- data/lib/ffwd/core/processor.rb +4 -5
- data/lib/ffwd/debug/monitor_session.rb +3 -6
- data/lib/ffwd/debug/tcp.rb +17 -12
- data/lib/ffwd/handler.rb +1 -1
- data/lib/ffwd/plugin.rb +20 -15
- data/lib/ffwd/plugin/json.rb +12 -20
- data/lib/ffwd/plugin/json/connection.rb +4 -2
- data/lib/ffwd/plugin/log.rb +17 -2
- data/lib/ffwd/plugin/log/writer.rb +4 -0
- data/lib/ffwd/plugin_channel.rb +8 -8
- data/lib/ffwd/processor.rb +11 -4
- data/lib/ffwd/processor/count.rb +16 -6
- data/lib/ffwd/processor/histogram.rb +26 -15
- data/lib/ffwd/processor/rate.rb +16 -6
- data/lib/ffwd/protocol/tcp.rb +47 -88
- data/lib/ffwd/protocol/tcp/bind.rb +22 -10
- data/lib/ffwd/protocol/tcp/connection.rb +23 -6
- data/lib/ffwd/protocol/tcp/flushing_connect.rb +42 -25
- data/lib/ffwd/protocol/tcp/plain_connect.rb +15 -3
- data/lib/ffwd/protocol/udp.rb +42 -17
- data/lib/ffwd/protocol/udp/bind.rb +21 -10
- data/lib/ffwd/protocol/udp/connect.rb +22 -9
- data/lib/ffwd/retrier.rb +4 -1
- data/lib/ffwd/schema.rb +10 -3
- data/lib/ffwd/statistics/collector.rb +31 -23
- data/lib/ffwd/test/protocol.rb +42 -0
- data/lib/ffwd/tunnel/tcp.rb +3 -1
- data/lib/ffwd/utils.rb +7 -0
- data/lib/ffwd/version.rb +1 -1
- metadata +56 -68
- data/lib/ffwd/circular_buffer.rb +0 -78
- data/lib/ffwd/statistics.rb +0 -29
- data/lib/ffwd/tunnel.rb +0 -27
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 4b630458a10baaf2b380c2fea5d264c0b5899dfb
|
4
|
+
data.tar.gz: de1dbbce8ec3bbd5a4d8acd85dc2b7f6c5ef9cfa
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1d32fad236f6af767352403f042f9cf03a5e7133a41081a0d390715467339ed579e0993b853a433dbbc5cae02c433ad44b4bcadea58228e2c68a9983e6f88219
|
7
|
+
data.tar.gz: b60bf9c734110e417fd45c9bb8282e9224780146bb2bd403b62d5a315c2ff26d061b8eaa303a266a1fd61f2ecc2dfcdc19ae99b1cf9562b8b222000191e509a0
|
data/lib/ffwd.rb
CHANGED
@@ -25,9 +25,8 @@ require_relative 'ffwd/schema'
|
|
25
25
|
require_relative 'ffwd/version'
|
26
26
|
|
27
27
|
module FFWD
|
28
|
-
DEFAULT_PLUGIN_DIRECTORIES = [
|
29
|
-
|
30
|
-
]
|
28
|
+
DEFAULT_PLUGIN_DIRECTORIES = ['./plugins' ]
|
29
|
+
DEFAULT_CONFIG_PREFIXES = ['./ffwd.d']
|
31
30
|
|
32
31
|
def self.load_yaml path
|
33
32
|
return YAML.load_file path
|
@@ -70,7 +69,7 @@ module FFWD
|
|
70
69
|
c = load_yaml entry_path
|
71
70
|
|
72
71
|
if c.nil?
|
73
|
-
log.
|
72
|
+
log.warning "Ignoring: #{entry_path} (invalid yaml)"
|
74
73
|
next
|
75
74
|
end
|
76
75
|
|
@@ -82,6 +81,7 @@ module FFWD
|
|
82
81
|
@@opts ||= {:debug => false, :config => nil, :config_dir => nil,
|
83
82
|
:list_plugins => false, :list_schemas => false,
|
84
83
|
:dump_config => false, :show_version => false,
|
84
|
+
:config_prefixes => DEFAULT_CONFIG_PREFIXES,
|
85
85
|
:config_paths => [],
|
86
86
|
:plugin_directories => DEFAULT_PLUGIN_DIRECTORIES}
|
87
87
|
end
|
@@ -95,9 +95,15 @@ module FFWD
|
|
95
95
|
end
|
96
96
|
|
97
97
|
o.on "-c", "--config <path>", "Load the specified configuration file." do |path|
|
98
|
+
puts "WARNING: Deprecated option '-c #{path}'."
|
99
|
+
puts " Use positional argument to specify configuration!"
|
98
100
|
opts[:config_paths] << path
|
99
101
|
end
|
100
102
|
|
103
|
+
o.on "-D", "--config-prefix <path>", "Scan for configuration files relative to this directory." do |path|
|
104
|
+
opts[:config_prefixes] << path
|
105
|
+
end
|
106
|
+
|
101
107
|
o.on "-d", "--config-directory <path>", "Load configuration files from the specified directory." do |path|
|
102
108
|
opts[:config_dir] = path
|
103
109
|
end
|
@@ -132,13 +138,13 @@ module FFWD
|
|
132
138
|
plugins = {}
|
133
139
|
|
134
140
|
plugins[:tunnel] = FFWD::Plugin.load_plugins(
|
135
|
-
log, "Tunnel", config[:tunnel], :tunnel)
|
141
|
+
log, "Tunnel", config[:tunnel], :input, :tunnel)
|
136
142
|
|
137
143
|
plugins[:input] = FFWD::Plugin.load_plugins(
|
138
|
-
log, "Input", config[:input], :input)
|
144
|
+
log, "Input", config[:input], :input, :bind)
|
139
145
|
|
140
146
|
plugins[:output] = FFWD::Plugin.load_plugins(
|
141
|
-
log, "Output", config[:output], :output)
|
147
|
+
log, "Output", config[:output], :output, :connect)
|
142
148
|
|
143
149
|
plugins
|
144
150
|
end
|
@@ -219,8 +225,24 @@ module FFWD
|
|
219
225
|
puts " https://github.com/spotify/ffwd"
|
220
226
|
end
|
221
227
|
|
228
|
+
def self.match_any_config_path prefixes, path
|
229
|
+
return path if File.file? path
|
230
|
+
|
231
|
+
prefixes.each do |prefix|
|
232
|
+
full = File.join prefix, path
|
233
|
+
next unless File.file? full
|
234
|
+
return full
|
235
|
+
end
|
236
|
+
|
237
|
+
return nil
|
238
|
+
end
|
239
|
+
|
222
240
|
def self.main args
|
223
|
-
parse_options
|
241
|
+
positional = parse_options(args)
|
242
|
+
|
243
|
+
positional.each do |path|
|
244
|
+
opts[:config_paths] << path
|
245
|
+
end
|
224
246
|
|
225
247
|
if opts[:show_version]
|
226
248
|
puts "ffwd version: #{FFWD::VERSION}"
|
@@ -232,7 +254,9 @@ module FFWD
|
|
232
254
|
config = {}
|
233
255
|
|
234
256
|
opts[:config_paths].each do |path|
|
235
|
-
|
257
|
+
path = match_any_config_path opts[:config_prefixes], path
|
258
|
+
|
259
|
+
unless path
|
236
260
|
puts "Configuration path does not exist: #{path}"
|
237
261
|
puts ""
|
238
262
|
puts parser.help
|
@@ -240,7 +264,7 @@ module FFWD
|
|
240
264
|
end
|
241
265
|
|
242
266
|
return 0 unless source = load_yaml(path)
|
243
|
-
|
267
|
+
puts "Loaded: #{path}"
|
244
268
|
merge_configurations config, source
|
245
269
|
end
|
246
270
|
|
data/lib/ffwd/core.rb
CHANGED
@@ -23,7 +23,6 @@ require_relative 'logging'
|
|
23
23
|
require_relative 'plugin_channel'
|
24
24
|
require_relative 'processor'
|
25
25
|
require_relative 'protocol'
|
26
|
-
require_relative 'statistics'
|
27
26
|
require_relative 'utils'
|
28
27
|
|
29
28
|
require_relative 'core/emitter'
|
@@ -31,6 +30,8 @@ require_relative 'core/interface'
|
|
31
30
|
require_relative 'core/processor'
|
32
31
|
require_relative 'core/reporter'
|
33
32
|
|
33
|
+
require_relative 'statistics/collector'
|
34
|
+
|
34
35
|
module FFWD
|
35
36
|
class Core
|
36
37
|
include FFWD::Lifecycle
|
@@ -46,8 +47,8 @@ module FFWD
|
|
46
47
|
@core_opts = opts[:core] || {}
|
47
48
|
@processors = FFWD::Processor.load_processors(opts[:processor] || {})
|
48
49
|
|
49
|
-
@output_channel = FFWD::PluginChannel.build 'output'
|
50
|
-
@input_channel = FFWD::PluginChannel.build 'input'
|
50
|
+
@output_channel = FFWD::PluginChannel.build 'core.output'
|
51
|
+
@input_channel = FFWD::PluginChannel.build 'core.input'
|
51
52
|
|
52
53
|
@system_channel = Channel.new log, "system_channel"
|
53
54
|
|
@@ -66,8 +67,8 @@ module FFWD
|
|
66
67
|
|
67
68
|
if @debug_opts
|
68
69
|
@debug = FFWD::Debug.setup @debug_opts
|
69
|
-
@debug.monitor
|
70
|
-
@debug.monitor
|
70
|
+
@debug.monitor @input_channel, FFWD::Debug::Input
|
71
|
+
@debug.monitor @output_channel, FFWD::Debug::Output
|
71
72
|
@debug.depend_on self
|
72
73
|
end
|
73
74
|
|
@@ -75,7 +76,8 @@ module FFWD
|
|
75
76
|
@statistics = nil
|
76
77
|
|
77
78
|
if config = @statistics_opts
|
78
|
-
@statistics = FFWD::Statistics.
|
79
|
+
@statistics = FFWD::Statistics::Collector.build(
|
80
|
+
@emitter, @system_channel, config)
|
79
81
|
@statistics.depend_on self
|
80
82
|
end
|
81
83
|
|
@@ -86,19 +88,19 @@ module FFWD
|
|
86
88
|
|
87
89
|
@interface.depend_on self
|
88
90
|
|
89
|
-
@input_instances = @input_plugins.map do |
|
90
|
-
|
91
|
+
@input_instances = @input_plugins.map do |factory|
|
92
|
+
factory.call @interface
|
91
93
|
end
|
92
94
|
|
93
|
-
@output_instances = @output_plugins.map do |
|
94
|
-
|
95
|
+
@output_instances = @output_plugins.map do |factory|
|
96
|
+
factory.call @interface
|
95
97
|
end
|
96
98
|
|
97
99
|
unless @statistics.nil?
|
98
100
|
reporters = [@input_channel, @output_channel, @processor]
|
99
101
|
reporters += @input_instances.select{|i| FFWD.is_reporter?(i)}
|
100
102
|
reporters += @output_instances.select{|i| FFWD.is_reporter?(i)}
|
101
|
-
@statistics.register "core", Core::Reporter.new(reporters)
|
103
|
+
@statistics.register self, "core", Core::Reporter.new(reporters)
|
102
104
|
end
|
103
105
|
|
104
106
|
# Make the core-related channels depend on core.
|
data/lib/ffwd/core/emitter.rb
CHANGED
data/lib/ffwd/core/interface.rb
CHANGED
@@ -25,8 +25,11 @@ module FFWD
|
|
25
25
|
attr_reader :tunnel_plugins, :statistics, :debug, :processors
|
26
26
|
attr_reader :tags, :attributes
|
27
27
|
|
28
|
-
def initialize(
|
29
|
-
|
28
|
+
def initialize(
|
29
|
+
input, output,
|
30
|
+
tunnel_plugins, statistics, debug,
|
31
|
+
processors, opts
|
32
|
+
)
|
30
33
|
@input = input
|
31
34
|
@output = output
|
32
35
|
@tunnel_plugins = tunnel_plugins
|
data/lib/ffwd/core/processor.rb
CHANGED
@@ -38,25 +38,24 @@ module FFWD
|
|
38
38
|
@emitter = emitter
|
39
39
|
@processors = processors
|
40
40
|
@reporters = reporters
|
41
|
-
|
42
|
-
subs = []
|
41
|
+
@subs = []
|
43
42
|
|
44
43
|
@processors.each do |name, p|
|
45
44
|
p.depend_on input
|
46
45
|
end
|
47
46
|
|
48
47
|
input.starting do
|
49
|
-
subs << input.metric_subscribe do |m|
|
48
|
+
@subs << input.metric_subscribe do |m|
|
50
49
|
process_metric m
|
51
50
|
end
|
52
51
|
|
53
|
-
subs << input.event_subscribe do |e|
|
52
|
+
@subs << input.event_subscribe do |e|
|
54
53
|
process_event e
|
55
54
|
end
|
56
55
|
end
|
57
56
|
|
58
57
|
input.stopping do
|
59
|
-
subs.each(&:unsubscribe).clear
|
58
|
+
@subs.each(&:unsubscribe).clear
|
60
59
|
end
|
61
60
|
end
|
62
61
|
|
@@ -17,10 +17,7 @@ require_relative '../lifecycle'
|
|
17
17
|
|
18
18
|
module FFWD::Debug
|
19
19
|
class MonitorSession
|
20
|
-
|
21
|
-
|
22
|
-
def initialize id, channel, type
|
23
|
-
@id = id
|
20
|
+
def initialize channel, type
|
24
21
|
@type = type
|
25
22
|
@clients = {}
|
26
23
|
|
@@ -31,7 +28,7 @@ module FFWD::Debug
|
|
31
28
|
data = @type.serialize_event event
|
32
29
|
|
33
30
|
begin
|
34
|
-
send JSON.dump(:id =>
|
31
|
+
send JSON.dump(:id => channel.id, :type => :event, :data => data)
|
35
32
|
rescue => e
|
36
33
|
log.error "Failed to serialize event", e
|
37
34
|
return
|
@@ -42,7 +39,7 @@ module FFWD::Debug
|
|
42
39
|
data = @type.serialize_metric metric
|
43
40
|
|
44
41
|
begin
|
45
|
-
send JSON.dump(:id =>
|
42
|
+
send JSON.dump(:id => channel.id, :type => :metric, :data => data)
|
46
43
|
rescue => e
|
47
44
|
log.error "Failed to serialize metric", e
|
48
45
|
return
|
data/lib/ffwd/debug/tcp.rb
CHANGED
@@ -31,14 +31,15 @@ module FFWD::Debug
|
|
31
31
|
@host = host
|
32
32
|
@port = port
|
33
33
|
@peer = "#{@host}:#{@port}"
|
34
|
+
info = "tcp://#{@peer}"
|
34
35
|
|
35
36
|
r = FFWD.retry :timeout => rebind_timeout do |attempt|
|
36
37
|
EM.start_server @host, @port, Connection, self
|
37
|
-
log.info "Bind on
|
38
|
+
log.info "Bind on #{info} (attempt #{attempt})"
|
38
39
|
end
|
39
40
|
|
40
41
|
r.error do |a, t, e|
|
41
|
-
log.
|
42
|
+
log.warning "Bind on #{info} failed, retry ##{a} in #{t}s: #{e}"
|
42
43
|
end
|
43
44
|
|
44
45
|
r.depend_on self
|
@@ -61,21 +62,25 @@ module FFWD::Debug
|
|
61
62
|
end
|
62
63
|
|
63
64
|
# Setup monitor hooks for the specified input and output channel.
|
64
|
-
def monitor
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
65
|
+
def monitor channel, type
|
66
|
+
channel.starting do
|
67
|
+
if session = @sessions[channel.id]
|
68
|
+
log.error "Session already monitored: #{channel.id}"
|
69
|
+
return
|
70
|
+
end
|
69
71
|
|
70
|
-
|
72
|
+
session = MonitorSession.new channel, type
|
71
73
|
|
72
|
-
|
73
|
-
|
74
|
-
|
74
|
+
# provide the session to any already connected clients.
|
75
|
+
@clients.each do |peer, client|
|
76
|
+
session.register peer, client
|
77
|
+
end
|
78
|
+
|
79
|
+
@sessions[channel.id] = session
|
75
80
|
end
|
76
81
|
|
77
82
|
channel.stopping do
|
78
|
-
@sessions.delete id
|
83
|
+
@sessions.delete channel.id
|
79
84
|
end
|
80
85
|
end
|
81
86
|
end
|
data/lib/ffwd/handler.rb
CHANGED
data/lib/ffwd/plugin.rb
CHANGED
@@ -28,7 +28,6 @@ module FFWD
|
|
28
28
|
@options = config[:options]
|
29
29
|
@setup_input_method = load_method @mod, config[:setup_input_method_name]
|
30
30
|
@setup_output_method = load_method @mod, config[:setup_output_method_name]
|
31
|
-
@setup_tunnel_method = load_method @mod, config[:setup_tunnel_method_name]
|
32
31
|
end
|
33
32
|
|
34
33
|
def capabilities
|
@@ -42,10 +41,6 @@ module FFWD
|
|
42
41
|
capabilities << "output"
|
43
42
|
end
|
44
43
|
|
45
|
-
if not @setup_tunnel_method.nil?
|
46
|
-
capabilities << "tunnel"
|
47
|
-
end
|
48
|
-
|
49
44
|
return capabilities
|
50
45
|
end
|
51
46
|
|
@@ -56,7 +51,6 @@ module FFWD
|
|
56
51
|
def get(kind)
|
57
52
|
return @setup_input_method if kind == :input
|
58
53
|
return @setup_output_method if kind == :output
|
59
|
-
return @setup_tunnel_method if kind == :tunnel
|
60
54
|
return nil
|
61
55
|
end
|
62
56
|
|
@@ -69,16 +63,16 @@ module FFWD
|
|
69
63
|
end
|
70
64
|
|
71
65
|
class Setup
|
72
|
-
attr_reader :
|
66
|
+
attr_reader :config, :name
|
73
67
|
|
74
|
-
def initialize
|
75
|
-
@
|
68
|
+
def initialize method, config, name
|
69
|
+
@method = method
|
76
70
|
@config = config
|
77
|
-
@
|
71
|
+
@name = name
|
78
72
|
end
|
79
73
|
|
80
|
-
def
|
81
|
-
@
|
74
|
+
def call *args
|
75
|
+
@method.call(*args)
|
82
76
|
end
|
83
77
|
end
|
84
78
|
|
@@ -100,7 +94,6 @@ module FFWD
|
|
100
94
|
|
101
95
|
config[:setup_input_method_name] = (opts[:setup_input_method] || :setup_input)
|
102
96
|
config[:setup_output_method_name] = (opts[:setup_output_method] || :setup_output)
|
103
|
-
config[:setup_tunnel_method_name] = (opts[:setup_tunnel_method] || :setup_tunnel)
|
104
97
|
|
105
98
|
FFWD::Plugin.discovered[name] = config
|
106
99
|
end
|
@@ -122,7 +115,7 @@ module FFWD
|
|
122
115
|
FFWD::Plugin.discovered.clear
|
123
116
|
end
|
124
117
|
|
125
|
-
def self.load_plugins log, kind_name, config, kind
|
118
|
+
def self.load_plugins log, kind_name, config, kind, m
|
126
119
|
result = []
|
127
120
|
|
128
121
|
return result if config.nil?
|
@@ -145,7 +138,19 @@ module FFWD
|
|
145
138
|
next
|
146
139
|
end
|
147
140
|
|
148
|
-
|
141
|
+
factory = setup.call Hash[plugin_config]
|
142
|
+
|
143
|
+
unless factory.respond_to? m
|
144
|
+
log.error "#{d}: Plugin '#{name}' does not support '#{m.to_s}'"
|
145
|
+
next
|
146
|
+
end
|
147
|
+
|
148
|
+
unless factory.respond_to? :config
|
149
|
+
log.error "#{d}: Plugin '#{name}' does not support 'config'"
|
150
|
+
next
|
151
|
+
end
|
152
|
+
|
153
|
+
result << Setup.new(factory.method(m), factory.config, name)
|
149
154
|
end
|
150
155
|
|
151
156
|
return result
|
data/lib/ffwd/plugin/json.rb
CHANGED
@@ -50,9 +50,7 @@ module FFWD::Plugin::JSON
|
|
50
50
|
])
|
51
51
|
]
|
52
52
|
|
53
|
-
class LineConnection < FFWD::Connection
|
54
|
-
include FFWD::Logging
|
55
|
-
include FFWD::Plugin::JSON::Connection
|
53
|
+
class LineConnection < FFWD::Plugin::JSON::Connection
|
56
54
|
include EM::Protocols::LineText2
|
57
55
|
|
58
56
|
def self.plugin_type
|
@@ -64,10 +62,7 @@ module FFWD::Plugin::JSON
|
|
64
62
|
end
|
65
63
|
end
|
66
64
|
|
67
|
-
class FrameConnection < FFWD::Connection
|
68
|
-
include FFWD::Logging
|
69
|
-
include FFWD::Plugin::JSON::Connection
|
70
|
-
|
65
|
+
class FrameConnection < FFWD::Plugin::JSON::Connection
|
71
66
|
def self.plugin_type
|
72
67
|
"json_frame_in"
|
73
68
|
end
|
@@ -79,13 +74,18 @@ module FFWD::Plugin::JSON
|
|
79
74
|
|
80
75
|
KINDS = {"frame" => FrameConnection, "line" => LineConnection}
|
81
76
|
|
82
|
-
def self.setup_input opts
|
83
|
-
kind = (opts[:kind] || DEFAULT_KIND).to_s
|
84
|
-
raise "No such kind: #{kind}" unless connection = KINDS[kind]
|
85
|
-
protocol = FFWD.parse_protocol opts[:protocol] || DEFAULT_PROTOCOL[kind]
|
77
|
+
def self.setup_input opts
|
86
78
|
opts[:host] ||= DEFAULT_HOST
|
87
79
|
opts[:port] ||= DEFAULT_PORT
|
88
80
|
|
81
|
+
kind = (opts[:kind] || DEFAULT_KIND).to_s
|
82
|
+
|
83
|
+
unless connection = KINDS[kind]
|
84
|
+
raise "No such protocol kind: #{kind}"
|
85
|
+
end
|
86
|
+
|
87
|
+
protocol = FFWD.parse_protocol opts[:protocol] || DEFAULT_PROTOCOL[kind]
|
88
|
+
|
89
89
|
if connection == FrameConnection and protocol != FFWD::UDP
|
90
90
|
log.warning "When using :frame kind, you should use the UDP protocol." +
|
91
91
|
" Not #{protocol.family.to_s.upcase}"
|
@@ -96,14 +96,6 @@ module FFWD::Plugin::JSON
|
|
96
96
|
"Not #{protocol.family.to_s.upcase}"
|
97
97
|
end
|
98
98
|
|
99
|
-
protocol.bind opts,
|
100
|
-
end
|
101
|
-
|
102
|
-
def self.setup_tunnel opts, core, tunnel
|
103
|
-
protocol = FFWD.parse_protocol opts[:protocol] || "tcp"
|
104
|
-
kind = (opts[:kind] || DEFAULT_KIND).to_s
|
105
|
-
raise "No such kind: #{kind}" unless connection = KINDS[kind]
|
106
|
-
opts[:port] ||= DEFAULT_PORT
|
107
|
-
protocol.tunnel opts, core, tunnel, log, connection
|
99
|
+
protocol.bind opts, log, connection
|
108
100
|
end
|
109
101
|
end
|