chili_logger 0.0.1 → 0.0.8

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.
@@ -0,0 +1,54 @@
1
+ require 'brokers/sqs_broker'
2
+ require 'errors/error_messages/config_error'
3
+
4
+ # class for centralizing Creative's logging logic
5
+ class ChiliLogger
6
+ # class that handles errors when message broker can't be reached, etc...
7
+ class LoggingErrorHandler
8
+ def initialize(fallback_name, config)
9
+ raise(ChiliLogger::ConfigError, ':fallback_broker_config must be present and be a hash') unless config.is_a?(Hash)
10
+
11
+ fallback_name = fallback_name.to_sym if fallback_name
12
+ fallback_broker_class = supported_fallback_brokers[fallback_name]
13
+ unsupported_fallback_broker_error unless fallback_broker_class
14
+
15
+ @fallback_broker = fallback_broker_class.new(config)
16
+ end
17
+
18
+ def handle_error(error, log = nil)
19
+ message = message(error, log)
20
+ @fallback_broker.publish(message)
21
+ rescue StandardError => e
22
+ puts '
23
+ There was a problem with both the Message Broker and the Fallback Broker simultaneously.
24
+ To keep the application running and prevent downtime,
25
+ ChiliLogger will ignore this errors and discard the log it was currently trying to publish.
26
+ Please note that logs are being permanently lost.
27
+ '
28
+ puts e
29
+ end
30
+
31
+ private
32
+
33
+ def message(error, log)
34
+ {
35
+ error_type: error.class.name,
36
+ error_message: error.message,
37
+ log: log
38
+ }
39
+ end
40
+
41
+ def unsupported_fallback_broker_error
42
+ error_handlers = supported_fallback_brokers.keys.join(', ')
43
+ unsupported_err = ":error_handler must be present and have one of the following values: #{error_handlers}"
44
+
45
+ raise(ChiliLogger::ConfigError, unsupported_err)
46
+ end
47
+
48
+ def supported_fallback_brokers
49
+ {
50
+ aws_sqs: AWS::SqsBroker
51
+ }
52
+ end
53
+ end
54
+ end
@@ -1,16 +1,18 @@
1
1
  require 'yaml'
2
2
  require 'fileutils'
3
+ require 'helpers/values/default'
3
4
 
4
5
  # class for centralizing Creative's logging logic
5
6
  class ChiliLogger
6
7
  # class for keeping logs coverage up to date
7
8
  class CoverageWriter
8
9
  def self.write(desc, backtrace)
10
+ default = ChiliLogger::Values::Default.new
9
11
  coverage = read_file
10
12
 
11
- type = desc[:type]
12
- service = desc[:service]
13
- action = desc[:action]
13
+ type = desc[:type] || default.type
14
+ service = desc[:service] || default.service
15
+ action = desc[:action] || default.action
14
16
  keys = [type, service, action]
15
17
 
16
18
  coverage = add_nested_value(coverage, keys, backtrace)
@@ -18,17 +20,6 @@ class ChiliLogger
18
20
  write_file(coverage)
19
21
  end
20
22
 
21
- def self.add_nested_value(object, keys, final_value)
22
- return final_value if keys.empty?
23
-
24
- current_key = keys.first
25
- nested_object = object[current_key] || {}
26
- nested_keys = keys.drop(1)
27
- object[current_key] = add_nested_value(nested_object, nested_keys, final_value)
28
-
29
- object
30
- end
31
-
32
23
  def self.read_file
33
24
  file_exists = File.file?(file_path)
34
25
 
@@ -41,6 +32,19 @@ class ChiliLogger
41
32
  true
42
33
  end
43
34
 
35
+ # private class methods
36
+
37
+ def self.add_nested_value(object, keys, final_value)
38
+ return final_value if keys.empty?
39
+
40
+ current_key = keys.first
41
+ nested_object = object[current_key] || {}
42
+ nested_keys = keys.drop(1)
43
+ object[current_key] = add_nested_value(nested_object, nested_keys, final_value)
44
+
45
+ object
46
+ end
47
+
44
48
  def self.dir_name
45
49
  'log'
46
50
  end
@@ -52,5 +56,7 @@ class ChiliLogger
52
56
  def self.file_path
53
57
  File.join('.', dir_name, file_name)
54
58
  end
59
+
60
+ private_class_method :add_nested_value, :dir_name, :file_name, :file_path
55
61
  end
