anschel 0.5.0 → 0.6.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1c067fd0f07d2642121198aed3e1a129c753ed34
4
- data.tar.gz: 4c404083a4512a68bbe8f84683e6d89dd47e3acd
3
+ metadata.gz: 6a2475c658cf220a706e32d1bd87816b1278465d
4
+ data.tar.gz: b6a9b99ff3ce1b8829373c1abc08809f9b0e7660
5
5
  SHA512:
6
- metadata.gz: 62fd8c2b1775ae0d938473fd706d2520d5f6dfa6573184f540e0fff7f3d91dacd93e18ca4fdfc2da06d89b13eba830248d163293b7c0aed744055e898014ebf6
7
- data.tar.gz: 2f986177c04b3a24af8c48966f270b8bed5d94b26db59147f866b98f91b493c4b552de21a23e54e11d8c842ede68a345ac06e6c07ab374fd32039049dc70a9e5
6
+ metadata.gz: 5e6882bb74eb0f96074c0a126c67eb9151d49ad64ab094fc91089cbdc9e3ae5d8603748b21e3190c6192defea4885d2517f632270dde4ac5a38ac3efc4a65e95
7
+ data.tar.gz: fd482f04a614e36a9f75a104e77ed52f2905e80730a35aabe485d8c2cce20918283eec6a2e447c9c3ff9b0dc347c41cd19107ae1c1a8020f6d5f5e215ef18f24
data/Readme.md CHANGED
@@ -162,4 +162,6 @@ You might deploy Anschel with Upstart. Here's a minimal config:
162
162
  _In development_
163
163
 
164
164
  - Intial implementation of the Kafka-to-Elasticsearch pipeline
165
- - Additional support for RabbitMQ input and file (device) output
165
+ - Support for file (device) output (v0.4)
166
+ - Support for RabbitMQ input (v0.5)
167
+ - Allow multiple input and output configuration (v0.6)
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.5.0
1
+ 0.6.0
@@ -2,7 +2,8 @@
2
2
  # "index": {
3
3
  # "stamp": "",
4
4
  # "prefix": "",
5
- # "suffix": ""
5
+ # "suffix": "",
6
+ # "format": ""
6
7
  # }
7
8
  # }
8
9
  module Anschel
@@ -11,18 +12,17 @@ module Anschel
11
12
  stamp = conf.delete(:stamp) || '@timestamp'
12
13
  prefix = conf.delete(:prefix) || 'logs-%{type}-'
13
14
  suffix = conf.delete(:suffix) || '%Y.%m.%d'
15
+ format = conf.delete(:format) || "yyyy-MM-dd'T'HH:mm:ss.SSSZ" # ISO8601
14
16
 
15
17
  stamp = stamp.to_sym
16
18
 
17
- iso8601 = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
18
-
19
- joda = org.joda.time.format.DateTimeFormat.forPattern iso8601
19
+ joda = org.joda.time.format.DateTimeFormat.forPattern format
20
20
  joda = joda.withDefaultYear(Time.new.year)
21
21
  joda = joda.withOffsetParsed
22
22
 
23
23
 
24
24
  log.debug event: 'compiled-filter', filter: 'index', \
25
- stamp: stamp, prefix: prefix, suffix: suffix
25
+ stamp: stamp, prefix: prefix, suffix: suffix, format: format
26
26
 
27
27
  lambda do |event|
28
28
  return event unless event.has_key? stamp
@@ -23,7 +23,7 @@ module Anschel
23
23
  return event unless event.has_key? field
24
24
  mdata = pattern.match event[field]
25
25
  mdata.names.each do |group|
26
- event[group] = mdata[group]
26
+ event[group.to_sym] = mdata[group]
27
27
  end
28
28
  filtered event, conf
29
29
  end
@@ -28,7 +28,7 @@ module Anschel
28
28
 
29
29
  def apply event
30
30
  raise 'Event does not have a "type" field' unless event[:type]
31
- type = event[:type].dup # In case of modification
31
+ type = event[:type].to_sym # In case of modification
32
32
  filters[:_before].each { |f| f.call event }
