ffwd 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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,28 @@
|
|
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 'protocol/udp'
|
17
|
+
require_relative 'protocol/tcp'
|
18
|
+
|
19
|
+
module FFWD
|
20
|
+
def self.parse_protocol(original)
|
21
|
+
string = original.downcase
|
22
|
+
|
23
|
+
return UDP if string == "udp"
|
24
|
+
return TCP if string == "tcp"
|
25
|
+
|
26
|
+
throw "Unknown protocol '#{original}'"
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,126 @@
|
|
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_relative '../tunnel'
|
19
|
+
|
20
|
+
require_relative 'tcp/bind'
|
21
|
+
require_relative 'tcp/plain_connect'
|
22
|
+
require_relative 'tcp/flushing_connect'
|
23
|
+
require_relative 'tcp/connection'
|
24
|
+
|
25
|
+
module FFWD::TCP
|
26
|
+
def self.family
|
27
|
+
:tcp
|
28
|
+
end
|
29
|
+
|
30
|
+
# default amount of bytes that the outbound connection will allow in its
|
31
|
+
# application-level buffer.
|
32
|
+
DEFAULT_OUTBOUND_LIMIT = 2 ** 20
|
33
|
+
# default flush period, if non-zero will cause the connection to be buffered.
|
34
|
+
DEFAULT_FLUSH_PERIOD = 10
|
35
|
+
# defaults for buffered connections.
|
36
|
+
# maximum amount of events to buffer up.
|
37
|
+
DEFAULT_EVENT_LIMIT = 1000
|
38
|
+
# maximum amount of metrics to buffer up.
|
39
|
+
DEFAULT_METRIC_LIMIT = 10000
|
40
|
+
# percent of maximum events/metrics which will cause a flush.
|
41
|
+
DEFAULT_FLUSH_LIMIT = 0.8
|
42
|
+
# Default initial timeout when binding fails.
|
43
|
+
DEFAULT_REBIND_TIMEOUT = 10
|
44
|
+
|
45
|
+
# Establish an outbound tcp connection.
|
46
|
+
#
|
47
|
+
# opts - Option hash.
|
48
|
+
# Expects the following keys.
|
49
|
+
# :host - The host to connect to.
|
50
|
+
# :port - The port to connect to.
|
51
|
+
# :outbound_limit - The amount of bytes that are allowed to be pending in
|
52
|
+
# the application level buffer for the connection to be considered
|
53
|
+
# 'writable'.
|
54
|
+
# :flush_period - The period in which outgoing data is buffered. If this
|
55
|
+
# is 0 no buffering will occur.
|
56
|
+
# Reads the following keys if the connection is buffered.
|
57
|
+
# :event_limit - The maximum amount of events the connection is allowed
|
58
|
+
# to buffer up.
|
59
|
+
# :metric_limimt - The maximum amount of metrics the connection is
|
60
|
+
# allowed to buffer up.
|
61
|
+
# :flush_limit - A percentage (0.0 - 1.0) indicating 'the percentage of
|
62
|
+
# events/metrics' that is required for a flush to be forced.
|
63
|
+
# If this percentage is reached, the connection will attempt to forcibly
|
64
|
+
# flush all buffered events and metrics prior to the end of the flushing
|
65
|
+
# period.
|
66
|
+
# core - The core interface associated with this connection.
|
67
|
+
# log - The logger to use for this connection.
|
68
|
+
# handler - An implementation of FFWD::Handler containing the connection
|
69
|
+
# logic.
|
70
|
+
# args - Arguments passed to the handler when a new instance is created.
|
71
|
+
def self.connect opts, core, log, handler, *args
|
72
|
+
raise "Missing required option :host" if (host = opts[:host]).nil?
|
73
|
+
raise "Missing required option :port" if (port = opts[:port]).nil?
|
74
|
+
|
75
|
+
outbound_limit = opts[:outbound_limit] || DEFAULT_OUTBOUND_LIMIT
|
76
|
+
flush_period = opts[:flush_period] || DEFAULT_FLUSH_PERIOD
|
77
|
+
|
78
|
+
connection = Connection.new log, host, port, handler, args, outbound_limit
|
79
|
+
|
80
|
+
if flush_period == 0
|
81
|
+
PlainConnect.new core, log, connection
|
82
|
+
else
|
83
|
+
event_limit = opts[:event_limit] || DEFAULT_EVENT_LIMIT
|
84
|
+
metric_limit = opts[:metric_limit] || DEFAULT_METRIC_LIMIT
|
85
|
+
flush_limit = opts[:flush_limit] || DEFAULT_FLUSH_LIMIT
|
86
|
+
|
87
|
+
FlushingConnect.new(
|
88
|
+
core, log, connection,
|
89
|
+
flush_period, event_limit, metric_limit, flush_limit
|
90
|
+
)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
# Bind and listen for a TCP connection.
|
95
|
+
#
|
96
|
+
# opts - Option hash.
|
97
|
+
# :host - The host to bind to.
|
98
|
+
# :port - The port to bind to.
|
99
|
+
# :rebind_timeout - The initial timeout to use when rebinding the
|
100
|
+
# connection.
|
101
|
+
# core - The core interface associated with this connection.
|
102
|
+
# log - The logger to use for this connection.
|
103
|
+
# connection - An implementation of FFWD::Connection containing the
|
104
|
+
# connection logic.
|
105
|
+
# args - Arguments passed to the connection when a new instance is created.
|
106
|
+
def self.bind opts, core, log, connection, *args
|
107
|
+
raise "Missing required option :host" if (host = opts[:host]).nil?
|
108
|
+
raise "Missing required option :port" if (port = opts[:port]).nil?
|
109
|
+
rebind_timeout = opts[:rebind_timeout] || DEFAULT_REBIND_TIMEOUT
|
110
|
+
Bind.new core, log, host, port, connection, args, rebind_timeout
|
111
|
+
end
|
112
|
+
|
113
|
+
# Set up a TCP tunnel.
|
114
|
+
#
|
115
|
+
# opts - Option hash.
|
116
|
+
# :port - The port to bind to on the remote side.
|
117
|
+
# core - The core interface associated with this connection.
|
118
|
+
# log - The logger to use for this connection.
|
119
|
+
# connection - An implementation of FFWD::Connection containing the
|
120
|
+
# connection logic.
|
121
|
+
# args - Arguments passed to the connection when a new instance is created.
|
122
|
+
def self.tunnel opts, core, plugin, log, connection, *args
|
123
|
+
raise "Missing required option :port" if (port = opts[:port]).nil?
|
124
|
+
FFWD.tunnel self.family, port, core, plugin, log, connection, args
|
125
|
+
end
|
126
|
+
end
|
@@ -0,0 +1,64 @@
|
|
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_relative '../../reporter'
|
19
|
+
require_relative '../../retrier'
|
20
|
+
|
21
|
+
module FFWD::TCP
|
22
|
+
class Bind
|
23
|
+
include FFWD::Reporter
|
24
|
+
|
25
|
+
setup_reporter :keys => [
|
26
|
+
:received_events, :received_metrics,
|
27
|
+
:failed_events, :failed_metrics
|
28
|
+
]
|
29
|
+
|
30
|
+
attr_reader :reporter_meta
|
31
|
+
|
32
|
+
def initialize core, log, host, port, connection, args, rebind_timeout
|
33
|
+
@peer = "#{host}:#{port}"
|
34
|
+
@reporter_meta = {
|
35
|
+
:type => connection.plugin_type,
|
36
|
+
:listen => @peer, :family => 'tcp'
|
37
|
+
}
|
38
|
+
|
39
|
+
@sig = nil
|
40
|
+
|
41
|
+
info = "tcp://#{@peer}"
|
42
|
+
|
43
|
+
r = FFWD.retry :timeout => rebind_timeout do |a|
|
44
|
+
@sig = EM.start_server host, port, connection, self, core, *args
|
45
|
+
log.info "Bind on #{info} (attempt #{a})"
|
46
|
+
end
|
47
|
+
|
48
|
+
r.error do |a, t, e|
|
49
|
+
log.error "Failed to bind #{info} (attempt #{a}), retry in #{t}s", e
|
50
|
+
end
|
51
|
+
|
52
|
+
r.depend_on core
|
53
|
+
|
54
|
+
core.stopping do
|
55
|
+
log.info "Unbinding #{info}"
|
56
|
+
|
57
|
+
if @sig
|
58
|
+
EM.stop_server @sig
|
59
|
+
@sig = nil
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,107 @@
|
|
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::TCP
|
17
|
+
class Connection
|
18
|
+
INITIAL_TIMEOUT = 2
|
19
|
+
|
20
|
+
attr_reader :log, :peer, :reporter_meta
|
21
|
+
|
22
|
+
def initialize log, host, port, handler, args, outbound_limit
|
23
|
+
@log = log
|
24
|
+
@host = host
|
25
|
+
@port = port
|
26
|
+
@handler = handler
|
27
|
+
@args = args
|
28
|
+
@outbound_limit = outbound_limit
|
29
|
+
|
30
|
+
@peer = "#{host}:#{port}"
|
31
|
+
@closing = false
|
32
|
+
@reconnect_timeout = INITIAL_TIMEOUT
|
33
|
+
@reporter_meta = {:type => @handler.plugin_type, :peer => peer}
|
34
|
+
|
35
|
+
@timer = nil
|
36
|
+
@c = nil
|
37
|
+
@open = false
|
38
|
+
end
|
39
|
+
|
40
|
+
# Start attempting to connect.
|
41
|
+
def connect
|
42
|
+
log.info "Connecting to tcp://#{@host}:#{@port}"
|
43
|
+
@c = EM.connect @host, @port, @handler, self, *@args
|
44
|
+
end
|
45
|
+
|
46
|
+
# Explicitly disconnect and discard any reconnect attempts..
|
47
|
+
def disconnect
|
48
|
+
log.info "Disconnecting from tcp://#{@host}:#{@port}"
|
49
|
+
@closing = true
|
50
|
+
|
51
|
+
@c.close_connection if @c
|
52
|
+
@timer.cancel if @timer
|
53
|
+
@c = nil
|
54
|
+
@timer = nil
|
55
|
+
end
|
56
|
+
|
57
|
+
def send_event event
|
58
|
+
@c.send_event event
|
59
|
+
end
|
60
|
+
|
61
|
+
def send_metric metric
|
62
|
+
@c.send_metric metric
|
63
|
+
end
|
64
|
+
|
65
|
+
def send_all events, metrics
|
66
|
+
@c.send_all events, metrics
|
67
|
+
end
|
68
|
+
|
69
|
+
def connection_completed
|
70
|
+
@open = true
|
71
|
+
@log.info "Connected tcp://#{peer}"
|
72
|
+
@reconnect_timeout = INITIAL_TIMEOUT
|
73
|
+
|
74
|
+
unless @timer.nil?
|
75
|
+
@timer.cancel
|
76
|
+
@timer = nil
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def unbind
|
81
|
+
@open = false
|
82
|
+
@c = nil
|
83
|
+
|
84
|
+
if @closing
|
85
|
+
return
|
86
|
+
end
|
87
|
+
|
88
|
+
@log.info "Disconnected from tcp://#{peer}, reconnecting in #{@reconnect_timeout}s"
|
89
|
+
|
90
|
+
unless @timer.nil?
|
91
|
+
@timer.cancel
|
92
|
+
@timer = nil
|
93
|
+
end
|
94
|
+
|
95
|
+
@timer = EM::Timer.new(@reconnect_timeout) do
|
96
|
+
@reconnect_timeout *= 2
|
97
|
+
@timer = nil
|
98
|
+
@c = EM.connect @host, @port, @handler, self, *@args
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# Check if a connection is writable or not.
|
103
|
+
def writable?
|
104
|
+
not @c.nil? and @open and @c.get_outbound_data_size < @outbound_limit
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,135 @@
|
|
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 '../../reporter'
|
17
|
+
|
18
|
+
module FFWD::TCP
|
19
|
+
# A TCP connection implementation that buffers events and metrics in batches
|
20
|
+
# over a time window and calls 'send_all' on the connection.
|
21
|
+
class FlushingConnect
|
22
|
+
include FFWD::Reporter
|
23
|
+
|
24
|
+
setup_reporter :keys => [
|
25
|
+
:dropped_events, :dropped_metrics,
|
26
|
+
:sent_events, :sent_metrics,
|
27
|
+
:failed_events, :failed_metrics,
|
28
|
+
:forced_flush
|
29
|
+
]
|
30
|
+
|
31
|
+
attr_reader :log
|
32
|
+
|
33
|
+
def reporter_meta
|
34
|
+
@c.reporter_meta
|
35
|
+
end
|
36
|
+
|
37
|
+
def initialize(
|
38
|
+
core, log, connection,
|
39
|
+
flush_period, event_limit, metric_limit, flush_limit
|
40
|
+
)
|
41
|
+
@log = log
|
42
|
+
@c = connection
|
43
|
+
|
44
|
+
@flush_period = flush_period
|
45
|
+
@event_limit = event_limit
|
46
|
+
@event_flush_limit = flush_limit * event_limit
|
47
|
+
@metric_limit = metric_limit
|
48
|
+
@metric_flush_limit = flush_limit * metric_limit
|
49
|
+
|
50
|
+
@event_buffer = []
|
51
|
+
@metric_buffer = []
|
52
|
+
@timer = nil
|
53
|
+
|
54
|
+
subs = []
|
55
|
+
|
56
|
+
core.starting do
|
57
|
+
log.info "Flushing every #{@flush_period}s"
|
58
|
+
@timer = EM::PeriodicTimer.new(@flush_period){flush!}
|
59
|
+
|
60
|
+
event_consumer = setup_consumer(
|
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)
|
64
|
+
|
65
|
+
subs << core.output.event_subscribe(&event_consumer)
|
66
|
+
subs << core.output.metric_subscribe(&metric_consumer)
|
67
|
+
|
68
|
+
@c.connect
|
69
|
+
end
|
70
|
+
|
71
|
+
core.stopping do
|
72
|
+
subs.each(&:unsubscribe).clear
|
73
|
+
|
74
|
+
if @timer
|
75
|
+
@timer.cancel
|
76
|
+
@timer = nil
|
77
|
+
end
|
78
|
+
|
79
|
+
@c.disconnect
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def flush!
|
84
|
+
if @event_buffer.empty? and @metric_buffer.empty?
|
85
|
+
return
|
86
|
+
end
|
87
|
+
|
88
|
+
unless @c.writable?
|
89
|
+
increment :dropped_events, @event_buffer.size
|
90
|
+
increment :dropped_metrics, @metric_buffer.size
|
91
|
+
return
|
92
|
+
end
|
93
|
+
|
94
|
+
@c.send_all @event_buffer, @metric_buffer
|
95
|
+
increment :sent_events, @event_buffer.size
|
96
|
+
increment :sent_metrics, @metric_buffer.size
|
97
|
+
rescue => e
|
98
|
+
log.error "Failed to flush buffers", e
|
99
|
+
|
100
|
+
log.error "The following data could not be flushed:"
|
101
|
+
|
102
|
+
@event_buffer.each_with_index do |event, i|
|
103
|
+
log.error "##{i}: #{event.to_h}"
|
104
|
+
end
|
105
|
+
|
106
|
+
@metric_buffer.each_with_index do |metric, i|
|
107
|
+
log.error "##{i}: #{metric.to_h}"
|
108
|
+
end
|
109
|
+
|
110
|
+
increment :failed_events, @event_buffer.size
|
111
|
+
increment :failed_metrics, @metric_buffer.size
|
112
|
+
ensure
|
113
|
+
@event_buffer.clear
|
114
|
+
@metric_buffer.clear
|
115
|
+
end
|
116
|
+
|
117
|
+
private
|
118
|
+
|
119
|
+
def setup_consumer buffer, buffer_limit, flush_limit, statistics_key
|
120
|
+
proc do |e|
|
121
|
+
if buffer.size >= buffer_limit
|
122
|
+
increment statistics_key, 1
|
123
|
+
next
|
124
|
+
end
|
125
|
+
|
126
|
+
buffer << e
|
127
|
+
|
128
|
+
if buffer.size >= flush_limit
|
129
|
+
increment :forced_flush, 1
|
130
|
+
flush!
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|