56
62
  end
@@ -0,0 +1,92 @@
1
+ # class for centralizing Creative's logging logic
2
+ class ChiliLogger
3
+ # module responsible for uniformization of values in ChiliLogger
4
+ module Values
5
+ # class for keeping all default values in a single place
6
+ class Default
7
+ def msg_broker
8
+ :rabbitmq
9
+ end
10
+
11
+ def msg_broker_config
12
+ {}
13
+ end
14
+
15
+ def user
16
+ {
17
+ cognito_id: undefined_string,
18
+ email: undefined_string,
19
+ company_cognito_id: undefined_string,
20
+ company_name: undefined_string,
21
+ ghost_user_cognito_id: undefined_string
22
+ }
23
+ end
24
+
25
+ def env
26
+ undefined_string
27
+ end
28
+
29
+ def layer
30
+ undefined_string
31
+ end
32
+
33
+ def type
34
+ undefined_string
35
+ end
36
+
37
+ def service
38
+ undefined_string
39
+ end
40
+
41
+ def action
42
+ undefined_string
43
+ end
44
+
45
+ def desc
46
+ { type: type, service: service, action: action }
47
+ end
48
+
49
+ def main_content
50
+ { modified_records: modified_records, errors: log_errors }
51
+ end
52
+
53
+ def modified_records
54
+ {}
55
+ end
56
+
57
+ def log_errors
58
+ []
59
+ end
60
+
61
+ def log_error
62
+ sentence1 = 'ChiliLogger received an unsupported type of error, so it replaced it with this generic string.'
63
+ sentence2 = ' Errors must be either a String or a descendant of the Exception class.'
64
+ sentence1 + sentence2
65
+ end
66
+
67
+ def server_url
68
+ undefined_string
69
+ end
70
+
71
+ def log
72
+ {}
73
+ end
74
+
75
+ def sqs_message
76
+ {
77
+ error_type: undefined_string,
78
+ error_message: undefined_string,
79
+ log: undefined_string
80
+ }
81
+ end
82
+
83
+ def invalid_string
84
+ 'invalid_format'
85
+ end
86
+
87
+ def undefined_string
88
+ 'not_specified'
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,64 @@
1
+ # class for centralizing Creative's logging logic
2
+ class ChiliLogger
3
+ # module responsible for uniformization of values in ChiliLogger
4
+ module Values
5
+ # class to enforce consistent typing of values across all classes
6
+ # this is important because of Elasticsearch. Check README, section ##read-before-contributing to know more about it
7
+ class TypeUniformizer
8
+ # responsible for uniformizing log's description primitive types
9
+ class Desc
10
+ def initialize
11
+ @default = ChiliLogger::Values::Default.new
12
+ end
13
+
14
+ def desc(desc)
15
+ return {} unless desc.is_a?(Hash)
16
+
17
+ uniformized_desc = {}
18
+ valid_desc_attrs.each do |attr_name|
19
+ # only overwrite if key was explicitly set in desc
20
+ next unless desc.key?(attr_name)
21
+
22
+ desc_attr = desc[attr_name]
23
+ desc_attr = @default.invalid_string unless valid_desc_attr_formats.include?(desc_attr.class.name)
24
+ desc_attr ||= @default.undefined_string # if type == nil
25
+ uniformized_desc[attr_name] = desc_attr
26
+ end
27
+
28
+ uniformized_desc
29
+ end
30
+
31
+ def type(type)
32
+ return @default.undefined_string if type.nil?
33
+ return @default.invalid_string unless type.is_a?(String)
34
+
35
+ type
36
+ end
37
+
38
+ def service(service)
39
+ return @default.undefined_string if service.nil?
40
+ return @default.invalid_string unless service.is_a?(String)
41
+
42
+ service
43
+ end
44
+
45
+ def action(action)
46
+ return @default.undefined_string if action.nil?
47
+ return @default.invalid_string unless action.is_a?(String)
48
+
49
+ action
50
+ end
51
+
52
+ private
53
+
54
+ def valid_desc_attrs
55
+ %i[type service action]
56
+ end
57
+
58
+ def valid_desc_attr_formats
59
+ %w[String NilClass]
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,62 @@
1
+ # class for centralizing Creative's logging logic
2
+ class ChiliLogger
3
+ # module responsible for uniformization of values in ChiliLogger
4
+ module Values
5
+ # class to enforce consistent typing of values across all classes, this is important because of Elasticsearch
6
+ # Check README, section ##read-before-contributing, to know more about it
7
+ class TypeUniformizer
8
+ # responsible for uniformizing the primitive types of a log's main_content
9
+ class MainContent
10
+ def initialize
11
+ @default = ChiliLogger::Values::Default.new
12
+ end
13
+
14
+ def main_content(content)
15
+ return {} unless content.is_a?(Hash)
16
+
17
+ uniformized_content = {}
18
+
19
+ if content.key?(:modified_records) # only overwrite if :modified_records was explicitly set in main_content
20
+ mod_recs = content[:modified_records]
21
+ uniformized_content[:modified_records] = modified_records(mod_recs)
22
+ end
23
+ # only overwrite if :errors was explicitly set in main_content
24
+ uniformized_content[:errors] = errors(content[:errors]) if content.key?(:errors)
25
+
26
+ uniformized_content
27
+ end
28
+
29
+ def modified_records(records)
30
+ return {} unless records.is_a?(Hash)
31
+
32
+ uniformized_recs = {}
33
+ # modified records should be a hash where each key points to an array of valid modified records
34
+ records.each do |key, val|
35
+ val_as_array = val.is_a?(Array) ? val : [].push(val)
36
+ uniformized_val = val_as_array.map { |record| modified_record(record) }
37
+ uniformized_recs[key.to_s] = uniformized_val
38
+ end
39
+
40
+ uniformized_recs
41
+ end
42
+
43
+ def modified_record(record)
44
+ record.is_a?(Hash) ? record : {}
45
+ end
46
+
47
+ def errors(errors)
48
+ return [] unless errors.is_a?(Array)
49
+
50
+ errors.map { |err| error(err) }
51
+ end
52
+
53
+ # a received error must be either a string or Exception descendent(it will be converted to a string)
54
+ def error(error)
55
+ error = error.inspect if error.class.ancestors.include?(Exception) # stringifies Exception descendents
56
+ error = @default.log_error unless error.is_a?(String)
57
+ error
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,43 @@
1
+ # class for centralizing Creative's logging logic
2
+ class ChiliLogger
3
+ # module responsible for uniformization of values in ChiliLogger
4
+ module Values
5
+ # class to enforce consistent typing of values across all classes
6
+ # this is important because of Elasticsearch. Check README, section ##read-before-contributing to know moreabout it
7
+ class TypeUniformizer
8
+ # responsible for uniformizing log's primitive types
9
+ class User
10
+ def initialize
11
+ @default = ChiliLogger::Values::Default.new
12
+ end
13
+
14
+ def user(user)
15
+ return {} unless user.is_a?(Hash)
16
+
17
+ uniformized_user = {}
18
+ valid_user_attrs.each do |attr_name|
19
+ # don't enforce typing compliance of attrs that weren't explicitly set in user
20
+ next unless user.key?(attr_name)
21
+
22
+ user_attr = user[attr_name]
23
+ user_attr = @default.invalid_string unless valid_user_attr_formats.include?(user_attr.class.name)
24
+ user_attr ||= @default.undefined_string # if type == nil
25
+ uniformized_user[attr_name] = user_attr.to_s
26
+ end
27
+
28
+ uniformized_user
29
+ end
30
+
31
+ private
32
+
33
+ def valid_user_attrs
34
+ %i[cognito_id email company_cognito_id company_name ghost_user_cognito_id]
35
+ end
36
+
37
+ def valid_user_attr_formats
38
+ %w[String NilClass Fixnum Bignum]
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -1,6 +1,5 @@
1
1
  require 'httparty'