33
33
  filters[type].each { |f| f.call event }
34
34
  filters[:_after].each { |f| f.call event }
@@ -40,7 +40,7 @@ module Anschel
40
40
 
41
41
  def filtered event, options
42
42
  if remove_field = options[:remove_field]
43
- event.delete remove_field
43
+ event.delete remove_field.to_sym
44
44
  end
45
45
  event
46
46
  end
@@ -0,0 +1,9 @@
1
+ module Anschel
2
+ class Input
3
+ class Base
4
+ def stop
5
+ raise 'To be implemented'
6
+ end
7
+ end
8
+ end
9
+ end
@@ -1,27 +1,22 @@
1
1
  require 'jruby-kafka'
2
2
 
3
+ require_relative 'base'
4
+
3
5
 
4
6
  module Anschel
5
7
  class Input
6
- class Kafka
7
- def initialize config, stats, log
8
+ class Kafka < Base
9
+ def initialize queue, config, stats, log
8
10
  log.trace event: 'input', kind: 'kafka', config: config
9
- qsize = config.delete(:queue_size) || 1000
10
- @queue = SizedQueue.new qsize
11
- consumer_group = ::Kafka::Group.new config
12
- consumer_group.run num_cpus, @queue
13
-
14
- trap('SIGINT') do
15
- consumer_group.shutdown
16
- log.info event: 'goodbye', version: VERSION
17
- exit
18
- end
19
-
20
- log.info event: 'input-loaded'
11
+ @consumer_group = ::Kafka::Group.new config
12
+ @consumer_group.run num_cpus, queue
21
13
  end
22
14
 
23
-
24
- def shift ; @queue.shift end
15
+ def stop
16
+ return if @stopped
17
+ @consumer_group.shutdown
18
+ @stopped = true
19
+ end
25
20
  end
26
21
  end
27
22
  end
@@ -1,15 +1,18 @@
1
1
  require 'march_hare'
2
2
 
3
+ require_relative 'base'
4
+
3
5
 
4
6
  module Anschel
5
7
  class Input
6
- class RabbitMQ
7
- def initialize config, stats, log
8
+ class RabbitMQ < Base
9
+ def initialize queue, config, stats, log
8
10
  log.trace event: 'input', kind: 'rabbitmq', config: config
9
- qsize = config[:connection].delete(:queue_size) || 1000
10
- @queue = SizedQueue.new qsize
11
11
 
12
- default_exchange = { type: 'x-consistent-hash' }
12
+ default_exchange = {
13
+ type: 'x-consistent-hash',
14
+ durable: true
15
+ }
13
16
 
