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.
Binary file
Binary file
@@ -11,6 +11,7 @@ Gem::Specification.new do |spec|
11
11
  spec.homepage = 'https://gitlab.com/chiligumdev/chili_logger'
12
12
  spec.license = 'MIT'
13
13
  spec.required_ruby_version = Gem::Requirement.new('>= 2.3.0')
14
+ spec.add_dependency 'aws-sdk', '~> 2.9', '>= 2.9.0'
14
15
  spec.add_dependency 'bunny'
15
16
  spec.add_dependency 'httparty'
16
17
 
@@ -1,10 +1,14 @@
1
1
  require 'bunny'
2
- require 'errors/rabbitmq_error'
2
+ require 'brokers/sqs_broker'
3
3
 
4
4
  # class for centralizing Creative's logging logic
5
5
  class ChiliLogger
6
6
  # class that configures and manages the RabbitMQ client
7
7
  class RabbitBroker
8
+ def initialize(logging_error_handler)
9
+ @logging_error_handler = logging_error_handler
10
+ end
11
+
8
12
  def config(config)
9
13
  validate_config(config)
10
14
 
@@ -13,7 +17,7 @@ class ChiliLogger
13
17
  @ip = config[:ip]
14
18
  @port = config[:port]
15
19
  @exchange_name = config[:exchange_name]
16
- @routing_key = config[:routing_key]
20
+ @routing_key_overwriter = config[:routing_key_overwriter]
17
21
 
18
22
  connect
19
23
  end
@@ -21,15 +25,15 @@ class ChiliLogger
21
25
  def connect
22
26
  return if ChiliLogger.instance.deactivated
23
27
 
24
- @connection = Bunny.new("amqp://#{@user}:#{@password}@#{@ip}:#{@port}")
28
+ @connection = Bunny.new(connection_config)
25
29
  @connection.start
26
30
 
27
31
  @channel = @connection.create_channel
28
32
  @exchange = @channel.topic(@exchange_name, durable: true)
29
33
 
30
- # wraps errors in a ChiliLogger class, so it's easier for user to see that the problem happened in chili_logger gem
31
- rescue Bunny::Exception => e
32
- raise(ChiliLogger::RabbitMQError, e.message)
34
+ rescue StandardError => e
35
+ puts 'Could not connect to RabbitMQ due to the following error:'
36
+ puts e
33
37
  end
34
38
 
35
39
  def disconnect
@@ -40,25 +44,48 @@ class ChiliLogger
40
44
  return if ChiliLogger.instance.deactivated
41
45
 
42
46
  # if no routing_key was provided when configuring RabbitBroker, than use the one received by the method here
43
- # temporary solution so we can test, while we don't implement correct routing_keys in logstash/elasticsearch
44
- key = @routing_key || routing_key
47
+ # temporary solution so we can force configure ChiliLogger to use a specific routing_key
48
+ key = @routing_key_overwriter || routing_key
49
+ puts key
50
+ puts key
51
+ puts key
52
+ puts key
53
+ puts key
54
+ puts key
45
55
  @exchange.publish(message.to_json, routing_key: key)
56
+
57
+ rescue StandardError => e
58
+ @logging_error_handler.handle_error(e, message)
46
59
  end
47
60
 
48
61
  private
49
62
 
50
63
  def invalid_config_format_error
51
- 'The configuration object must include a Hash'
64
+ 'The configuration object must be a Hash'
52
65
  end
53
66
 
54
67
  def config_attr_error(attr)
55
68
  "The configuration object must include a ':#{attr}' attribute"
56
69
  end
57
70
 
71
+ def connection_config
72
+ # shouldn't try to recover connection,
73
+ # it may cause app in production to collapse if reconnection doesn't work or takes too many attempts!!!
74
+ recovery_attempts = 0
75
+
76
+ {
77
+ user: @user,
78
+ password: @password,
79
+ host: @ip,
80
+ port: @port,
81
+ recovery_attempts: recovery_attempts
82
+ }
83
+ end
84
+
58
85
  def validate_config(config)
59
86
  raise(ChiliLogger::ConfigError, invalid_config_format_error) unless config.is_a?(Hash)
60
87
 