2
- require 'logs_coverage/coverage_writer'
3
- require 'helpers/rails_backtrace_cleaner'
2
+ require 'helpers/logs_coverage/coverage_writer'
4
3
  require 'message_writer/aws_ops_metadata'
5
4
 
6
5
  # class for centralizing Creative's logging logic
@@ -1,5 +1,4 @@
1
- require 'logs_coverage/coverage_writer'
2
- require 'helpers/rails_backtrace_cleaner'
1
+ require 'helpers/logs_coverage/coverage_writer'
3
2
  require 'message_writer/aws_ops_metadata'
4
3
 
5
4
  # class for centralizing Creative's logging logic
@@ -7,30 +6,36 @@ class ChiliLogger
7
6
  # class for writing log messages
8
7
  class MessageWriter
9
8
  def initialize(config)
10
- @env = config[:env] || 'not_specified'
11
- @layer = config[:layer] || 'not_specified'
12
- @server_url = config[:server_url] || 'not_specified'
9
+ @default = ChiliLogger::Values::Default.new
10
+ @env = config[:env] || @default.env
11
+ @layer = config[:layer] || @default.layer
12
+ @server_url = config[:server_url] || @default.server_url
13
13
  @cloud_provider = config[:cloud_provider]
14
- @backtrace_cleaner = RailsBacktraceCleaner.new
15
14
  end
