conrad 2.3.1 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b41619922ba6057aff0e0c1132b13ebd674e897f6edd141a7f4fc2ce6c8fad70
4
- data.tar.gz: 381de5251326c319d50f1c4d6d2af93a1b00ffca594f5b3e423647c105cfb75a
3
+ metadata.gz: 5bea95c17248374dd5931d1de26433e47f3e47b46ef262ef89e86e8fe516040a
4
+ data.tar.gz: c1a1388a3ec0d4fcd8002a4b185f336950c92e037db2a831e8fa3cfee47627e9
5
5
  SHA512:
6
- metadata.gz: f1d65e6a2141b159ee97077ecaa4cb9917edc060b5611736a17146e7f37daea7ce88984380d89ad6ddba30ef55ba3d1c7c81be717506bb1eafa1029e7c176f1a
7
- data.tar.gz: 1455dbf8b1ac7b2a39c78c61fd000508d2cb222fa75c13aac7105f4a296a9667ccf2bc102bd9692583da303dacd8cee2aad03b28d4f68b431f503acb01bcf5e8
6
+ metadata.gz: 3cfc946e370b048f352936240516546ba5677d1e2bea493a19c8f537c93f358ad2198f33fb6ab02e6b9d590ad2169a8410fef0ce815a21b39d0b8ef5f7e0c32f
7
+ data.tar.gz: ba69a3a6d255e10700a7f6bc57672bfa3b06d51dbe2ffdf88ed6a24ebb0f536c16bf70489d9a892031b68daecc3d2c2f477d0706a42b3242b47f4262dadf9995
data/lib/conrad.rb CHANGED
@@ -1,8 +1,25 @@
1
- Gem.find_files('conrad/processors/*.rb').each { |file| require file }
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
@@ -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
- if emit_as_batch?
142
- record_events_as_batch
143
- else
144
- record_individual_events
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
- emitter.call(events)
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
- begin
183
- emitter.call(event)
184
- rescue StandardError => e
185
- write_log(:error, e)
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
@@ -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
- attr_reader :queue_url
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
- private
65
-
66
- def create_client(region:, access_key_id:, secret_access_key:)
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
@@ -0,0 +1,6 @@
1
+ module Conrad
2
+ # :nodoc:
3
+ module Formatters
4
+ autoload :JSON, 'conrad/formatters/json'
5
+ end
6
+ end
@@ -1 +1,8 @@
1
- Dir['conrad/processors/*.rb'].each { |file| require file }
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
@@ -1,5 +1,5 @@
1
1
  # :nodoc:
2
2
  module Conrad
3
3
  # :nodoc:
4
- VERSION = '2.3.1'.freeze
4
+ VERSION = '2.4.0'.freeze
5
5
  end
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.3.1
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-01-28 00:00:00.000000000 Z
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.6
142
+ rubygems_version: 2.7.3
124
143
  signing_key:
125
144
  specification_version: 4
126
145
  summary: Tool for auditing events.