ffwd-kafka 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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f573e5f2791717f35db451565fbe6c6fa81eed31
4
+ data.tar.gz: 801ab9687daa06525d5700f664d23e7ee0e8303c
5
+ SHA512:
6
+ metadata.gz: 73165428dc728720ee1eea06a94c9a9ab72a2e40128b9391649b432aa1b9b0ce2e36db343e143e5365762742433a24bb58e9dfa2493be3c27d6012c9e81c19c3
7
+ data.tar.gz: 348dd79932ef81d62ba544c49887594c0270f71da0ea252c3fa1dbb39893ed4389487cb5b1b6fe4e3929c311429c04da622ad9524567fba540df39f61bf99554
@@ -0,0 +1,102 @@
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 'ffwd/logging'
17
+ require 'ffwd/producing_client'
18
+
19
+ require_relative 'producer'
20
+
21
+ module FFWD::Plugin::Kafka
22
+ class Output < FFWD::ProducingClient::Producer
23
+ include FFWD::Logging
24
+ include FFWD::Reporter
25
+
26
+ setup_reporter :keys => [:kafka_routing_error, :kafka_routing_success]
27
+
28
+ attr_reader :reporter_meta
29
+
30
+ MAPPING = [:host, :ttl, :key, :time, :value, :tags, :attributes]
31
+
32
+ def initialize producer, brokers, schema, router, partitioner
33
+ @producer = producer
34
+ @brokers = brokers
35
+ @schema = schema
36
+ @router = router
37
+ @partitioner = partitioner
38
+ @reporter_meta = {:producer_type => "kafka", :producer => @producer}
39
+ @instance = nil
40
+ end
41
+
42
+ def setup
43
+ if not @brokers or @brokers.empty?
44
+ log.error "No usable initial list of brokers"
45
+ return
46
+ end
47
+
48
+ @instance = Producer.new @brokers, @producer
49
+ end
50
+
51
+ def teardown
52
+ if @instance
53
+ @instance.stop
54
+ @instance = nil
55
+ end
56
+ end
57
+
58
+ def produce events, metrics
59
+ unless @instance
60
+ return nil
61
+ end
62
+
63
+ expected_messages = events.size + metrics.size
64
+ messages = []
65
+
66
+ events.each do |e|
67
+ message = make_event_message e
68
+ next if message.nil?
69
+ messages << message
70
+ end
71
+
72
+ metrics.each do |e|
73
+ message = make_metric_message e
74
+ next if message.nil?
75
+ messages << message
76
+ end
77
+
78
+ if messages.size < expected_messages
79
+ increment :kafka_routing_error, expected_messages - messages.size
80
+ end
81
+
82
+ increment :kafka_routing_success, messages.size
83
+ @instance.send_messages messages
84
+ end
85
+
86
+ def make_event_message e
87
+ topic = @router.route_event e
88
+ return nil if topic.nil?
89
+ data = @schema.dump_event e
90
+ key = @partitioner.partition e
91
+ MessageToSend.new topic, data, key
92
+ end
93
+
94
+ def make_metric_message m
95
+ topic = @router.route_metric m
96
+ return nil if topic.nil?
97
+ data = @schema.dump_metric m
98
+ key = @partitioner.partition m
99
+ MessageToSend.new topic, data, key
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,67 @@
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::Plugin::Kafka
17
+ # Use the key for partitioning.
18
+ module KeyPartitioner
19
+ def self.partition d
20
+ d.key
21
+ end
22
+ end
23
+
24
+ # Use the host for partitioning.
25
+ module HostPartitioner
26
+ def self.partition d
27
+ d.host
28
+ end
29
+ end
30
+
31
+ # Use a custom attribute for partitioning.
32
+ class AttributePartitioner
33
+ DEFAULT_ATTRIBUTE = :site
34
+
35
+ def self.build opts
36
+ attr = opts[:attribute] || DEFAULT_ATTRIBUTE
37
+ new attr
38
+ end
39
+
40
+ def initialize attr
41
+ @attr = attr.to_sym
42
+ @attr_s = attr.to_s
43
+ end
44
+
45
+ # currently there is an issue where you can store both symbols and string
46
+ # as attribute keys, we need to take that into account.
47
+ def partition d
48
+ if v = d.attributes[@attr]
49
+ return v
50
+ end
51
+
52
+ d.attributes[@attr_s]
53
+ end
54
+ end
55
+
56
+ def self.build_partitioner type, opts
57
+ if type == :host
58
+ return HostPartitioner
59
+ end
60
+
61
+ if type == :key
62
+ return KeyPartitioner
63
+ end
64
+
65
+ return AttributePartitioner.build opts
66
+ end
67
+ end
@@ -0,0 +1,99 @@
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 'poseidon'
17
+
18
+ module FFWD::Plugin::Kafka
19
+ MessageToSend = Poseidon::MessageToSend
20
+
21
+ # A Kafka producer proxy for Poseidon (a kafka library) that delegates all
22
+ # blocking work to the EventMachine thread pool.
23
+ class Producer
24
+ class Request
25
+ include EM::Deferrable
26
+ end
27
+
28
+ def initialize *args
29
+ @args = args
30
+ @mutex = Mutex.new
31
+ @request = nil
32
+ @stopped = false
33
+ end
34
+
35
+ def stop
36
+ @stopped = true
37
+ shutdown
38
+ end
39
+
40
+ def shutdown
41
+ return if @request
42
+
43
+ @mutex.synchronize do
44
+ @producer.shutdown
45
+ end
46
+ end
47
+
48
+ def send_messages messages
49
+ execute do |p|
50
+ p.send_messages messages
51
+ end
52
+ end
53
+
54
+ def make_producer
55
+ if EM.reactor_thread?
56
+ raise "Should not be called in the reactor thread"
57
+ end
58
+
59
+ @mutex.synchronize do
60
+ @producer ||= Poseidon::Producer.new(*@args)
61
+ end
62
+ end
63
+
64
+ # Execute the provided block on a dedicated thread.
65
+ # The sole provided argument is an instance of Poseidon::Producer.
66
+ def execute &block
67
+ raise "Expected block" unless block_given?
68
+ raise "Request already pending" if @request
69
+
70
+ if @stopped
71
+ r = Request.new
72
+ r.fail "producer stopped"
73
+ return r
74
+ end
75
+
76
+ @request = Request.new
77
+
78
+ EM.defer do
79
+ begin
80
+ result = block.call make_producer
81
+
82
+ EM.next_tick do
83
+ @request.succeed result
84
+ @request = nil
85
+ shutdown if @stopped
86
+ end
87
+ rescue => e
88
+ EM.next_tick do
89
+ @request.fail e
90
+ @request = nil
91
+ shutdown if @stopped
92
+ end
93
+ end
94
+ end
95
+
96
+ @request
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,63 @@
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::Plugin::Kafka
17
+ # Use a custom attribute for partitioning.
18
+ class AttributeRouter
19
+ DEFAULT_METRIC_PATTERN = "metrics-%s"
20
+ DEFAULT_EVENT_PATTERN = "events-%s"
21
+ DEFAULT_ATTRIBUTE = :site
22
+
23
+ def self.build opts
24
+ metric_pattern = opts[:metric_pattern] || DEFAULT_METRIC_PATTERN
25
+ event_pattern = opts[:event_pattern] || DEFAULT_EVENT_PATTERN
26
+ attr = opts[:attribute] || DEFAULT_ATTRIBUTE
27
+ new(metric_pattern, event_pattern, attr)
28
+ end
29
+
30
+ def initialize metric_pattern, event_pattern, attr
31
+ @metric_pattern = metric_pattern
32
+ @event_pattern = event_pattern
33
+ @attr = attr.to_sym
34
+ @attr_s = attr.to_s
35
+ end
36
+
37
+ def value d
38
+ if v = d.attributes[@attr]
39
+ return v
40
+ end
41
+
42
+ d.attributes[@attr_s]
43
+ end
44
+ p
45
+ def route_event e
46
+ return nil unless v = value(e)
47
+ @event_pattern % [v]
48
+ end
49
+
50
+ def route_metric m
51
+ return nil unless v = value(m)
52
+ @metric_pattern % [v]
53
+ end
54
+ end
55
+
56
+ def self.build_router type, opts
57
+ if type == :attribute
58
+ return AttributeRouter.build opts
59
+ end
60
+
61
+ raise "Unsupported router type: #{type}"
62
+ end
63
+ end
@@ -0,0 +1,22 @@
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
+ module Plugin
18
+ module Kafka
19
+ VERSION = "0.1.0"
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,53 @@
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 'ffwd/logging'
17
+ require 'ffwd/plugin'
18
+ require 'ffwd/producing_client'
19
+ require 'ffwd/reporter'
20
+ require 'ffwd/schema'
21
+
22
+ require_relative 'kafka/output'
23
+ require_relative 'kafka/partitioners'
24
+ require_relative 'kafka/routers'
25
+
26
+ module FFWD::Plugin
27
+ module Kafka
28
+ include FFWD::Plugin
29
+ include FFWD::Logging
30
+
31
+ register_plugin "kafka"
32
+
33
+ DEFAULT_PRODUCER = "ffwd"
34
+ DEFAULT_ROUTING_METHOD = :attribute
35
+ DEFAULT_ROUTING_KEY = :site
36
+ DEFAULT_BROKERS = ["localhost:9092"]
37
+ DEFAULT_PARTITIONER = :host
38
+ DEFAULT_ROUTER = :attribute
39
+
40
+ def self.setup_output opts, core
41
+ producer = opts[:producer] || DEFAULT_PRODUCER
42
+ brokers = opts[:brokers] || DEFAULT_BROKERS
43
+ partitioner = FFWD::Plugin::Kafka.build_partitioner(
44
+ opts[:partitioner] || DEFAULT_PARTITIONER, opts)
45
+ router = FFWD::Plugin::Kafka.build_router(
46
+ opts[:router] || DEFAULT_ROUTER, opts)
47
+ schema = FFWD.parse_schema opts
48
+
49
+ producer = Output.new producer, brokers, schema, router, partitioner
50
+ FFWD.producing_client core.output, producer, opts
51
+ end
52
+ end
53
+ end
metadata ADDED
@@ -0,0 +1,78 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ffwd-kafka
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - John-John Tedro
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-02-25 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: poseidon
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: ffwd
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description:
42
+ email:
43
+ - udoprog@spotify.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - lib/ffwd/plugin/kafka/output.rb
49
+ - lib/ffwd/plugin/kafka/producer.rb
50
+ - lib/ffwd/plugin/kafka/routers.rb
51
+ - lib/ffwd/plugin/kafka/version.rb
52
+ - lib/ffwd/plugin/kafka/partitioners.rb
53
+ - lib/ffwd/plugin/kafka.rb
54
+ homepage: https://github.com/spotify/ffwd
55
+ licenses:
56
+ - Apache 2.0
57
+ metadata: {}
58
+ post_install_message:
59
+ rdoc_options: []
60
+ require_paths:
61
+ - lib
62
+ required_ruby_version: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - '>='
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
67
+ required_rubygems_version: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - '>='
70
+ - !ruby/object:Gem::Version
71
+ version: '0'
72
+ requirements: []
73
+ rubyforge_project:
74
+ rubygems_version: 2.0.3
75
+ signing_key:
76
+ specification_version: 4
77
+ summary: Kafka support for FFWD.
78
+ test_files: []