16
15
 
17
- def write(desc = {}, agent = 'not_specified', main_content = {})
16
+ def write(**options)
18
17
  return if ChiliLogger.instance.deactivated
19
18
 
20
- desc ||= {}
21
- main_content ||= {}
19
+ desc = options[:desc] || @default.desc
20
+ user = options[:user] || @default.user
21
+ main_content = options[:main_content] || @default.main_content
22
22
 
23
- main_content.merge!({ backtrace: @backtrace_cleaner.clean(caller) })
23
+ main_content[:backtrace] = clean_backtrace(caller)
24
24
  update_logs_coverage(desc, main_content)
25
- message_hash(desc, agent, main_content)
25
+ message_hash(desc: desc, user: user, main_content: main_content)
26
+ end
27
+
28
+ def clean_backtrace(backtrace)
29
+ backtrace.reject! { |line| line =~ %r{bundle\/gems} }
30
+ backtrace
26
31
  end
27
32
 
28
33
  def write_description_tag(desc)
29
34
  env = desc[:env] || @env
30
35
  layer = desc[:layer] || @layer
31
- type = desc[:type] || 'not_specified'
32
- service = desc[:service] || 'not_specified'
33
- action = desc[:action] || 'not_specified'
36
+ type = desc[:type] || @default.type
37
+ service = desc[:service] || @default.service
38
+ action = desc[:action] || @default.action
34
39
 
35
40
  "#{env}.#{layer}.#{type}.#{service}.#{action}"
36
41
  end
@@ -39,22 +44,23 @@ class ChiliLogger
39
44
 
40
45
  # uses message infos to keep logs_coverage up to date with what logs are being generated in the application
41
46
  def update_logs_coverage(desc, main_content)
42
- backtrace = main_content[:backtrace] || @backtrace_cleaner.clean(caller)
47
+ backtrace = main_content[:backtrace] || clean_backtrace(caller)
43
48
  CoverageWriter.write(desc, backtrace)
44
49
  end
45
50
 
46
51
  # rubocop:disable Metrics/MethodLength
47
- def message_hash(desc, agent, main_content)
52
+ def message_hash(**options)
53
+ desc = options[:desc]
48
54
  {
49
55
  desc: write_description_tag(desc),
50
56
  env: @env,
51
57
  layer: @layer,
52
- type: desc[:type] || 'not_specified',
53
- service: desc[:service] || 'not_specified',
54
- action: desc[:action] || 'not_specified',
55
- user_info: agent || 'not_specified',
58
+ type: desc[:type] || @default.type,
59
+ service: desc[:service] || @default.service,
60
+ action: desc[:action] || @default.action,
61
+ user: options[:user] || @default.undefined_string,
56
62
  timestamp: DateTime.now,
57
- "#{desc[:type]}": main_content || {},
63
+ "#{desc[:type]}": options[:main_content] || {},
58
64
  ops_metadata: write_ops_metadata
59
65
  }
60
66
  end
@@ -64,15 +70,18 @@ class ChiliLogger
64
70
  return unless @cloud_provider
65
71
 
66
72
  provider = @cloud_provider.is_a?(String) ? @cloud_provider.to_sym : @cloud_provider
73
+ cloud_ops_metadata = cloud_metadata[provider]
74
+ return unless cloud_ops_metadata
75
+
67
76
  {
68
77
  server_url: @server_url,
69
- cloud: cloud_metadata[provider]
78
+ cloud: cloud_ops_metadata.write
70
79
  }
71
80
  end
72
81
 
73
82
  def cloud_metadata
74
83
  {
75
- aws: AwsOpsMetadata.write
84
+ aws: AwsOpsMetadata
76
85
  }
77
86
  end
78
87
  end