61
- main_config_keys = %i[user password ip port exchange_name routing_key]
88
+ main_config_keys = %i[user password ip port exchange_name]
62
89
  main_config_keys.each { |key| raise(ChiliLogger::ConfigError, config_attr_error(key)) unless config[key] }
63
90
  end
64
91
  end
@@ -0,0 +1,61 @@
1
+ require 'aws-sdk'
2
+
3
+ # class for centralizing Creative's logging logic
4
+ class ChiliLogger
5
+ # module with classes using Amazon Web Services services
6
+ module AWS
7
+ # class that handles errors when message broker can't be reached, etc...
8
+ class SqsBroker
9
+ def initialize(config)
10
+ @sqs_config = validate_config(config)
11
+ @queue_name = config[:queue_name]
12
+ @default = ChiliLogger::Values::Default.new
13
+
14
+ @sqs = Aws::SQS::Client.new(@sqs_config)
15
+ end
16
+
17
+ def publish(message = @default.sqs_message)
18
+ message_body = { body: message }
19
+ queue_message = queue_message(message_body)
20
+
21
+ @sqs.send_message(queue_message)
22
+ end
23
+
24
+ private
25
+
26
+ def queue_message(message_body)
27
+ {
28
+ queue_url: queue_url(@queue_name),
29
+ message_body: message_body.to_json,
30
+ message_group_id: SecureRandom.hex(8).to_s,
31
+ message_deduplication_id: SecureRandom.hex(8).to_s
32
+ }
33
+ end
34
+
35
+ def queue_url(queue_name)
36
+ @sqs.get_queue_url(queue_name: queue_name).queue_url
37
+ end
38
+
39
+ def invalid_config_format_error
40
+ 'The :error_hanldler_config object must be a Hash'
41
+ end
42
+
43
+ def config_attr_error(attr)
44
+ "The configuration object must include a ':#{attr}' attribute"
45
+ end
46
+
47
+ def validate_config(config)
48
+ raise(ChiliLogger::ConfigError, invalid_config_format_error) unless config.is_a?(Hash)
49
+
50
+ main_config_keys = %i[region access_key_id secret_access_key queue_name]
51
+ main_config_keys.each { |key| raise(ChiliLogger::ConfigError, config_attr_error(key)) unless config[key] }
52
+
53
+ {
54
+ region: config[:region],
55
+ access_key_id: config[:access_key_id],
56
+ secret_access_key: config[:secret_access_key]
57
+ }
58
+ end
59
+ end
60
+ end
61
+ end
@@ -1,8 +1,14 @@
1
1
  require 'chili_logger/version'
2
2
  require 'current_log_accessor'
3
- require 'errors/config_error'
3
+ require 'errors/error_messages/config_error'
4
+ require 'errors/logging_error_handler/logging_error_handler'
4
5
  require 'brokers/rabbit_broker'
5
6
  require 'message_writer/message_writer'
7
+ require 'brokers/sqs_broker'
8
+ require 'helpers/values/default'
9
+ require 'helpers/values/type_uniformizer/desc'
10
+ require 'helpers/values/type_uniformizer/user'
11
+ require 'helpers/values/type_uniformizer/main_content'
6
12
  require 'singleton'
7
13
 
8
14
  # class for centralizing Creative's logging logic
@@ -13,9 +19,17 @@ class ChiliLogger
13
19
  # initialize it with ChiliLogger.instance
14
20
  include Singleton
15
21
 
22
+ def initialize
23
+ @default = ChiliLogger::Values::Default.new
24
+ @user_uniformizer = ChiliLogger::Values::TypeUniformizer::User.new
25
+ @desc_uniformizer = ChiliLogger::Values::TypeUniformizer::Desc.new
26
+ @main_content_uniformizer = ChiliLogger::Values::TypeUniformizer::MainContent.new
27
+ end
28
+
16
29
  def config(config)
17
30
  @deactivated = config[:deactivated] || false # ChilLogger can be deactivated for test environents
18
31
 
32
+ config_logging_error_handler(config)
19
33
  config_msg_writer(config)
20
34
  config_msg_broker(config)
21
35
 
@@ -26,25 +40,40 @@ class ChiliLogger
26
40
  @current_log_accessor
