chili_logger 0.0.1 → 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -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