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.
Files changed (61) hide show
  1. checksums.yaml +7 -0
  2. data/bin/ffwd +9 -0
  3. data/bin/fwc +15 -0
  4. data/lib/em/all.rb +68 -0
  5. data/lib/ffwd.rb +250 -0
  6. data/lib/ffwd/channel.rb +62 -0
  7. data/lib/ffwd/circular_buffer.rb +78 -0
  8. data/lib/ffwd/connection.rb +40 -0
  9. data/lib/ffwd/core.rb +173 -0
  10. data/lib/ffwd/core/emitter.rb +38 -0
  11. data/lib/ffwd/core/interface.rb +47 -0
  12. data/lib/ffwd/core/processor.rb +92 -0
  13. data/lib/ffwd/core/reporter.rb +32 -0
  14. data/lib/ffwd/debug.rb +76 -0
  15. data/lib/ffwd/debug/connection.rb +48 -0
  16. data/lib/ffwd/debug/monitor_session.rb +71 -0
  17. data/lib/ffwd/debug/tcp.rb +82 -0
  18. data/lib/ffwd/event.rb +65 -0
  19. data/lib/ffwd/event_emitter.rb +57 -0
  20. data/lib/ffwd/handler.rb +43 -0
  21. data/lib/ffwd/lifecycle.rb +92 -0
  22. data/lib/ffwd/logging.rb +139 -0
  23. data/lib/ffwd/metric.rb +55 -0
  24. data/lib/ffwd/metric_emitter.rb +50 -0
  25. data/lib/ffwd/plugin.rb +149 -0
  26. data/lib/ffwd/plugin/json_line.rb +47 -0
  27. data/lib/ffwd/plugin/json_line/connection.rb +118 -0
  28. data/lib/ffwd/plugin/log.rb +35 -0
  29. data/lib/ffwd/plugin/log/writer.rb +42 -0
  30. data/lib/ffwd/plugin_channel.rb +64 -0
  31. data/lib/ffwd/plugin_loader.rb +121 -0
  32. data/lib/ffwd/processor.rb +96 -0
  33. data/lib/ffwd/processor/count.rb +109 -0
  34. data/lib/ffwd/processor/histogram.rb +200 -0
  35. data/lib/ffwd/processor/rate.rb +116 -0
  36. data/lib/ffwd/producing_client.rb +181 -0
  37. data/lib/ffwd/protocol.rb +28 -0
  38. data/lib/ffwd/protocol/tcp.rb +126 -0
  39. data/lib/ffwd/protocol/tcp/bind.rb +64 -0
  40. data/lib/ffwd/protocol/tcp/connection.rb +107 -0
  41. data/lib/ffwd/protocol/tcp/flushing_connect.rb +135 -0
  42. data/lib/ffwd/protocol/tcp/plain_connect.rb +74 -0
  43. data/lib/ffwd/protocol/udp.rb +48 -0
  44. data/lib/ffwd/protocol/udp/bind.rb +64 -0
  45. data/lib/ffwd/protocol/udp/connect.rb +110 -0
  46. data/lib/ffwd/reporter.rb +65 -0
  47. data/lib/ffwd/retrier.rb +72 -0
  48. data/lib/ffwd/schema.rb +92 -0
  49. data/lib/ffwd/schema/default.rb +36 -0
  50. data/lib/ffwd/schema/spotify100.rb +58 -0
  51. data/lib/ffwd/statistics.rb +29 -0
  52. data/lib/ffwd/statistics/collector.rb +99 -0
  53. data/lib/ffwd/statistics/system_statistics.rb +255 -0
  54. data/lib/ffwd/tunnel.rb +27 -0
  55. data/lib/ffwd/tunnel/plugin.rb +47 -0
  56. data/lib/ffwd/tunnel/tcp.rb +60 -0
  57. data/lib/ffwd/tunnel/udp.rb +61 -0
  58. data/lib/ffwd/utils.rb +46 -0
  59. data/lib/ffwd/version.rb +18 -0
  60. data/lib/fwc.rb +206 -0
  61. 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
@@ -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