anschel 0.5.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Readme.md +3 -1
- data/VERSION +1 -1
- data/lib/anschel/filter/index.rb +5 -5
- data/lib/anschel/filter/parse.rb +1 -1
- data/lib/anschel/filter.rb +2 -2
- data/lib/anschel/input/base.rb +9 -0
- data/lib/anschel/input/kafka.rb +11 -16
- data/lib/anschel/input/rabbitmq.rb +18 -22
- data/lib/anschel/input.rb +37 -6
- data/lib/anschel/main.rb +13 -3
- data/lib/anschel/output/base.rb +13 -0
- data/lib/anschel/output/device.rb +9 -10
- data/lib/anschel/output/elasticsearch.rb +5 -8
- data/lib/anschel/output.rb +30 -6
- metadata +3 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6a2475c658cf220a706e32d1bd87816b1278465d
|
4
|
+
data.tar.gz: b6a9b99ff3ce1b8829373c1abc08809f9b0e7660
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
-
|
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.
|
1
|
+
0.6.0
|
data/lib/anschel/filter/index.rb
CHANGED
@@ -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
|
-
|
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
|
data/lib/anschel/filter/parse.rb
CHANGED
data/lib/anschel/filter.rb
CHANGED
@@ -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].
|
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
|
data/lib/anschel/input/kafka.rb
CHANGED
@@ -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
|
-
|
10
|
-
@
|
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
|
-
|
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 = {
|
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
|
-
|
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 =
|
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
|
32
|
-
|
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
|
-
|
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
|
9
|
-
|
10
|
-
|
11
|
-
|
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
|
-
|
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
|
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
|
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
|
77
|
+
input.shift, symbolize_keys: true
|
68
78
|
output.push filter.apply(event)
|
69
79
|
stats.inc 'event'
|
70
80
|
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
|
10
|
-
qsize
|
11
|
-
@
|
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 @
|
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
|
data/lib/anschel/output.rb
CHANGED
@@ -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
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
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.
|
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
|