ffwd 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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