14
17
  default_qconf = {
15
18
  exclusive: false,
@@ -19,34 +22,27 @@ module Anschel
19
22
 
20
23
  exchange_name = config[:exchange].delete(:name)
21
24
 
22
- rmq_threads = config[:queues].map do |qname, qconf|
25
+ @threads = config[:queues].map do |qname, qconf|
23
26
  Thread.new do
24
27
  conn = ::MarchHare.connect config[:connection]
25
28
  chan = conn.create_channel
26
29
 
27
- exchange = channel.exchange exchange_name, \
30
+ exchange = chan.exchange exchange_name, \
28
31
  default_exchange.merge(config[:exchange])
29
32
 
30
- rmq = chan.queue qname, default_qconf.merge(qconf)
31
- rmq.subscribe(block: true, ack: true) do |_, message|
32
- @queue << message
33
+ rmq = chan.queue qname.to_s, default_qconf.merge(qconf)
34
+ rmq.subscribe(block: true) do |_, message|
35
+ queue << message
33
36
  end
34
37
  end
35
38
  end
36
-
37
- trap('SIGINT') do
38
- rmq_threads.map &:kill
39
- log.info event: 'goodbye', version: VERSION
40
- exit
41
- end
42
-
43
- log.info event: 'input-loaded'
44
-
45
- rmq_threads.map &:join
46
39
  end
47
40
 
48
-
49
- def shift ; @queue.shift end
41
+ def stop
42
+ return if @stopped
43
+ @threads.map &:kill
44
+ @stopped = true
45
+ end
50
46
  end
51
47
  end
52
48
  end
data/lib/anschel/input.rb CHANGED
@@ -4,13 +4,44 @@ require_relative 'input/rabbitmq'
4
4
 
5
5
  module Anschel
6
6
  class Input
7
- def initialize config, stats, log
8
- if config[:kafka]
9
- Input::Kafka.new config[:kafka], stats, log
10
- elsif config[:rabbitmq]
11
- Input::RabbitMQ.new config[:rabbitmq], stats, log
7
+ def initialize config, qsize, stats, log
8
+ if config.empty?
9
+ raise 'No input provided'
10
+ end
11
+
12
+ @queue = SizedQueue.new qsize || 2000
13
+
14
+ @inputs = []
15
+
16
+ config.each do |input|
17
+ case input.delete(:kind)
18
+ when 'kafka'
19
+ @inputs << Input::Kafka.new(@queue, input, stats, log)
20
+ when 'rabbitmq'
21
+ @inputs << Input::RabbitMQ.new(@queue, input, stats, log)
22
+ else
23
+ raise 'Uknown input type'
24
+ end
25
+ end
26
+
27
+ log.info event: 'input-loaded'
28
+ end
29
+
30
+
31
+ def stop
32
+ return if @stopped
33
+ @inputs.map &:stop
34
+ @stopped = true
35
+ end
36
+
37
+
38
+ def shift
39
+ event = @queue.shift
40
+ case event
41
+ when String
42
+ event
12
43
  else
13
- raise 'Unkown input type'
44
+ event.message.to_s
14
45
  end
15
46
  end
16
47
  end
data/lib/anschel/main.rb CHANGED
@@ -46,17 +46,27 @@ module Anschel
46
46
  options: options.to_hash,
47
47
  num_cpus: num_cpus
48
48
 
49
- config = JrJackson::Json.load File.read(options.config), symbolize_keys: true
49
+ config = JrJackson::Json.load \
50
+ File.read(options.config), symbolize_keys: true
51
+
50
52
  setup_log4j config[:log4j]
51
53
 
52
54
  stats = Stats.new log, options.stats_interval
53
55
 
54
- input = Input.new config[:input], stats, log
56
+ input = Input.new config[:input], config[:queue_size], stats, log
55
57
 
56
58
  filter = Filter.new config[:filter], stats, log
57
59
 
58
60
  output = Output.new config[:output], stats, log
59
61
 
62
+ trap('SIGINT') do
63
+ input.stop
64
+ output.stop
65
+ log.info event: 'goodbye', version: VERSION
66
+ exit
67
+ end
68
+
69
+
60
70
  stats.create 'event'
61
71
  stats.get 'event'
62
72
 
@@ -64,7 +74,7 @@ module Anschel
64
74
  Thread.new do
65
75
  loop do
66
76
  event = JrJackson::Json.load \
67
- input.shift.message.to_s, symbolize_keys: true
77
+ input.shift, symbolize_keys: true
68
78
  output.push filter.apply(event)
69
79
  stats.inc 'event'
70
80
  end
@@ -0,0 +1,13 @@
1
+ module Anschel
2
+ class Output
3
+ class Base
4
+ def stop
5
+ return if @stopped
6
+ @thread.kill
7
+ @stopped = true
8
+ end
9
+
10
+ def push event ; @queue.push event end
11
+ end
12
+ end
13
+ end
@@ -1,27 +1,26 @@
1
1
  require 'thread'
2
2
 
3
+ require_relative 'base'
4
+
5
+
3
6
  module Anschel
4
7
  class Output
5
- class Device
8
+ class Device < Base
6
9
  def initialize config, stats, log
7
10
  log.trace event: 'output', kind: 'device', config: config
8
11
 
9
- path = config.delete(:path)
10
- qsize = config.delete(:queue_size) || 2000
11
- @q = SizedQueue.new qsize
12
+ path = config.delete(:path)
13
+ qsize = config.delete(:queue_size) || 2000
14
+ @queue = SizedQueue.new qsize
12
15
 
13
- Thread.new do
16
+ @thread = Thread.new do
14
17
  File.open(path, 'w') do |f|
15
18
  loop do
16
- f.puts @q.shift
19
+ f.puts @queue.shift
17
20
  end
18
21
  end
19
22
  end
20
-
21
- log.info event: 'output-loaded'
22
23
  end
23
-
24
- def push event ; @q.push event end
25
24
  end
26
25
  end
27
26
  end
@@ -1,16 +1,17 @@
1
1
  require 'thread'
2
2
 
3
- require 'typhoeus/adapters/faraday'
4
3
  require 'typhoeus'
4
+ require 'typhoeus/adapters/faraday'
5
5
  require 'elasticsearch'
6
6
 
7
+ require_relative 'base'
8
+
7
9
 
8
10
  module Anschel
9
11
  class Output
10
- class Elasticsearch
12
+ class Elasticsearch < Base
11
13
  def initialize config, stats, log
12
14
  log.trace event: 'output', kind: 'elasticsearch', config: config
13
- pattern = config.delete(:index_pattern)
14
15
  qsize = config.delete(:queue_size) || 2000
15
16
  bsize = config.delete(:bulk_size) || 500
16
17
  timeout = config.delete(:bulk_timeout) || 0.5
@@ -20,7 +21,7 @@ module Anschel
20
21
 
21
22
  @queue = SizedQueue.new qsize
22
23
 
23
- Thread.new do
24
+ @thread = Thread.new do
24
25
  loop do
25
26
  events = []
26
27
  count = 0
@@ -43,11 +44,7 @@ module Anschel
43
44
  client.bulk body: body
44
45
  end
45
46
  end
46
-
47
- log.info event: 'output-loaded'
48
47
  end
49
-
50
- def push event ; @queue.push event end
51
48
  end
52
49
  end
53
50
  end
@@ -5,12 +5,36 @@ require_relative 'output/device'
5
5
  module Anschel
6
6
  class Output
7
7
  def initialize config, stats, log
8
- if config[:device]
9
- Output::Device.new config[:device], stats, log
10
- elsif config[:elasticsearch]
11
- Output::Elasticsearch.new config[:elasticsearch], stats, log
12
- else
13
- raise 'Unkown output type'
8
+ if config.empty?
9
+ raise 'No output provided'
10
+ end
11
+
12
+ @outputs = []
13
+
14
+ config.each do |output|
15
+ case output.delete(:kind)
16
+ when 'device'
17
+ @outputs << Output::Device.new(output, stats, log)
18
+ when 'elasticsearch'
19
+ @outputs << Output::Elasticsearch.new(output, stats, log)
20
+ else
21
+ raise 'Unkown output type'
22
+ end
23
+ end
24
+
25
+ log.info event: 'output-loaded'
26
+ end
27
+
28
+
29
+ def stop
30
+ return if @stopped
31
+ @outputs.map &:stop
32
+ @stopped = true
33
+ end
34
+
35
+ def push event
36
+ @outputs.each do |output|
37
+ output.push event
14
38
  end
15
39
  end
16
40
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: anschel
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sean Clemmer
@@ -128,12 +128,14 @@ files:
128
128
  - lib/anschel/filter/scan.rb
129
129
  - lib/anschel/filter/stamp.rb
130
130
  - lib/anschel/input.rb
131
+ - lib/anschel/input/base.rb
131
132
  - lib/anschel/input/kafka.rb
132
133
  - lib/anschel/input/rabbitmq.rb
133
134
  - lib/anschel/main.rb
134
135
  - lib/anschel/metadata.rb
135
136
  - lib/anschel/mjolnir.rb
136
137
  - lib/anschel/output.rb
138
+ - lib/anschel/output/base.rb
137
139
  - lib/anschel/output/device.rb
138
140
  - lib/anschel/output/elasticsearch.rb
139
141
  - lib/anschel/stats.rb