ffwd 0.1.7 → 0.2.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/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
@@ -13,19 +13,35 @@
|
|
13
13
|
# License for the specific language governing permissions and limitations under
|
14
14
|
# the License.
|
15
15
|
|
16
|
+
require_relative '../../utils'
|
17
|
+
|
16
18
|
module FFWD::TCP
|
17
19
|
class Connection
|
18
20
|
INITIAL_TIMEOUT = 2
|
19
21
|
|
22
|
+
# default flush period, if non-zero will cause the connection to be buffered.
|
23
|
+
DEFAULT_FLUSH_PERIOD = 10
|
24
|
+
# default amount of bytes that the outbound connection will allow in its
|
25
|
+
# application-level buffer.
|
26
|
+
DEFAULT_TCP_OUTBOUND_LIMIT = 2 ** 20
|
27
|
+
|
20
28
|
attr_reader :log, :peer, :reporter_meta
|
21
29
|
|
22
|
-
def
|
30
|
+
def self.prepare opts
|
31
|
+
opts[:flush_period] ||= DEFAULT_FLUSH_PERIOD
|
32
|
+
opts[:tcp_outbound_limit] ||= DEFAULT_TCP_OUTBOUND_LIMIT
|
33
|
+
opts[:ignored] = (opts[:ignored] || []).map{|v| Utils.check_ignored v}
|
34
|
+
opts
|
35
|
+
end
|
36
|
+
|
37
|
+
def initialize log, host, port, handler, config
|
23
38
|
@log = log
|
24
39
|
@host = host
|
25
40
|
@port = port
|
26
41
|
@handler = handler
|
27
|
-
@
|
28
|
-
|
42
|
+
@config = config
|
43
|
+
|
44
|
+
@tcp_outbound_limit = config[:tcp_outbound_limit]
|
29
45
|
|
30
46
|
@peer = "#{host}:#{port}"
|
31
47
|
@closing = false
|
@@ -39,8 +55,9 @@ module FFWD::TCP
|
|
39
55
|
|
40
56
|
# Start attempting to connect.
|
41
57
|
def connect
|
42
|
-
|
43
|
-
|
58
|
+
@c = EM.connect @host, @port, @handler, self, @config
|
59
|
+
log.info "Connect to tcp://#{@host}:#{@port}"
|
60
|
+
log.info " config: #{@config.inspect}"
|
44
61
|
end
|
45
62
|
|
46
63
|
# Explicitly disconnect and discard any reconnect attempts..
|
@@ -101,7 +118,7 @@ module FFWD::TCP
|
|
101
118
|
|
102
119
|
# Check if a connection is writable or not.
|
103
120
|
def writable?
|
104
|
-
not @c.nil? and @open and @c.get_outbound_data_size < @
|
121
|
+
not @c.nil? and @open and @c.get_outbound_data_size < @tcp_outbound_limit
|
105
122
|
end
|
106
123
|
end
|
107
124
|
end
|
@@ -21,6 +21,14 @@ module FFWD::TCP
|
|
21
21
|
class FlushingConnect
|
22
22
|
include FFWD::Reporter
|
23
23
|
|
24
|
+
# percent of maximum events/metrics which will cause a flush.
|
25
|
+
DEFAULT_FORCED_FLUSH_FACTOR = 0.8
|
26
|
+
# defaults for buffered connections.
|
27
|
+
# maximum amount of events to buffer up.
|
28
|
+
DEFAULT_EVENT_LIMIT = 1000
|
29
|
+
# maximum amount of metrics to buffer up.
|
30
|
+
DEFAULT_METRIC_LIMIT = 10000
|
31
|
+
|
24
32
|
setup_reporter :keys => [
|
25
33
|
:dropped_events, :dropped_metrics,
|
26
34
|
:sent_events, :sent_metrics,
|
@@ -34,49 +42,55 @@ module FFWD::TCP
|
|
34
42
|
@c.reporter_meta
|
35
43
|
end
|
36
44
|
|
37
|
-
def
|
38
|
-
|
39
|
-
|
40
|
-
|
45
|
+
def self.prepare opts
|
46
|
+
opts[:forced_flush_factor] ||= DEFAULT_FORCED_FLUSH_FACTOR
|
47
|
+
opts[:event_limit] ||= DEFAULT_EVENT_LIMIT
|
48
|
+
opts[:metric_limit] ||= DEFAULT_METRIC_LIMIT
|
49
|
+
opts
|
50
|
+
end
|
51
|
+
|
52
|
+
def initialize(core, log, connection, config)
|
41
53
|
@log = log
|
42
54
|
@c = connection
|
43
55
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
56
|
+
flush_period = config[:flush_period]
|
57
|
+
ignored = config[:ignored]
|
58
|
+
forced_flush_factor = config[:forced_flush_factor]
|
59
|
+
event_limit = config[:event_limit]
|
60
|
+
metric_limit = config[:metric_limit]
|
49
61
|
|
50
62
|
@event_buffer = []
|
51
63
|
@metric_buffer = []
|
52
64
|
@timer = nil
|
53
|
-
|
54
|
-
subs = []
|
65
|
+
@subs = []
|
55
66
|
|
56
67
|
core.starting do
|
57
|
-
|
58
|
-
@timer = EM::PeriodicTimer.new(@flush_period){flush!}
|
68
|
+
@c.connect
|
59
69
|
|
60
|
-
|
61
|
-
@event_buffer, @event_limit, @event_flush_limit, :dropped_events)
|
62
|
-
metric_consumer = setup_consumer(
|
63
|
-
@metric_buffer, @metric_limit, @metric_flush_limit, :dropped_metrics)
|
70
|
+
@timer = EM::PeriodicTimer.new(flush_period){flush!}
|
64
71
|
|
65
|
-
|
66
|
-
|
72
|
+
unless ignored.include? :events
|
73
|
+
event_consumer = setup_consumer(
|
74
|
+
@event_buffer, forced_flush_factor, event_limit, :dropped_events)
|
75
|
+
@subs << core.output.event_subscribe(&event_consumer)
|
76
|
+
end
|
67
77
|
|
68
|
-
|
78
|
+
unless ignored.include? :metrics
|
79
|
+
metric_consumer = setup_consumer(
|
80
|
+
@metric_buffer, forced_flush_factor, metric_limit, :dropped_metrics)
|
81
|
+
@subs << core.output.metric_subscribe(&metric_consumer)
|
82
|
+
end
|
69
83
|
end
|
70
84
|
|
71
85
|
core.stopping do
|
72
|
-
|
86
|
+
@c.disconnect
|
73
87
|
|
74
88
|
if @timer
|
75
89
|
@timer.cancel
|
76
90
|
@timer = nil
|
77
91
|
end
|
78
92
|
|
79
|
-
@
|
93
|
+
@subs.each(&:unsubscribe).clear
|
80
94
|
end
|
81
95
|
end
|
82
96
|
|
@@ -116,16 +130,19 @@ module FFWD::TCP
|
|
116
130
|
|
117
131
|
private
|
118
132
|
|
119
|
-
def setup_consumer buffer,
|
133
|
+
def setup_consumer buffer, drop, flush, statistics_key
|
134
|
+
drop_limit = drop
|
135
|
+
forced_flush_limit = drop * flush
|
136
|
+
|
120
137
|
proc do |e|
|
121
|
-
if buffer.size >=
|
138
|
+
if buffer.size >= drop_limit
|
122
139
|
increment statistics_key, 1
|
123
140
|
next
|
124
141
|
end
|
125
142
|
|
126
143
|
buffer << e
|
127
144
|
|
128
|
-
if buffer.size >=
|
145
|
+
if buffer.size >= forced_flush_limit
|
129
146
|
increment :forced_flush, 1
|
130
147
|
flush!
|
131
148
|
end
|
@@ -19,6 +19,10 @@ module FFWD::TCP
|
|
19
19
|
class PlainConnect
|
20
20
|
include FFWD::Reporter
|
21
21
|
|
22
|
+
def self.prepare opts
|
23
|
+
opts
|
24
|
+
end
|
25
|
+
|
22
26
|
setup_reporter :keys => [
|
23
27
|
:dropped_events, :dropped_metrics,
|
24
28
|
:sent_events, :sent_metrics,
|
@@ -33,16 +37,24 @@ module FFWD::TCP
|
|
33
37
|
|
34
38
|
INITIAL_TIMEOUT = 2
|
35
39
|
|
36
|
-
def initialize core, log, connection
|
40
|
+
def initialize core, log, connection, config
|
37
41
|
@log = log
|
38
42
|
@c = connection
|
39
43
|
|
44
|
+
ignored = config[:ignored]
|
45
|
+
|
40
46
|
subs = []
|
41
47
|
|
42
48
|
core.starting do
|
43
49
|
@c.connect
|
44
|
-
|
45
|
-
|
50
|
+
|
51
|
+
unless ignored.include? :events
|
52
|
+
subs << core.output.event_subscribe{|e| handle_event e}
|
53
|
+
end
|
54
|
+
|
55
|
+
unless ignored.include? :metrics
|
56
|
+
subs << core.output.metric_subscribe{|e| handle_metric e}
|
57
|
+
end
|
46
58
|
end
|
47
59
|
|
48
60
|
core.stopping do
|
data/lib/ffwd/protocol/udp.rb
CHANGED
@@ -13,36 +13,61 @@
|
|
13
13
|
# License for the specific language governing permissions and limitations under
|
14
14
|
# the License.
|
15
15
|
|
16
|
-
|
16
|
+
require_relative '../utils'
|
17
|
+
require_relative '../tunnel/udp'
|
17
18
|
|
18
19
|
require_relative 'udp/connect'
|
19
20
|
require_relative 'udp/bind'
|
20
21
|
|
21
|
-
require_relative '../tunnel'
|
22
|
-
|
23
22
|
module FFWD::UDP
|
24
23
|
def self.family
|
25
24
|
:udp
|
26
25
|
end
|
27
26
|
|
28
|
-
|
27
|
+
class SetupOutput
|
28
|
+
attr_reader :config
|
29
|
+
|
30
|
+
def initialize config, log, handler
|
31
|
+
@config = config
|
32
|
+
@log = log
|
33
|
+
@handler = handler
|
34
|
+
@config = Connect.prepare Hash[@config]
|
35
|
+
end
|
36
|
+
|
37
|
+
def connect core
|
38
|
+
raise "Missing required key :host" if (host = @config[:host]).nil?
|
39
|
+
raise "Missing required key :port" if (port = @config[:port]).nil?
|
40
|
+
Connect.new core, @log, host, port, @handler, @config
|
41
|
+
end
|
42
|
+
end
|
29
43
|
|
30
|
-
def self.connect
|
31
|
-
|
32
|
-
raise "Missing required key :port" if (port = opts[:port]).nil?
|
33
|
-
Connect.new core, log, host, port, handler
|
44
|
+
def self.connect config, log, handler
|
45
|
+
SetupOutput.new config, log, handler
|
34
46
|
end
|
35
47
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
48
|
+
class SetupInput
|
49
|
+
attr_reader :config
|
50
|
+
|
51
|
+
def initialize config, log, connection
|
52
|
+
@config = config
|
53
|
+
@log = log
|
54
|
+
@connection = connection
|
55
|
+
end
|
56
|
+
|
57
|
+
def bind core
|
58
|
+
raise "Missing required key :host" if (host = @config[:host]).nil?
|
59
|
+
raise "Missing required key :port" if (port = @config[:port]).nil?
|
60
|
+
@config = Bind.prepare Hash[@config]
|
61
|
+
Bind.new core, @log, host, port, @connection, @config
|
62
|
+
end
|
63
|
+
|
64
|
+
def tunnel core, plugin
|
65
|
+
raise "Missing required key :port" if (port = @config[:port]).nil?
|
66
|
+
FFWD::Tunnel::UDP.new port, core, plugin, @log, @connection, @config
|
67
|
+
end
|
41
68
|
end
|
42
69
|
|
43
|
-
def self.
|
44
|
-
|
45
|
-
FFWD.tunnel self.family, port, core, plugin, log, connection, args
|
70
|
+
def self.bind config, log, connection
|
71
|
+
SetupInput.new config, log, connection
|
46
72
|
end
|
47
73
|
end
|
48
|
-
|
@@ -22,42 +22,53 @@ module FFWD::UDP
|
|
22
22
|
class Bind
|
23
23
|
include FFWD::Reporter
|
24
24
|
|
25
|
+
DEFAULT_REBIND_TIMEOUT = 10
|
26
|
+
|
27
|
+
def self.prepare opts
|
28
|
+
opts[:rebind_timeout] ||= DEFAULT_REBIND_TIMEOUT
|
29
|
+
opts
|
30
|
+
end
|
31
|
+
|
25
32
|
setup_reporter :keys => [
|
26
33
|
:received_events, :received_metrics,
|
27
34
|
:failed_events, :failed_metrics
|
28
35
|
]
|
29
36
|
|
30
|
-
attr_reader :reporter_meta
|
37
|
+
attr_reader :reporter_meta, :log, :config
|
31
38
|
|
32
|
-
def initialize core, log, host, port, connection,
|
39
|
+
def initialize core, log, host, port, connection, config
|
40
|
+
@log = log
|
33
41
|
@peer = "#{host}:#{port}"
|
34
42
|
@reporter_meta = {
|
35
43
|
:type => connection.plugin_type,
|
36
44
|
:listen => @peer, :family => 'udp'
|
37
45
|
}
|
38
46
|
|
39
|
-
|
47
|
+
rebind_timeout = config[:rebind_timeout]
|
48
|
+
|
49
|
+
@socket = nil
|
40
50
|
|
41
51
|
info = "udp://#{@peer}"
|
42
52
|
|
43
53
|
r = FFWD.retry :timeout => rebind_timeout do |a|
|
44
|
-
@
|
54
|
+
@socket = EM.open_datagram_socket host, port, connection, self, core, config
|
45
55
|
log.info "Bind on #{info} (attempt #{a})"
|
56
|
+
log.info " config: #{config.inspect}"
|
46
57
|
end
|
47
58
|
|
48
59
|
r.error do |a, t, e|
|
49
|
-
log.
|
60
|
+
log.warning "Bind on #{info} failed, retry ##{a} in #{t}s: #{e}"
|
50
61
|
end
|
51
62
|
|
52
63
|
r.depend_on core
|
53
64
|
|
54
65
|
core.stopping do
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
@sig.unbind
|
59
|
-
@sig = nil
|
66
|
+
if @socket
|
67
|
+
@socket.unbind
|
68
|
+
@socket = nil
|
60
69
|
end
|
70
|
+
|
71
|
+
log.info "Unbound #{info}"
|
61
72
|
end
|
62
73
|
end
|
63
74
|
end
|
@@ -22,19 +22,26 @@ module FFWD::UDP
|
|
22
22
|
|
23
23
|
RESOLVE_TIMEOUT = 10
|
24
24
|
|
25
|
-
|
25
|
+
def self.prepare config
|
26
|
+
config[:ignored] = (config[:ignored] || []).map{|v| Utils.check_ignored v}
|
27
|
+
config
|
28
|
+
end
|
29
|
+
|
30
|
+
attr_reader :reporter_meta, :log, :config
|
26
31
|
|
27
32
|
setup_reporter :keys => [
|
28
33
|
:dropped_events, :dropped_metrics,
|
29
34
|
:sent_events, :sent_metrics
|
30
35
|
]
|
31
36
|
|
32
|
-
def initialize core, log, host, port, handler
|
37
|
+
def initialize core, log, host, port, handler, config
|
33
38
|
@log = log
|
34
39
|
@host = host
|
35
40
|
@port = port
|
36
41
|
@handler = handler
|
37
42
|
|
43
|
+
ignored = config[:ignored]
|
44
|
+
|
38
45
|
@bind_host = "0.0.0.0"
|
39
46
|
@host_ip = nil
|
40
47
|
@c = nil
|
@@ -45,7 +52,7 @@ module FFWD::UDP
|
|
45
52
|
|
46
53
|
info = "udp://#{@peer}"
|
47
54
|
|
48
|
-
subs = []
|
55
|
+
@subs = []
|
49
56
|
|
50
57
|
r = FFWD.retry :timeout => RESOLVE_TIMEOUT do |a|
|
51
58
|
unless @host_ip
|
@@ -53,16 +60,22 @@ module FFWD::UDP
|
|
53
60
|
raise "Could not resolve: #{@host}" if @host_ip.nil?
|
54
61
|
end
|
55
62
|
|
56
|
-
@c = EM.open_datagram_socket
|
63
|
+
@c = EM.open_datagram_socket @bind_host, nil, @handler, self, config
|
57
64
|
|
58
|
-
|
65
|
+
unless ignored.include? :events
|
66
|
+
@subs << core.output.event_subscribe{|e| handle_event e}
|
67
|
+
end
|
68
|
+
|
69
|
+
unless ignored.include? :metrics
|
70
|
+
@subs << core.output.metric_subscribe{|m| handle_metric m}
|
71
|
+
end
|
59
72
|
|
60
|
-
|
61
|
-
|
73
|
+
log.info "Connect to #{info} (attempt #{a})"
|
74
|
+
log.info " config: #{config.inspect}"
|
62
75
|
end
|
63
76
|
|
64
77
|
r.error do |a, t, e|
|
65
|
-
log.
|
78
|
+
log.warning "Connect to #{info} failed, retry ##{a} in #{t}s: #{e}"
|
66
79
|
end
|
67
80
|
|
68
81
|
r.depend_on core
|
@@ -73,7 +86,7 @@ module FFWD::UDP
|
|
73
86
|
@c = nil
|
74
87
|
end
|
75
88
|
|
76
|
-
subs.each(&:unsubscribe).clear
|
89
|
+
@subs.each(&:unsubscribe).clear
|
77
90
|
end
|
78
91
|
end
|
79
92
|
|
data/lib/ffwd/retrier.rb
CHANGED
@@ -22,10 +22,13 @@ module FFWD
|
|
22
22
|
class Retrier
|
23
23
|
include FFWD::Lifecycle
|
24
24
|
|
25
|
+
MAX_FACTOR = 7
|
26
|
+
|
25
27
|
def initialize timeout, &block
|
26
28
|
@block = block
|
27
29
|
@timer = nil
|
28
30
|
@timeout = timeout
|
31
|
+
@max_timeout = timeout * 2**MAX_FACTOR
|
29
32
|
@current_timeout = @timeout
|
30
33
|
@attempt = 0
|
31
34
|
@error_callbacks = []
|
@@ -56,7 +59,7 @@ module FFWD
|
|
56
59
|
end
|
57
60
|
|
58
61
|
@timer = EM::Timer.new(@current_timeout) do
|
59
|
-
@current_timeout *= 2
|
62
|
+
@current_timeout *= 2 unless @current_timeout >= @max_timeout
|
60
63
|
@timer = nil
|
61
64
|
try_block
|
62
65
|
end
|