event_tracer 0.3.2 → 0.4.3

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: '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