27
41
  end
28
42
 
29
- def start_new_log(new_desc = nil, new_agent = nil, new_main_content = nil)
43
+ def start_new_log(**options)
30
44
  current_log.clear_log_info
31
45
 
32
- current_log.overwrite_desc(new_desc)
33
- current_log.overwrite_agent(new_agent)
34
- current_log.overwrite_main_content(new_main_content)
46
+ current_log.update_desc(options[:desc])
47
+ current_log.update_user(options[:user])
48
+ current_log.update_main_content(options[:main_content])
35
49
 
36
50
  current_log
37
51
  end
38
52
 
39
- def publish_instant_log(desc, agent, main_content)
40
- message = @msg_writer.write(desc, agent, main_content)
41
- routing_key = @msg_writer.write_description_tag(desc)
53
+ def publish_instant_log(**options)
54
+ # enforces that all attributes have valid primitive types
55
+ if options
56
+ options[:desc] = @desc_uniformizer.desc(options[:desc])
57
+ options[:user] = @user_uniformizer.user(options[:user])
58
+ options[:main_content] = @main_content_uniformizer.main_content(options[:main_content])
59
+ end
60
+
61
+ message = @msg_writer.write(options)
62
+ routing_key = @msg_writer.write_description_tag(options[:desc])
42
63
 
43
64
  @msg_broker.publish(message, routing_key)
44
65
  end
45
66
 
46
67
  private
47
68
 
69
+ def config_logging_error_handler(general_config)
70
+ return @logging_error_handler = nil if @deactivated
71
+
72
+ fallback_name = general_config[:fallback_broker]
73
+ fallback_config = general_config[:fallback_broker_config]
74
+ @logging_error_handler = LoggingErrorHandler.new(fallback_name, fallback_config)
75
+ end
76
+
48
77
  def config_msg_writer(general_config)
