event_tracer 0.3.2 → 0.4.3

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
  SHA256:
3
- metadata.gz: '002520584662d6b31ce2f05310a70c4fb8af37c3c865f6bdf2b8ebc44bf16654'
4
- data.tar.gz: daa3fc169b3daa2771adb7d832872c055b723dbe25d28fff4ba24c618f2b54a2
3
+ metadata.gz: f13a5619d77a274784538f42abb8121d19f91fc24f4d2def934e9430aa232410
4
+ data.tar.gz: f281a954af8e3d1e38fc6640ca9ca971ae46b2ea567f80b6d569a4e432fe117f
5
5
  SHA512:
6
- metadata.gz: '038e91c1d03b17070b97c3c170d73992d4050b9cee39f3529fc712a2cfda324d8afdfb10013f6a6838176966f94d6dd17b5f4851a62af6bdc0e6c8ea2b2e95b1'
7
- data.tar.gz: fdeb28420163369840b82b0a56e6bd83a638fe4c5e7069f280c6807d8f9ad00b9044c642263fc89391628c110af8e527596c2e86c2b759a50691c3d13a7390c5
6
+ metadata.gz: f24211641d5b8f3ae7e6006122b2f8dc3af0403249e8149dcc64caf479d07cf6b7d96aae8ae7295a048935c1a9b38fa769a2f1ea6cdce2243f8a0bb7bea90cbe
7
+ data.tar.gz: c5c85f05628fbeb39878f2ba9dd04a87fb0d02f284f09b827cedf69454154d7a8db0d3d224d85456d01c4152f28d661bf4d5eda7ec9d943ed2d756e38611cf6f
@@ -1,4 +1,3 @@
1
- require_relative '../event_tracer'
2
1
  require_relative './basic_decorator'
3
2
 
4
3
  # NOTES
@@ -21,9 +20,11 @@ module EventTracer
21
20
  DEFAULT_METRIC_TYPE = :increment_counter
22
21
  DEFAULT_COUNTER = 1
23
22
 
23
+ attr_reader :allowed_tags
24
+
24
25
  def initialize(decoratee, allowed_tags: [])
25
26
  super(decoratee)
26
- @allowed_tags = allowed_tags
27
+ @allowed_tags = allowed_tags.freeze
27
28
  end
28
29
 
29
30
  LOG_TYPES.each do |log_type|
@@ -53,7 +54,6 @@ module EventTracer
53
54
 
54
55
  private
55
56
 
56
- attr_reader :decoratee, :allowed_tags
57
57
  alias_method :appsignal, :decoratee
58
58
 
59
59
  def valid_args?(metrics)
@@ -1,4 +1,3 @@
1
- require_relative '../event_tracer'
2
1
  require_relative './basic_decorator'
3
2
  require 'json'
4
3
 
@@ -15,7 +14,6 @@ module EventTracer
15
14
 
16
15
  private
17
16
 
18
- attr_reader :logger, :decoratee
19
17
  alias_method :logger, :decoratee
20
18
 
21
19
  # EventTracer ensures action & message is always populated
@@ -24,5 +24,8 @@ module EventTracer
24
24
  LogResult.new(false, message)
25
25
  end
26
26
 
27
+ private
28
+
29
+ attr_reader :decoratee
27
30
  end
28
31
  end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'time'
