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,48 @@
|
|
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::Debug
|
17
|
+
class Connection < EM::Connection
|
18
|
+
include FFWD::Logging
|
19
|
+
|
20
|
+
def initialize handler
|
21
|
+
@handler = handler
|
22
|
+
@peer = nil
|
23
|
+
@ip = nil
|
24
|
+
@port = nil
|
25
|
+
end
|
26
|
+
|
27
|
+
def get_peer
|
28
|
+
peer = get_peername
|
29
|
+
port, ip = Socket.unpack_sockaddr_in(peer)
|
30
|
+
return peer, ip, port
|
31
|
+
end
|
32
|
+
|
33
|
+
def post_init
|
34
|
+
@peer, @ip, @port = get_peer
|
35
|
+
@handler.register_client @peer, self
|
36
|
+
log.info "#{@ip}:#{@port}: Connect"
|
37
|
+
end
|
38
|
+
|
39
|
+
def unbind
|
40
|
+
@handler.unregister_client @peer, self
|
41
|
+
log.info "#{@ip}:#{@port}: Disconnect"
|
42
|
+
end
|
43
|
+
|
44
|
+
def send_line line
|
45
|
+
send_data "#{line}\n"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,71 @@
|
|
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::Debug
|
19
|
+
class MonitorSession
|
20
|
+
attr_reader :id
|
21
|
+
|
22
|
+
def initialize id, channel, type
|
23
|
+
@type = type
|
24
|
+
@clients = {}
|
25
|
+
|
26
|
+
subs = []
|
27
|
+
|
28
|
+
channel.starting do
|
29
|
+
subs << channel.event_subscribe do |event|
|
30
|
+
data = @type.serialize_event event
|
31
|
+
|
32
|
+
begin
|
33
|
+
send JSON.dump(:id => @id, :type => :event, :data => data)
|
34
|
+
rescue => e
|
35
|
+
log.error "Failed to serialize event", e
|
36
|
+
return
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
subs << channel.metric_subscribe do |metric|
|
41
|
+
data = @type.serialize_metric metric
|
42
|
+
|
43
|
+
begin
|
44
|
+
send JSON.dump(:id => @id, :type => :metric, :data => data)
|
45
|
+
rescue => e
|
46
|
+
log.error "Failed to serialize metric", e
|
47
|
+
return
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
channel.stopping do
|
53
|
+
subs.each(&:unsubscribe).clear
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def register peer, client
|
58
|
+
@clients[peer] = client
|
59
|
+
end
|
60
|
+
|
61
|
+
def unregister peer, client
|
62
|
+
@clients.delete peer
|
63
|
+
end
|
64
|
+
|
65
|
+
def send line
|
66
|
+
@clients.each do |peer, client|
|
67
|
+
client.send_line line
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,82 @@
|
|
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
|
+
require_relative '../logging'
|
18
|
+
require_relative '../retrier'
|
19
|
+
|
20
|
+
require_relative 'connection'
|
21
|
+
require_relative 'monitor_session'
|
22
|
+
|
23
|
+
module FFWD::Debug
|
24
|
+
class TCP
|
25
|
+
include FFWD::Logging
|
26
|
+
include FFWD::Lifecycle
|
27
|
+
|
28
|
+
def initialize host, port, rebind_timeout
|
29
|
+
@clients = {}
|
30
|
+
@sessions = {}
|
31
|
+
@host = host
|
32
|
+
@port = port
|
33
|
+
@peer = "#{@host}:#{@port}"
|
34
|
+
|
35
|
+
r = FFWD.retry :timeout => rebind_timeout do |attempt|
|
36
|
+
EM.start_server @host, @port, Connection, self
|
37
|
+
log.info "Bind on tcp://#{@peer} (attempt #{attempt})"
|
38
|
+
end
|
39
|
+
|
40
|
+
r.error do |a, t, e|
|
41
|
+
log.error "Failed to bind tcp://#{@peer} (attempt #{a}), retry in #{t}s", e
|
42
|
+
end
|
43
|
+
|
44
|
+
r.depend_on self
|
45
|
+
end
|
46
|
+
|
47
|
+
def register_client peer, client
|
48
|
+
@sessions.each do |id, session|
|
49
|
+
session.register peer, client
|
50
|
+
end
|
51
|
+
|
52
|
+
@clients[peer] = client
|
53
|
+
end
|
54
|
+
|
55
|
+
def unregister_client peer, client
|
56
|
+
@sessions.each do |id, session|
|
57
|
+
session.unregister peer, client
|
58
|
+
end
|
59
|
+
|
60
|
+
@clients.delete peer
|
61
|
+
end
|
62
|
+
|
63
|
+
# Setup monitor hooks for the specified input and output channel.
|
64
|
+
def monitor id, channel, type
|
65
|
+
if session = @sessions[id]
|
66
|
+
log.error "Session already monitored: #{id}"
|
67
|
+
return
|
68
|
+
end
|
69
|
+
|
70
|
+
session = @sessions[id] = MonitorSession.new id, channel, type
|
71
|
+
|
72
|
+
# provide the session to the already connected clients.
|
73
|
+
@clients.each do |peer, client|
|
74
|
+
session.register peer, client
|
75
|
+
end
|
76
|
+
|
77
|
+
channel.stopping do
|
78
|
+
@sessions.delete id
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
data/lib/ffwd/event.rb
ADDED
@@ -0,0 +1,65 @@
|
|
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 an event.
|
18
|
+
EventStruct = Struct.new(
|
19
|
+
# The time at which the event was collected.
|
20
|
+
:time,
|
21
|
+
# The unique key of the event.
|
22
|
+
:key,
|
23
|
+
# A numeric value associated with the event.
|
24
|
+
:value,
|
25
|
+
# The host from which the event originated.
|
26
|
+
:host,
|
27
|
+
# The source event this event was derived from (if any).
|
28
|
+
:source,
|
29
|
+
# A state associated to the event.
|
30
|
+
:state,
|
31
|
+
# A description associated to the event.
|
32
|
+
:description,
|
33
|
+
# A time to live associated with the event.
|
34
|
+
:ttl,
|
35
|
+
# Tags associated with the event.
|
36
|
+
:tags,
|
37
|
+
# Attributes (extra fields) associated with the event.
|
38
|
+
:attributes
|
39
|
+
)
|
40
|
+
|
41
|
+
# A convenience class for each individual event.
|
42
|
+
class Event < EventStruct
|
43
|
+
def self.make opts = {}
|
44
|
+
new(opts[:time], opts[:key], opts[:value], opts[:host], opts[:source],
|
45
|
+
opts[:state], opts[:description], opts[:ttl], opts[:tags],
|
46
|
+
opts[:attributes])
|
47
|
+
end
|
48
|
+
|
49
|
+
# Convert event to a sparse hash.
|
50
|
+
def to_h
|
51
|
+
d = {}
|
52
|
+
d[:time] = time.to_i if time
|
53
|
+
d[:key] = key if key
|
54
|
+
d[:value] = value if value
|
55
|
+
d[:host] = host if host
|
56
|
+
d[:source] = source if source
|
57
|
+
d[:state] = state if state
|
58
|
+
d[:description] = description if description
|
59
|
+
d[:ttl] = ttl if ttl
|
60
|
+
d[:tags] = tags.to_a if tags
|
61
|
+
d[:attributes] = attributes if attributes
|
62
|
+
d
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,57 @@
|
|
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 'event'
|
18
|
+
require_relative 'logging'
|
19
|
+
|
20
|
+
module FFWD
|
21
|
+
# Used to emit events to an 'output' channel
|
22
|
+
#
|
23
|
+
# Can take two parts of a configuration 'base' and 'opts' to decide which
|
24
|
+
# metadata emitted events should be decorated with.
|
25
|
+
class EventEmitter
|
26
|
+
include FFWD::Logging
|
27
|
+
|
28
|
+
def self.build output, base, opts
|
29
|
+
output = output
|
30
|
+
host = opts[:host] || base[:host] || FFWD.current_host
|
31
|
+
ttl = opts[:ttl] || base[:ttl]
|
32
|
+
tags = FFWD.merge_sets base[:tags], opts[:tags]
|
33
|
+
attributes = FFWD.merge_hashes base[:attributes], opts[:attributes]
|
34
|
+
new output, host, ttl, tags, attributes
|
35
|
+
end
|
36
|
+
|
37
|
+
def initialize output, host, ttl, tags, attributes
|
38
|
+
@output = output
|
39
|
+
@host = host
|
40
|
+
@ttl = ttl
|
41
|
+
@tags = tags
|
42
|
+
@attributes = attributes
|
43
|
+
end
|
44
|
+
|
45
|
+
def emit e
|
46
|
+
e[:time] ||= Time.now
|
47
|
+
e[:host] ||= @host if @host
|
48
|
+
e[:ttl] ||= @ttl if @ttl
|
49
|
+
e[:tags] = FFWD.merge_sets @tags, e[:tags]
|
50
|
+
e[:attributes] = FFWD.merge_hashes @attributes, e[:attributes]
|
51
|
+
|
52
|
+
@output.event Event.make(e)
|
53
|
+
rescue => e
|
54
|
+
log.error "Failed to emit event", e
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
data/lib/ffwd/handler.rb
ADDED
@@ -0,0 +1,43 @@
|
|
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 'connection'
|
17
|
+
|
18
|
+
module FFWD
|
19
|
+
# Handlers are used by output plugins based of the protocol stack.
|
20
|
+
class Handler < FFWD::Connection
|
21
|
+
def self.new signature, parent, *args
|
22
|
+
instance = super(signature, *args)
|
23
|
+
|
24
|
+
instance.instance_eval do
|
25
|
+
@parent = parent
|
26
|
+
end
|
27
|
+
|
28
|
+
instance
|
29
|
+
end
|
30
|
+
|
31
|
+
def unbind
|
32
|
+
@parent.unbind
|
33
|
+
end
|
34
|
+
|
35
|
+
def connection_completed
|
36
|
+
@parent.connection_completed
|
37
|
+
end
|
38
|
+
|
39
|
+
def send_all events, metrics; end
|
40
|
+
def send_event event; end
|
41
|
+
def send_metric metric; end
|
42
|
+
end
|
43
|
+
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
|
+
# Lifecycle management module.
|
17
|
+
#
|
18
|
+
# Any class and module including this will allow other components to subscribe
|
19
|
+
# to their state changes (starting, stopping).
|
20
|
+
module FFWD
|
21
|
+
module Lifecycle
|
22
|
+
def stopping_hooks
|
23
|
+
@stopping_hooks ||= []
|
24
|
+
end
|
25
|
+
|
26
|
+
def starting_hooks
|
27
|
+
@starting_hooks ||= []
|
28
|
+
end
|
29
|
+
|
30
|
+
# Register a callback to be executed when the Stoppable is to be stopped.
|
31
|
+
#
|
32
|
+
# This will only be called once.
|
33
|
+
def stopping &block
|
34
|
+
if stopped?
|
35
|
+
block.call
|
36
|
+
else
|
37
|
+
stopping_hooks << block
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def starting &block
|
42
|
+
if started?
|
43
|
+
block.call
|
44
|
+
else
|
45
|
+
starting_hooks << block
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def start
|
50
|
+
return if started?
|
51
|
+
starting_hooks.each(&:call)
|
52
|
+
starting_hooks.clear
|
53
|
+
@state = :started
|
54
|
+
end
|
55
|
+
|
56
|
+
def stop
|
57
|
+
return if stopped?
|
58
|
+
stopping_hooks.each(&:call)
|
59
|
+
stopping_hooks.clear
|
60
|
+
@state = :stopped
|
61
|
+
end
|
62
|
+
|
63
|
+
def started?
|
64
|
+
(@state ||= :none) == :started
|
65
|
+
end
|
66
|
+
|
67
|
+
def stopped?
|
68
|
+
(@state ||= :none) == :stopped
|
69
|
+
end
|
70
|
+
|
71
|
+
def depend_on other_lifecycle
|
72
|
+
if other_lifecycle.nil?
|
73
|
+
raise "Other lifecycle must not be nil"
|
74
|
+
end
|
75
|
+
|
76
|
+
if (@depends ||= nil)
|
77
|
+
raise "This component already depends on #{@depends}"
|
78
|
+
end
|
79
|
+
|
80
|
+
@depends = other_lifecycle
|
81
|
+
|
82
|
+
other_lifecycle.starting do
|
83
|
+
start
|
84
|
+
end
|
85
|
+
|
86
|
+
other_lifecycle.stopping do
|
87
|
+
stop
|
88
|
+
@depends = nil
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|