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 +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
|