4
+
5
+ module EventTracer
6
+ class BufferedLogger
7
+ def initialize(log_processor:, worker:, buffer: Buffer.new(buffer_size: 0))
8
+ @buffer = buffer
9
+ @worker = worker
10
+ @log_processor = log_processor
11
+ end
12
+
13
+ EventTracer::LOG_TYPES.each do |log_type|
14
+ define_method log_type do |**args|
15
+ save_message log_type, **args
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ attr_reader :buffer, :log_processor, :worker
22
+
23
+ def save_message(log_type, action:, message:, **args)
24
+ payload = log_processor.call(log_type, action: action, message: message, args: args)
25
+
26
+ unless buffer.add(payload)
27
+ all_payloads = buffer.flush + [payload]
28
+ execute_payload(all_payloads)
29
+ end
30
+
31
+ LogResult.new(true)
32
+ end
33
+
34
+ def execute_payload(payloads)
35
+ worker.perform_async(payloads)
36
+ rescue JSON::GeneratorError => e
37
+ filtered_payloads = filter_invalid_data(payloads)
38
+
39
+ EventTracer.warn(
40
+ loggers: %i(base),
41
+ action: self.class.name,
42
+ app: EventTracer::Config.config.app_name,
43
+ error: e.class.name,
44
+ message: e.message,
45
+ payload: payloads - filtered_payloads
46
+ )
47
+
48
+ worker.perform_async(filtered_payloads) if filtered_payloads.any?
49
+ end
50
+
51
+ def filter_invalid_data(payloads)
52
+ payloads.select { |payload| payload.to_json rescue false }
53
+ end
54
+ end
55
+ end
@@ -5,6 +5,10 @@ module EventTracer
5
5
  extend Dry::Configurable
6
6
 
7
7
  setting :app_name, default: 'app_name'
8
+
9
+ # TODO: switch to namespace in v1.0
8
10
  setting :dynamo_db_table_name, default: 'logs'
11
+ setting :dynamo_db_client
12
+ setting :dynamo_db_queue_name, default: 'low'
9
13
  end
10
14
  end
@@ -1,4 +1,3 @@
1
- require_relative '../event_tracer'
2
1
  require_relative './basic_decorator'
3
2
  # NOTES
4
3
  # Datadog interface to send our usual actions
@@ -23,9 +22,11 @@ module EventTracer
23
22
  DEFAULT_METRIC_TYPE = :count
24
23
  DEFAULT_COUNTER = 1
25
24
 
25
+ attr_reader :allowed_tags
26
+
26
27
  def initialize(decoratee, allowed_tags: [])
27
28
  super(decoratee)
28
- @allowed_tags = allowed_tags
29
+ @allowed_tags = allowed_tags.freeze
29
30
  end
30
31
 
31
32
  LOG_TYPES.each do |log_type|
@@ -55,7 +56,6 @@ module EventTracer
55
56
 
56
57
  private
57
58
 
58
- attr_reader :decoratee, :allowed_tags
59
59
  alias_method :datadog, :decoratee
60
60
 
61
61
  def valid_args?(metrics)
