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.
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