conrad 2.3.1 → 2.4.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/lib/conrad.rb +21 -4
- data/lib/conrad/collector.rb +17 -11
- data/lib/conrad/emitter_queue.rb +58 -0
- data/lib/conrad/emitters.rb +11 -0
- data/lib/conrad/emitters/amazon_base.rb +59 -0
- data/lib/conrad/emitters/kinesis.rb +34 -0
- data/lib/conrad/emitters/sqs.rb +5 -61
- data/lib/conrad/errors.rb +9 -0
- data/lib/conrad/formatters.rb +6 -0
- data/lib/conrad/processors.rb +8 -1
- data/lib/conrad/version.rb +1 -1
- metadata +22 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5bea95c17248374dd5931d1de26433e47f3e47b46ef262ef89e86e8fe516040a
|
4
|
+
data.tar.gz: c1a1388a3ec0d4fcd8002a4b185f336950c92e037db2a831e8fa3cfee47627e9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3cfc946e370b048f352936240516546ba5677d1e2bea493a19c8f537c93f358ad2198f33fb6ab02e6b9d590ad2169a8410fef0ce815a21b39d0b8ef5f7e0c32f
|
7
|
+
data.tar.gz: ba69a3a6d255e10700a7f6bc57672bfa3b06d51dbe2ffdf88ed6a24ebb0f536c16bf70489d9a892031b68daecc3d2c2f477d0706a42b3242b47f4262dadf9995
|
data/lib/conrad.rb
CHANGED
@@ -1,8 +1,25 @@
|
|
1
|
-
|
2
|
-
Gem.find_files('conrad/formatters/*.rb').each { |file| require file }
|
3
|
-
Gem.find_files('conrad/emitters/*.rb').each { |file| require file }
|
4
|
-
Gem.find_files('conrad/*.rb').each { |file| require file }
|
1
|
+
require 'conrad/version'
|
5
2
|
|
6
3
|
# :nodoc:
|
7
4
|
module Conrad
|
5
|
+
autoload :Collector, 'conrad/collector'
|
6
|
+
autoload :Errors, 'conrad/errors'
|
7
|
+
autoload :EmitterQueue, 'conrad/emitter_queue'
|
8
|
+
autoload :Emitters, 'conrad/emitters'
|
9
|
+
autoload :Formatters, 'conrad/formatters'
|
10
|
+
autoload :Processors, 'conrad/processors'
|
11
|
+
autoload :ProcessorStack, 'conrad/processor_stack'
|
12
|
+
autoload :Recorder, 'conrad/recorder'
|
13
|
+
|
14
|
+
class << self
|
15
|
+
# Boolean indicating if the events collected should be emitted in the
|
16
|
+
# background. Defaults to false.
|
17
|
+
def background_emit?
|
18
|
+
EmitterQueue.instance.background
|
19
|
+
end
|
20
|
+
|
21
|
+
def background_emit=(value)
|
22
|
+
EmitterQueue.instance.background = value
|
23
|
+
end
|
24
|
+
end
|
8
25
|
end
|
data/lib/conrad/collector.rb
CHANGED
@@ -138,10 +138,12 @@ module Conrad
|
|
138
138
|
# emitted events, the error will be allowed to bubble up. This is to
|
139
139
|
# prevent the unexpected loss of events if a single one is malformed.
|
140
140
|
def record_events
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
141
|
+
Array(emitter).each do |emitter|
|
142
|
+
if emit_as_batch?
|
143
|
+
record_events_as_batch(emitter, events.clone)
|
144
|
+
else
|
145
|
+
record_individual_events(emitter, events.clone)
|
146
|
+
end
|
145
147
|
end
|
146
148
|
ensure
|
147
149
|
reset_state
|
@@ -173,16 +175,20 @@ module Conrad
|
|
173
175
|
end
|
174
176
|
end
|
175
177
|
|
176
|
-
def record_events_as_batch
|
177
|
-
|
178
|
+
def record_events_as_batch(emitter, events)
|
179
|
+
EmitterQueue.instance.enqueue do
|
180
|
+
emitter.call(events)
|
181
|
+
end
|
178
182
|
end
|
179
183
|
|
180
|
-
def record_individual_events
|
184
|
+
def record_individual_events(emitter, events)
|
181
185
|
events.each do |event|
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
+
EmitterQueue.instance.enqueue do
|
187
|
+
begin
|
188
|
+
emitter.call(event)
|
189
|
+
rescue StandardError => e
|
190
|
+
write_log(:error, e)
|
191
|
+
end
|
186
192
|
end
|
187
193
|
end
|
188
194
|
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Conrad
|
2
|
+
# Centralized event emission queue across threads
|
3
|
+
class EmitterQueue
|
4
|
+
include Singleton
|
5
|
+
|
6
|
+
# Boolean that determines whether events will be emitted inline or in a
|
7
|
+
# background thread
|
8
|
+
attr_reader :background
|
9
|
+
|
10
|
+
# Logger object used for sending log events
|
11
|
+
attr_accessor :logger
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
@thread = nil
|
15
|
+
@queue = Queue.new
|
16
|
+
@logger ||= Logger.new(STDOUT)
|
17
|
+
end
|
18
|
+
|
19
|
+
# bakground setter. Will start/stop the background thread
|
20
|
+
# @param value [Boolean] assigns whether events should be processed inline
|
21
|
+
# or in a separate thread.
|
22
|
+
def background=(value)
|
23
|
+
@background = value
|
24
|
+
value ? start_thread : @thread = nil
|
25
|
+
end
|
26
|
+
|
27
|
+
# Enqueues a block
|
28
|
+
# @yield block to execute. Will either run inline or separately depending on
|
29
|
+
# whether the queue is backgrounded
|
30
|
+
def enqueue
|
31
|
+
@queue.push -> { yield }
|
32
|
+
|
33
|
+
# if it's backgounded we can break out of here, as the background
|
34
|
+
# queue will pick it up. otherwise, we need to explicitly process it
|
35
|
+
emit! unless @background
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def start_thread
|
41
|
+
@thread ||= Thread.new do
|
42
|
+
Thread.current.abort_on_exception = true
|
43
|
+
loop do
|
44
|
+
emit!
|
45
|
+
break unless @background
|
46
|
+
end
|
47
|
+
end
|
48
|
+
rescue e
|
49
|
+
logger.error(e)
|
50
|
+
@thread = nil
|
51
|
+
start_thread
|
52
|
+
end
|
53
|
+
|
54
|
+
def emit!
|
55
|
+
@queue.pop.call until @queue.empty?
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Conrad
|
4
|
+
# :nodoc:
|
5
|
+
module Emitters
|
6
|
+
autoload :AmazonBase, 'conrad/emitters/amazon_base'
|
7
|
+
autoload :Kinesis, 'conrad/emitters/kinesis'
|
8
|
+
autoload :Sqs, 'conrad/emitters/sqs'
|
9
|
+
autoload :Stdout, 'conrad/emitters/stdout'
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'active_model'
|
2
|
+
|
3
|
+
module Conrad
|
4
|
+
module Emitters
|
5
|
+
# Base class for AWS-based emitters
|
6
|
+
class AmazonBase
|
7
|
+
include ::ActiveModel::Model
|
8
|
+
|
9
|
+
# @return [String, nil] the configured region
|
10
|
+
attr_accessor :region
|
11
|
+
|
12
|
+
# @deprecated Will be removed in 3.0.0, no migration path
|
13
|
+
# @return [String, nil] the configured AWS Access key ID
|
14
|
+
attr_accessor :access_key_id
|
15
|
+
|
16
|
+
# @deprecated Will be removed in 3.0.0, no migration path
|
17
|
+
# @return [String, nil] the configured AWS secret access key
|
18
|
+
attr_accessor :secret_access_key
|
19
|
+
|
20
|
+
# @return [Aws::SQS::Client] the created client
|
21
|
+
attr_accessor :client
|
22
|
+
|
23
|
+
# @param queue_url [String] the queue to send messages to
|
24
|
+
# @param region [String] region the queue lives in
|
25
|
+
# @param access_key_id [String] AWS Acesss Key ID
|
26
|
+
# @param secret_access_key [String] AWS Secret Access Key
|
27
|
+
#
|
28
|
+
# @raise [InvalidAwsCredentials] if access_key_id or secret_access_key are
|
29
|
+
# not provided AND the running environment does not have valid AWS
|
30
|
+
# credentials
|
31
|
+
# @raise [Aws::Errors::MissingRegionError] if region is not provided and
|
32
|
+
# also not set via an allowed AWS environment variable
|
33
|
+
def initialize(args = {})
|
34
|
+
super
|
35
|
+
create_client(region: region, access_key_id: access_key_id, secret_access_key: secret_access_key)
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def create_client(region:, access_key_id:, secret_access_key:)
|
41
|
+
if secret_access_key.nil? || access_key_id.nil?
|
42
|
+
validate_implicit_credentials
|
43
|
+
|
44
|
+
@client = self.class.client_class.new({ region: region }.compact)
|
45
|
+
else
|
46
|
+
@client = self.class.client_class.new({
|
47
|
+
region: region,
|
48
|
+
access_key_id: access_key_id,
|
49
|
+
secret_access_key: secret_access_key
|
50
|
+
}.compact)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def validate_implicit_credentials
|
55
|
+
raise Conrad::InvalidAwsCredentials unless Aws::CredentialProviderChain.new.resolve&.set?
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'conrad/errors'
|
2
|
+
|
3
|
+
module Conrad
|
4
|
+
# A module containing all of conrad's built in event emitters for outputting
|
5
|
+
# events
|
6
|
+
module Emitters
|
7
|
+
# Basic emitter for sending events to AWS's kinesis event stream. The emitter will
|
8
|
+
# attempt to use values configured in the running environment according to
|
9
|
+
# the AWS SDK documentation (such as from ~/.aws/credentials).
|
10
|
+
class Kinesis < AmazonBase
|
11
|
+
# @return [String] the configured kinesis stream name
|
12
|
+
attr_accessor :stream_name
|
13
|
+
|
14
|
+
# Sends an event up to Kinesis
|
15
|
+
#
|
16
|
+
# @param event [String] the event to be sent as a Kinesis message body
|
17
|
+
def call(event)
|
18
|
+
client.put_record(
|
19
|
+
stream_name: stream_name,
|
20
|
+
data: event,
|
21
|
+
# There's a 256 character limit on the partition key, and it's hashed down into a value used to
|
22
|
+
# pick the shard to put the data on
|
23
|
+
partition_key: event.first(255)
|
24
|
+
)
|
25
|
+
end
|
26
|
+
|
27
|
+
class << self
|
28
|
+
def client_class
|
29
|
+
Aws::Kinesis::Client
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/conrad/emitters/sqs.rb
CHANGED
@@ -8,51 +8,9 @@ module Conrad
|
|
8
8
|
# is given, the given credentials will be used. Otherwise, the emitter will
|
9
9
|
# attempt to use values configured in the running environment according to
|
10
10
|
# the AWS SDK documentation (such as from ~/.aws/credentials).
|
11
|
-
class Sqs
|
12
|
-
# Error for responding with issues around SQS credential creation
|
13
|
-
class InvalidAwsCredentials < ::Conrad::Error
|
14
|
-
# :nodoc:
|
15
|
-
def to_s
|
16
|
-
'Must provide secret_access_key and access_key_id OR rely ' \
|
17
|
-
'on configured values in the running environment.'
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
11
|
+
class Sqs < AmazonBase
|
21
12
|
# @return [String] the configured SQS queue URL
|
22
|
-
|
23
|
-
|
24
|
-
# @return [String, nil] the configured region
|
25
|
-
attr_reader :region
|
26
|
-
|
27
|
-
# @deprecated Will be removed in 3.0.0, no migration path
|
28
|
-
# @return [String, nil] the configured AWS Access key ID
|
29
|
-
attr_reader :access_key_id
|
30
|
-
|
31
|
-
# @deprecated Will be removed in 3.0.0, no migration path
|
32
|
-
# @return [String, nil] the configured AWS secret access key
|
33
|
-
attr_reader :secret_access_key
|
34
|
-
|
35
|
-
# @return [Aws::SQS::Client] the created client
|
36
|
-
attr_reader :client
|
37
|
-
|
38
|
-
# @param queue_url [String] the queue to send messages to
|
39
|
-
# @param region [String] region the queue lives in
|
40
|
-
# @param access_key_id [String] AWS Acesss Key ID
|
41
|
-
# @param secret_access_key [String] AWS Secret Access Key
|
42
|
-
#
|
43
|
-
# @raise [InvalidAwsCredentials] if access_key_id or secret_access_key are
|
44
|
-
# not provided AND the running environment does not have valid AWS
|
45
|
-
# credentials
|
46
|
-
# @raise [Aws::Errors::MissingRegionError] if region is not provided and
|
47
|
-
# also not set via an allowed AWS environment variable
|
48
|
-
def initialize(queue_url:, region: nil, access_key_id: nil, secret_access_key: nil)
|
49
|
-
@queue_url = queue_url
|
50
|
-
@region = region
|
51
|
-
@access_key_id = access_key_id
|
52
|
-
@secret_access_key = secret_access_key
|
53
|
-
|
54
|
-
create_client(region: region, access_key_id: access_key_id, secret_access_key: secret_access_key)
|
55
|
-
end
|
13
|
+
attr_accessor :queue_url
|
56
14
|
|
57
15
|
# Sends an event up to SQS
|
58
16
|
#
|
@@ -61,25 +19,11 @@ module Conrad
|
|
61
19
|
client.send_message(queue_url: queue_url, message_body: event)
|
62
20
|
end
|
63
21
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
if secret_access_key.nil? || access_key_id.nil?
|
68
|
-
validate_implicit_credentials
|
69
|
-
|
70
|
-
@client = Aws::SQS::Client.new({ region: region }.compact)
|
71
|
-
else
|
72
|
-
@client = Aws::SQS::Client.new({
|
73
|
-
region: region,
|
74
|
-
access_key_id: access_key_id,
|
75
|
-
secret_access_key: secret_access_key
|
76
|
-
}.compact)
|
22
|
+
class << self
|
23
|
+
def client_class
|
24
|
+
Aws::SQS::Client
|
77
25
|
end
|
78
26
|
end
|
79
|
-
|
80
|
-
def validate_implicit_credentials
|
81
|
-
raise InvalidAwsCredentials unless Aws::CredentialProviderChain.new.resolve.set?
|
82
|
-
end
|
83
27
|
end
|
84
28
|
end
|
85
29
|
end
|
data/lib/conrad/errors.rb
CHANGED
@@ -9,6 +9,15 @@ module Conrad
|
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
12
|
+
# Error for responding with issues around kinesis credential creation
|
13
|
+
class InvalidAwsCredentials < Error
|
14
|
+
# :nodoc:
|
15
|
+
def to_s
|
16
|
+
'Must provide secret_access_key and access_key_id OR rely ' \
|
17
|
+
'on configured values in the running environment.'
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
12
21
|
# Error raised when the value of an event attribute is not of one of the
|
13
22
|
# allowed types
|
14
23
|
class ForbiddenValue < Error
|
data/lib/conrad/processors.rb
CHANGED
@@ -1 +1,8 @@
|
|
1
|
-
|
1
|
+
module Conrad
|
2
|
+
# :nodoc:
|
3
|
+
module Processors
|
4
|
+
autoload :AddTimestamp, 'conrad/processors/add_timestamp'
|
5
|
+
autoload :AddUUID, 'conrad/processors/add_uuid'
|
6
|
+
autoload :Envelope, 'conrad/processors/envelope'
|
7
|
+
end
|
8
|
+
end
|
data/lib/conrad/version.rb
CHANGED
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: conrad
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jonathon Anderson
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-03-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activemodel
|
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'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: aws-sdk
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -89,9 +103,14 @@ extra_rdoc_files: []
|
|
89
103
|
files:
|
90
104
|
- lib/conrad.rb
|
91
105
|
- lib/conrad/collector.rb
|
106
|
+
- lib/conrad/emitter_queue.rb
|
107
|
+
- lib/conrad/emitters.rb
|
108
|
+
- lib/conrad/emitters/amazon_base.rb
|
109
|
+
- lib/conrad/emitters/kinesis.rb
|
92
110
|
- lib/conrad/emitters/sqs.rb
|
93
111
|
- lib/conrad/emitters/stdout.rb
|
94
112
|
- lib/conrad/errors.rb
|
113
|
+
- lib/conrad/formatters.rb
|
95
114
|
- lib/conrad/formatters/json.rb
|
96
115
|
- lib/conrad/processor_stack.rb
|
97
116
|
- lib/conrad/processors.rb
|
@@ -120,7 +139,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
120
139
|
version: '0'
|
121
140
|
requirements: []
|
122
141
|
rubyforge_project:
|
123
|
-
rubygems_version: 2.7.
|
142
|
+
rubygems_version: 2.7.3
|
124
143
|
signing_key:
|
125
144
|
specification_version: 4
|
126
145
|
summary: Tool for auditing events.
|