@@ -0,0 +1,14 @@
1
+ module EventTracer
2
+ module DynamoDB
3
+ class Client
4
+ class << self
5
+ extend Gem::Deprecate
6
+
7
+ def call
8
+ Aws::DynamoDB::Client.new
9
+ end
10
+ deprecate :call, 'EventTracer::Config.config.dynamo_db_client', 2021, 12
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,15 @@
1
+ module EventTracer
2
+ module DynamoDB
3
+ class DefaultProcessor
4
+ def call(log_type, action:, message:, args:)
5
+ args.merge(
6
+ timestamp: Time.now.utc.iso8601(6),
7
+ action: action,
8
+ message: message,
9
+ log_type: log_type,
10
+ app: EventTracer::Config.config.app_name
11
+ )
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'time'
4
+ require_relative 'client'
5
+ require_relative 'worker'
6
+ require_relative 'default_processor'
7
+
8
+ module EventTracer
9
+ module DynamoDB
10
+ class Logger < BufferedLogger
11
+ def initialize(buffer: Buffer.new(buffer_size: 0), log_processor: DefaultProcessor.new)
12
+ super(buffer: buffer, log_processor: log_processor, worker: Worker)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'client'
4
+
5
+ begin
6
+ require 'sidekiq'
7
+ require 'aws-sdk-dynamodb'
8
+ rescue LoadError => e
9
+ puts "Please add the missing gem into your app Gemfile: #{e.message}"
10
+ raise
11
+ end
12
+
13
+ module EventTracer
14
+ module DynamoDB
15
+ class Worker
16
+ include ::Sidekiq::Worker
17
+
18
+ sidekiq_options retry: 1, queue: EventTracer::Config.config.dynamo_db_queue_name
19
+
20
+ # See https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/DynamoDB/Client.html#batch_write_item-instance_method
21
+ MAX_DYNAMO_DB_ITEM_PER_REQUEST = 25
22
+
23
+ def initialize(client = nil)
24
+ @config = EventTracer::Config.config
25
+ @client = client || @config.dynamo_db_client || Client.call
26
+ end
27
+
28
+ def perform(items)
29
+ wrap(items).each_slice(MAX_DYNAMO_DB_ITEM_PER_REQUEST) do |batch|
30
+ data = batch.map do |item|
31
+ { put_request: { item: clean_empty_values(item) } }
32
+ end
33
+
34
+ client.batch_write_item(
35
+ request_items: { config.dynamo_db_table_name => data }
36
+ )
37
+
38
+ rescue Aws::DynamoDB::Errors::ServiceError => e
39
+ EventTracer.error(
40
+ loggers: %i(base),
41
+ action: 'DynamoDBWorker',
42
+ app: EventTracer::Config.config.app_name,
43
+ error: e.class.name,
44
+ message: e.message
45
+ )
46
+ end
47
+ end
48
+
49
+ private
50
+
51
+ attr_reader :client, :config
52
+
53
+ def wrap(items)
54
+ # NOTE: This allows us to handle either buffered or unbuffered payloads
55
+ if items.is_a?(Hash)
56
+ [items]
57
+ else
58
+ Array(items)
59
+ end
60
+ end
61
+
62
+ # dynamo can't serialise empty strings/ non-zero numerics
63
+ def clean_empty_values(data)
64
+ data.delete_if do |_key, value|
65
+ case value
66
+ when Hash
67
+ clean_empty_values(value)
68
+ false
69
+ when String then value.empty?
70
+ else false
71
+ end
72
+ end
73
+ end
74
+
75
+ end
76
+ end
77
+ end
@@ -1,3 +1,3 @@
1
1
  module EventTracer
2
- VERSION = '0.3.2'.freeze
2
+ VERSION = '0.4.3'.freeze
3
3
  end
data/lib/event_tracer.rb CHANGED
@@ -3,7 +3,7 @@ require 'event_tracer/log_result'
3
3
 
4
4
  module EventTracer
5
5
 
6
- LOG_TYPES ||= %i(info warn error)
6
+ LOG_TYPES = %i(info warn error)
7
7
 
8
8
  @loggers = {}
9
9
 
@@ -70,4 +70,4 @@ module EventTracer
70
70
  end
71
71
 
72
72
  project_root = File.dirname(File.absolute_path(__FILE__))
73
- Dir.glob("#{project_root}/event_tracer/*") {|file| require file}
73
+ Dir.glob("#{project_root}/event_tracer/*.rb") {|file| require file}
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: event_tracer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.2
4
+ version: 0.4.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - melvrickgoh
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-10-11 00:00:00.000000000 Z
11
+ date: 2022-01-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby
@@ -93,12 +93,13 @@ files:
93
93
  - lib/event_tracer/base_logger.rb
94
94
  - lib/event_tracer/basic_decorator.rb
95
95
  - lib/event_tracer/buffer.rb
96
+ - lib/event_tracer/buffered_logger.rb
96
97
  - lib/event_tracer/config.rb
97
98
  - lib/event_tracer/datadog_logger.rb
98
- - lib/event_tracer/dynamo_db_client.rb
99
- - lib/event_tracer/dynamo_db_default_processor.rb
100
- - lib/event_tracer/dynamo_db_log_worker.rb
101
- - lib/event_tracer/dynamo_db_logger.rb
99
+ - lib/event_tracer/dynamo_db/client.rb
100
+ - lib/event_tracer/dynamo_db/default_processor.rb
101
+ - lib/event_tracer/dynamo_db/logger.rb
102
+ - lib/event_tracer/dynamo_db/worker.rb
102
103
  - lib/event_tracer/log_result.rb
103
104
  - lib/event_tracer/version.rb
104
105
  homepage: https://github.com/melvrickgoh/event_tracer