49
78
  msg_writer_config = {
50
79
  env: general_config[:log_env],
@@ -56,12 +85,17 @@ class ChiliLogger
56
85
  @msg_writer = MessageWriter.new(msg_writer_config)
57
86
  end
58
87
 
59
- def config_msg_broker(config)
60
- msg_broker_name = config[:msg_broker_name] || :rabbitmq
61
- msg_broker_config = config[:msg_broker_config] || {}
88
+ def config_msg_broker(general_config)
89
+ msg_broker_name = general_config[:msg_broker_name] || @default.msg_broker
90
+ msg_broker_config = general_config[:msg_broker_config] || @default.msg_broker_config
62
91
  @msg_broker = supported_msg_brokers[msg_broker_name.to_sym]
63
92
  raise(ConfigError, broker_name_error(msg_broker_name)) unless @msg_broker
64
93
 
94
+ # TODO: implement MessageBroker class, an interface between ChiliLogger and possible brokers.
95
+ # TODO: add "supported_msg_broker", "broker_name_error" and "return @msg_broker if @deactivated" to MessageBroker
96
+ # prevents broker from even starting connection if ChiliLogger is deactivated
97
+ return @msg_broker if @deactivated
98
+
65
99
  @msg_broker.config(msg_broker_config)
66
100
  end
67
101
 
@@ -71,7 +105,7 @@ class ChiliLogger
71
105
 
72
106
  def supported_msg_brokers
73
107
  {
74
- rabbitmq: RabbitBroker.new
108
+ rabbitmq: RabbitBroker.new(@logging_error_handler)
75
109
  }
76
110
  end
77
111
  end
@@ -1,3 +1,3 @@
1
1
  class ChiliLogger
2
- VERSION = '0.0.1'
2
+ VERSION = "0.0.8"
3
3
  end
@@ -1,4 +1,8 @@
1
1
  require 'message_writer/message_writer'
2
+ require 'helpers/values/default'
3
+ require 'helpers/values/type_uniformizer/desc'
4
+ require 'helpers/values/type_uniformizer/main_content'
5
+ require 'helpers/values/type_uniformizer/user'
2
6
  require 'byebug'
3
7
 
4
8
  # class for centralizing Creative's logging logic
@@ -8,14 +12,16 @@ class ChiliLogger
8
12
  def initialize(msg_broker, msg_writer)
9
13
  @msg_broker = msg_broker
10
14
  @msg_writer = msg_writer
15
+ @default = ChiliLogger::Values::Default.new
16
+ @user_uniformizer = ChiliLogger::Values::TypeUniformizer::User.new
17
+ @desc_uniformizer = ChiliLogger::Values::TypeUniformizer::Desc.new
18
+ @main_content_uniformizer = ChiliLogger::Values::TypeUniformizer::MainContent.new
11
19
  end
12
20
 
13
- def publish(new_desc = nil, new_agent = nil, new_main_content = nil)
14
- overwrite_desc(new_desc) if new_desc
15
- overwrite_agent(new_agent) if new_agent
16
- overwrite_main_content(new_main_content) if new_main_content
21
+ def publish(**options)
22
+ update_current_log(options)
17
23
 
18
- message = @msg_writer.write(desc, agent, main_content)
24
+ message = @msg_writer.write(desc: desc, user: user, main_content: main_content)
19
25
  routing_key = @msg_writer.write_description_tag(desc)
20
26
 
21
27
  @msg_broker.publish(message, routing_key)
@@ -23,98 +29,116 @@ class ChiliLogger
23
29
  end
24
30
 
25
31
  # ACCESSOR METHODS BELOW
26
- # all relevant infos for the current log are stored in thread variables,
27
- # so they can be accessed anywhere (controllers, models, tasks, etc...)
28
- def agent
29
- Thread.current[:current_log_agent] ||= 'not_specified'
32
+ # current log infos are stored in thread variables, so they can be accessed anywhere(controllers, models, tasks...)
33
+ def user
34
+ Thread.current[:current_log_user] ||= @default.user
30
35
  end
31
36
 
32
- def overwrite_agent(agent)
33
- Thread.current[:current_log_agent] = agent
34
- agent
37
+ def update_user(new_user)
38
+ return Thread.current[:current_log_user] = nil if new_user.nil?
39
+
40
+ uniformized_user = @user_uniformizer.user(new_user)
41
+ Thread.current[:current_log_user] = user.merge(uniformized_user)
35
42
  end
36
43
 
37
44
  def desc
38
- Thread.current[:current_log_desc] ||= { type: 'not_specified', service: 'not_specified', action: 'not_specified' }
45
+ Thread.current[:current_log_desc] ||= @default.desc
39
46
  end
40
47
 
41
- def overwrite_type(new_type_name)
42
- desc[:type] = new_type_name || 'not_specified'
48
+ def update_type(new_type_name)
49
+ desc[:type] = @desc_uniformizer.type(new_type_name)
43
50
  end
44
51
 
45
- def overwrite_service(new_service_name)
46
- desc[:service] = new_service_name || 'not_specified'
52
+ def update_service(new_service_name)
53
+ desc[:service] = @desc_uniformizer.service(new_service_name)
47
54
  end
48
55
 
49
- def overwrite_action(new_action_name)
50
- desc[:action] = new_action_name || 'not_specified'
56
+ def update_action(new_action_name)
57
+ desc[:action] = @desc_uniformizer.action(new_action_name)
51
58
  end
52
59
 
53
- def overwrite_desc(new_desc)
60
+ def update_desc(new_desc)
54
61
  return Thread.current[:current_log_desc] = nil if new_desc.nil?
55
- return unless new_desc.is_a?(Hash)
56
62
 
57
- overwrite_desc_items(new_desc, valid_desc_items)
58
- desc
63
+ uniformized_desc = @desc_uniformizer.desc(new_desc)
64
+ Thread.current[:current_log_desc] = desc.merge(uniformized_desc)
59
65
  end
60
66
 
61
67
  def main_content
62
- Thread.current[:current_log_main_content] ||= {}
68
+ Thread.current[:current_log_main_content] ||= @default.main_content
63
69
  end
64
70
 
65
- def overwrite_main_content(new_main_content)
66
- return Thread.current[:current_log_main_content] = nil if new_main_content.nil?
67
- return unless new_main_content.is_a?(Hash)
71
+ def update_main_content(new_content)
72
+ return Thread.current[:current_log_main_content] = nil if new_content.nil?
73
+
74
+ uniform_content = @main_content_uniformizer.main_content(new_content)
75
+ uniform_recs = @main_content_uniformizer.modified_records(uniform_content[:modified_records])
76
+ uniform_errors = @main_content_uniformizer.errors(uniform_content[:errors])
68
77
 
69
- Thread.current[:current_log_main_content] = new_main_content
78
+ # only overwrite if key was explicitly set
79
+ main_content[:modified_records] = uniform_recs if uniform_content.key?(:modified_records)
80
+ main_content[:errors] = uniform_errors if uniform_content.key?(:errors)
70
81
  end
71
82
 
72
83
  def add_to_main_content(new_content)
73
- return unless new_content.is_a?(Hash)
84
+ uniform_content = @main_content_uniformizer.main_content(new_content)
85
+ uniform_recs = uniform_content[:modified_records]
86
+ uniform_errs = uniform_content[:errors]
74
87
 
75
- Thread.current[:current_log_main_content] = main_content.merge(new_content)
88
+ # only overwrite if key was explicitly set
89
+ main_content[:modified_records] = modified_records.merge(uniform_recs) if uniform_recs
90
+ main_content[:errors] = errors + uniform_errs if uniform_errs
76
91
  end
77
92
 
78
93
  def modified_records
79
- main_content[:modified_records] ||= {}
94
+ main_content[:modified_records] ||= @default.modified_records
80
95
  end
81
96
 
82
- def overwrite_modified_records(modified_records)
83
- return Thread.current[:current_log_main_content] = nil if modified_records.nil?
84
- return unless modified_records.is_a?(Hash)
97
+ def overwrite_modified_records(new_mod_recs)
98
+ return main_content[:modified_records] = nil if new_mod_recs.nil?
85
99
 
86
- main_content[:modified_records] = modified_records
100
+ uniformized_recs = @main_content_uniformizer.modified_records(new_mod_recs)
101
+ main_content[:modified_records] = uniformized_recs
87
102
  end
88
103
 
89
- def add_modified_record(table_name, modified_record_hash)
90
- return unless table_name
104
+ def add_modified_record(table_name, new_mod_rec)
91
105
  return unless table_name.is_a?(String)
92
- return unless modified_record_hash
93
- return unless modified_record_hash.is_a?(Hash)
94
106
 
107
+ uniformized_rec = @main_content_uniformizer.modified_record(new_mod_rec)
95
108
  modified_records[table_name] ||= []
96
- modified_records[table_name] = modified_records[table_name].push(modified_record_hash)
109
+ modified_records[table_name] = modified_records[table_name].push(uniformized_rec)
97
110
  end
98
111
 
99
- def clear_log_info
100
- overwrite_desc(nil)
101
- overwrite_agent(nil)
102
- overwrite_main_content(nil)
112
+ def errors
113
+ main_content[:errors] ||= @default.log_errors
103
114
  end
104
115
 
105
- private
116
+ def overwrite_errors(new_errors)
117
+ return main_content[:errors] = nil if new_errors.nil?
106
118
 
107
- def valid_desc_items
108
- %i[type service action]
119
+ uniformized_errors = @main_content_uniformizer.errors(new_errors)
120
+ main_content[:errors] = uniformized_errors
109
121
  end
110
122
 
111
- def overwrite_desc_items(new_desc, item_names)
112
- item_names.each do |item_name|
113
- next unless new_desc.keys.include?(item_name)
123
+ def add_error(error)
124
+ uniformized_error = @main_content_uniformizer.error(error)
125
+
126
+ main_content[:errors] = errors.push(uniformized_error)
127
+ errors
128
+ end
129
+
130
+ def clear_log_info
131
+ update_desc(nil)
132
+ update_user(nil)
133
+ update_main_content(nil)
134
+ end
135
+
136
+ private
114
137
 
115
- item = new_desc[item_name]
116
- desc[item_name] = item || 'not_specified'
117
- end
138
+ def update_current_log(options)
139
+ update_desc(options[:desc]) if options[:desc]
140
+ update_user(options[:user]) if options[:user]
141
+ update_main_content(options[:main_content]) if options[:main_content]
118
142
  end
119
143
  end
120
144
  end