@@ -121,7 +122,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
121
122
  - !ruby/object:Gem::Version
122
123
  version: '0'
123
124
  requirements: []
124
- rubygems_version: 3.2.28
125
+ rubygems_version: 3.2.3
125
126
  signing_key:
126
127
  specification_version: 4
127
128
  summary: Thin wrapper for formatted logging/ metric services to be used as a single
@@ -1,7 +0,0 @@
1
- module EventTracer
2
- class DynamoDBClient
3
- def self.call
4
- Aws::DynamoDB::Client.new
5
- end
6
- end
7
- end
@@ -1,13 +0,0 @@
1
- module EventTracer
2
- class DynamoDBDefaultProcessor
3
- def call(log_type, action:, message:, args:)
4
- args.merge(
5
- timestamp: Time.now.utc.iso8601(6),
6
- action: action,
7
- message: message,
8
- log_type: log_type,
9
- app: EventTracer::Config.config.app_name
10
- )
11
- end
12
- end
13
- end
@@ -1,68 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'dynamo_db_client'
4
-
5
- begin
6
- require 'sidekiq'
7
- require 'aws-sdk-dynamodb'
8
- rescue LoadError => e
9
- puts "Please add the missing gem into your app Gemfile: #{e.message}"
10
- raise
11
- end
12
-
13
- module EventTracer
14
- class DynamoDBLogWorker
15
- include ::Sidekiq::Worker
16
-
17
- sidekiq_options retry: 1, queue: 'low'
18
-
19
- # See https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/DynamoDB/Client.html#batch_write_item-instance_method
20
- MAX_DYNAMO_DB_ITEM_PER_REQUEST = 25
21
-
22
- def perform(items)
23
- wrap(items).each_slice(MAX_DYNAMO_DB_ITEM_PER_REQUEST) do |batch|
24
- data = batch.map do |item|
25
- { put_request: { item: clean_empty_values(item) } }
26
- end
27
-
28
- EventTracer::DynamoDBClient.call.batch_write_item(
29
- request_items: { EventTracer::Config.config.dynamo_db_table_name => data }
30
- )
31
-
32
- rescue Aws::DynamoDB::Errors::ServiceError => e
33
- EventTracer.error(
34
- loggers: %i(base),
35
- action: 'DynamoDBLogWorker',
36
- app: EventTracer::Config.config.app_name,
37
- error: e.class.name,
38
- message: e.message
39
- )
40
- end
41
- end
42
-
43
- private
44
-
45
- def wrap(items)
46
- # NOTE: This allows us to handle either buffered or unbuffered payloads
47
- if items.is_a?(Hash)
48
- [items]
49
- else
50
- Array(items)
51
- end
52
- end
53
-
54
- # dynamo can't serialise empty strings/ non-zero numerics
55
- def clean_empty_values(data)
56
- data.delete_if do |_key, value|
57
- case value
58
- when Hash
59
- clean_empty_values(value)
60
- false
61
- when String then value.empty?
62
- else false
63
- end
64
- end
65
- end
66
-
67
- end
68
- end
@@ -1,35 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'time'
4
- require_relative 'dynamo_db_client'
5
-
6
- module EventTracer
7
- class DynamoDBLogger
8
- def initialize(buffer: Buffer.new(buffer_size: 0), log_processor: EventTracer::DynamoDBDefaultProcessor.new)
9
- @buffer = buffer
10
- @log_processor = log_processor
11
- end
12
-
13
- EventTracer::LOG_TYPES.each do |log_type|
14
- define_method log_type do |**args|
15
- save_message log_type, **args
16
- end
17
- end
18
-
19
- private
20
-
21
- attr_reader :buffer, :log_processor
22
-
23
- def save_message(log_type, action:, message:, **args)
24
- payload = log_processor.call(log_type, action: action, message: message, args: args)
25
-
26
- unless buffer.add(payload)
27
- all_payloads = buffer.flush + [payload]
28
- DynamoDBLogWorker.perform_async(all_payloads)
29
- end
30
-
31
- LogResult.new(true)
32
- end
33
-
34
- end
35
- end