railway-ipc 1.1.0 → 2.0.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f2a31b80fc9d4f13598bdc2fbd14c84c78360bd4adeb588bb63b3bb20c33a2de
4
- data.tar.gz: 2bfef85b0fbe56b0d66df365f8ffa5b7913b188658edbb63484aaa0138dfa6ba
3
+ metadata.gz: 11e49c11ff3e5815f7c8050ad5fcdfde1510cf7646d10cfa5d1104a5c1868422
4
+ data.tar.gz: 3fbdeab2e555f9c4b3402cf27e3b072d33c833f85659eaccc09f31d11fddc219
5
5
  SHA512:
6
- metadata.gz: a27c830370df223add103179c9e8b60d5259abbb5b21b664f0b2642d96e5736926325c07e271b08822401c312ef532ec8a6f3c03dba30ce5a637edcbbba1ed12
7
- data.tar.gz: 555cb81425239fba2c5752e238bd541db554f48eb7d46d1336122d730781e40fdd0b339a8266a49a42ace8b73909d7a26f145b9e3ea5d9602fbfcefb9db1a022
6
+ metadata.gz: 70d3834ac2a0db7b1a9a53c52edb3718b34a821d3b0d42e49ebe01f1c76c00188b928734a5969ef621e9609a3852117fd8190706566777c870b2b8b3d9592ccd
7
+ data.tar.gz: 297bbf2e92f9a77d85661849f3bbada5b18eff08b213ec6a48089dea112ab65b70a47b196e8ddc59b475e61cb9e6ecfc8648bb5dcbcd2836e341079d81b2fd92
@@ -10,6 +10,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
10
10
  ### Removed
11
11
  ### Fixed
12
12
 
13
+ ## [2.0.0] - 2020-08-20
14
+ ### Added
15
+ * Several additions to internal logging:
16
+ - Log messages now include a `feature` key. This can be used by logging aggregator tools to group log messages across different systems that use the gem. If one isn't provided a default value of `railway_ipc` is used.
17
+ - Protobufs are logged as a sub-hash which contains both the protobuf type and payload.
18
+ - Exchange and queue names are logged where applicable.
19
+ - The internal Bunny connection now uses the `RailwayIpc::Logger` instead of a generic `Logger`.
20
+
21
+ ### Changed
22
+ * *Breaking Change* `RailwayIpc.configure` now takes `device`, `level`, and `formatter` instead of a complete `Logger` instance. The instance is now managed internally by Railway. This is a breaking change to the `RailwayIpc.configure` API, clients will need to be updated to use the new syntax.
23
+
13
24
  ## [1.1.0] - 2020-08-07
14
25
  ### Changed
15
26
  * allow multiple consumers to handle the same message
data/README.md CHANGED
@@ -19,7 +19,7 @@ And then execute:
19
19
  ```ruby
20
20
  # config/initializers/railway_ipc.rb
21
21
 
22
- RailwayIpc.configure(logger: Rails.logger)
22
+ RailwayIpc.configure(STDOUT, Logger::INFO, MyFormatter)
23
23
  ```
24
24
 
25
25
  * Load the rake tasks in your Rakefile
@@ -29,16 +29,12 @@ module RailwayIpc
29
29
  Rake::Task['sneakers:run'].invoke
30
30
  end
31
31
 
32
- def self.configure(logger: ::Logger.new(STDOUT))
33
- @logger = RailwayIpc::Logger.new(logger)
32
+ def self.configure(log_device=STDOUT, level=::Logger::INFO, log_formatter=nil)
33
+ @logger = RailwayIpc::Logger.new(log_device, level, log_formatter)
34
34
  end
35
35
 
36
36
  def self.logger
37
- @logger || RailwayIpc::Logger.new(::Logger.new(STDOUT))
38
- end
39
-
40
- def self.bunny_logger
41
- logger.logger
37
+ @logger || RailwayIpc::Logger.new(STDOUT)
42
38
  end
43
39
 
44
40
  def self.bunny_connection
@@ -44,10 +44,12 @@ module RailwayIpc
44
44
  RailwayIpc::ProcessIncomingMessage.call(self, message)
45
45
  ack!
46
46
  rescue StandardError => e
47
- RailwayIpc.logger.log_exception(
48
- feature: 'railway_consumer',
47
+ RailwayIpc.logger.error(
48
+ e.message,
49
+ feature: 'railway_ipc_consumer',
50
+ exchange: exchange_name,
51
+ queue: queue_name,
49
52
  error: e.class,
50
- error_message: e.message,
51
53
  payload: payload
52
54
  )
53
55
  raise e
@@ -16,8 +16,9 @@ module RailwayIpc
16
16
 
17
17
  def run
18
18
  logger.warn(
19
- incoming_message.decoded,
20
- "Ignoring unknown message of type '#{incoming_message.type}'"
19
+ "Ignoring unknown message of type '#{incoming_message.type}'",
20
+ feature: 'railway_ipc_consumer',
21
+ protobuf: { type: incoming_message.type, data: incoming_message.decoded }
21
22
  )
22
23
  end
23
24
  end
@@ -36,8 +37,9 @@ module RailwayIpc
36
37
 
37
38
  def run
38
39
  logger.warn(
39
- incoming_message.decoded,
40
- "Ignoring message, no registered handler for '#{incoming_message.type}'"
40
+ "Ignoring message, no registered handler for '#{incoming_message.type}'",
41
+ feature: 'railway_ipc_consumer',
42
+ protobuf: { type: incoming_message.type, data: incoming_message.decoded }
41
43
  )
42
44
  end
43
45
  end
@@ -81,7 +83,13 @@ module RailwayIpc
81
83
 
82
84
  def raise_message_invalid_error
83
85
  error = "Message is invalid: #{incoming_message.stringify_errors}."
84
- logger.error(incoming_message.decoded, error)
86
+ logger.error(
87
+ error,
88
+ feature: 'railway_ipc_consumer',
89
+ exchange: consumer.exchange_name,
90
+ queue: consumer.queue_name,
91
+ protobuf: { type: incoming_message.class, data: incoming_message.decoded }
92
+ )
85
93
  raise RailwayIpc::IncomingMessage::InvalidMessage.new(error)
86
94
  end
87
95
 
@@ -11,15 +11,27 @@ module RailwayIpc
11
11
  end
12
12
 
13
13
  def handle(message)
14
- RailwayIpc.logger.info(message, 'Handling message')
14
+ RailwayIpc.logger.info('Handling message', log_message_options(message))
15
15
  response = self.class.block.call(message)
16
16
  if response.success?
17
- RailwayIpc.logger.info(message, 'Successfully handled message')
17
+ RailwayIpc.logger.info('Successfully handled message', log_message_options(message))
18
18
  else
19
- RailwayIpc.logger.error(message, 'Failed to handle message')
19
+ RailwayIpc.logger.error('Failed to handle message', log_message_options(message))
20
20
  end
21
21
 
22
22
  response
23
23
  end
24
+
25
+ private
26
+
27
+ def log_message_options(message)
28
+ {
29
+ feature: 'railway_ipc_consumer',
30
+ protobuf: {
31
+ type: message.class.name,
32
+ data: message
33
+ }
34
+ }
35
+ end
24
36
  end
25
37
  end
@@ -1,36 +1,41 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RailwayIpc
4
+ # Custom logger that accepts a `device`, `level`, and `formatter`.
5
+ # `formatter` can be any object that responds to `call`; a
6
+ # `Logger::Formatter` is used if the argument is not provided.
7
+ #
8
+ # Here is an example formatter that uses `Oj` to format structured log
9
+ # messages:
10
+ #
11
+ # require 'oj'
12
+ # OjFormatter = proc do |severity, datetime, progname, data|
13
+ # data.merge!(
14
+ # name: progname,
15
+ # timestamp: datetime,
16
+ # severity: severity
17
+ # )
18
+ # Oj.dump(data, { mode: :compat, time_format: :xmlschema })
19
+ # end
20
+ #
21
+ # logger = RailwayIpc::Logger.new(STDOUT, Logger::INFO, OjFormatter)
22
+ #
4
23
  class Logger
5
- attr_reader :logger
6
-
7
- def initialize(logger)
8
- @logger = logger
9
- end
10
-
11
- def info(message, statement)
12
- logger.info("[#{message_header(message)}] #{statement}")
24
+ def initialize(device=STDOUT, level=::Logger::INFO, formatter=nil)
25
+ @logger = ::Logger.new(device)
26
+ @logger.level = level
27
+ @logger.formatter = formatter if formatter
13
28
  end
14
29
 
15
- def warn(message, statement)
16
- logger.warn("[#{message_header(message)}] #{statement}")
30
+ %w[fatal error warn info debug].each do |level|
31
+ define_method(level) do |message, data={}|
32
+ data.merge!(feature: 'railway_ipc') unless data.key?(:feature)
33
+ logger.send(level, data.merge(message: message))
34
+ end
17
35
  end
18
36
 
19
- def debug(message, statement)
20
- logger.debug("[#{message_header(message)}] #{statement}")
21
- end
37
+ private
22
38
 
23
- def error(message, statement)
24
- logger.error("[#{message_header(message)}] #{statement}")
25
- end
26
-
27
- def log_exception(exception)
28
- logger.error(exception)
29
- end
30
-
31
- def message_header(message)
32
- log_statement = "message type: #{message.class}, uuid: #{message.uuid}, correlation_id: #{message.correlation_id}"
33
- message.respond_to?(:user_uuid) ? "#{log_statement}, user_uuid: #{message.user_uuid}" : log_statement
34
- end
39
+ attr_reader :logger
35
40
  end
36
41
  end
@@ -21,16 +21,15 @@ module RailwayIpc
21
21
  end
22
22
 
23
23
  def publish(message, published_message_store=RailwayIpc::PublishedMessage)
24
- RailwayIpc.logger.logger.warn('DEPRECATED: Use new PublisherInstance class')
24
+ RailwayIpc.logger.warn('DEPRECATED: Use new PublisherInstance class', log_message_options)
25
25
  ensure_message_uuid(message)
26
26
  ensure_correlation_id(message)
27
- RailwayIpc.logger.info(message, 'Publishing message')
28
-
27
+ RailwayIpc.logger.info('Publishing message', log_message_options(message))
29
28
  result = super(RailwayIpc::Rabbitmq::Payload.encode(message))
30
29
  published_message_store.store_message(self.class.exchange_name, message)
31
30
  result
32
31
  rescue RailwayIpc::InvalidProtobuf => e
33
- RailwayIpc.logger.error(message, 'Invalid protobuf')
32
+ RailwayIpc.logger.error('Invalid protobuf', log_message_options(message))
34
33
  raise e
35
34
  end
36
35
 
@@ -45,6 +44,11 @@ module RailwayIpc
45
44
  message.correlation_id = SecureRandom.uuid if message.correlation_id.blank?
46
45
  message
47
46
  end
47
+
48
+ def log_message_options(message=nil)
49
+ options = { feature: 'railway_ipc_publisher', exchange: self.class.exchange_name }
50
+ message.nil? ? options : options.merge(protobuf: { type: message.class, data: message })
51
+ end
48
52
  end
49
53
  end
50
54
 
@@ -68,20 +72,33 @@ module RailwayIpc
68
72
  def publish(message)
69
73
  message.uuid = SecureRandom.uuid if message.uuid.blank?
70
74
  message.correlation_id = SecureRandom.uuid if message.correlation_id.blank?
71
- RailwayIpc.logger.info(message, 'Publishing message')
75
+ RailwayIpc.logger.info('Publishing message', log_message_options(message))
72
76
 
73
77
  stored_message = message_store.store_message(exchange_name, message)
74
78
  super(RailwayIpc::Rabbitmq::Payload.encode(message))
75
79
  rescue RailwayIpc::InvalidProtobuf => e
76
- RailwayIpc.logger.error(message, 'Invalid protobuf')
80
+ RailwayIpc.logger.error('Invalid protobuf', log_message_options(message))
77
81
  raise e
78
82
  rescue ActiveRecord::RecordInvalid => e
79
- RailwayIpc.logger.error(message, 'Failed to store outgoing message')
83
+ RailwayIpc.logger.error('Failed to store outgoing message', log_message_options(message))
80
84
  raise RailwayIpc::FailedToStoreOutgoingMessage.new(e)
81
85
  rescue StandardError => e
82
86
  stored_message&.destroy
83
87
  raise e
84
88
  end
85
89
  # rubocop:enable Metrics/AbcSize
90
+
91
+ private
92
+
93
+ def log_message_options(message)
94
+ {
95
+ feature: 'railway_ipc_publisher',
96
+ exchange: exchange_name,
97
+ protobuf: {
98
+ type: message.class,
99
+ data: message
100
+ }
101
+ }
102
+ end
86
103
  end
87
104
  end
@@ -28,7 +28,7 @@ module RailwayIpc
28
28
  port: settings[:port],
29
29
  vhost: vhost,
30
30
  automatic_recovery: false,
31
- logger: RailwayIpc.bunny_logger
31
+ logger: RailwayIpc.logger
32
32
  }.merge(options))
33
33
  end
34
34
 
@@ -11,7 +11,11 @@ module RailwayIpc
11
11
  end
12
12
 
13
13
  def respond(request)
14
- RailwayIpc.logger.info(request, 'Responding to request')
14
+ RailwayIpc.logger.info(
15
+ 'Responding to request',
16
+ protobuf: { type: request.class, data: request },
17
+ feature: 'railway_ipc_request'
18
+ )
15
19
  response = self.class.block.call(request)
16
20
  raise ResponseTypeError.new(response.class) unless response.is_a?(Google::Protobuf::MessageExts)
17
21
 
@@ -39,18 +39,26 @@ module RailwayIpc
39
39
  end
40
40
 
41
41
  # rubocop:disable Metrics/AbcSize
42
+ # rubocop:disable Metrics/MethodLength
42
43
  def process_payload(response)
43
44
  decoded_payload = decode_payload(response)
44
45
  case decoded_payload.type
45
46
  when *registered_handlers
46
47
  @message = get_message_class(decoded_payload).decode(decoded_payload.message)
47
- RailwayIpc.logger.info(message, 'Handling response')
48
+ RailwayIpc.logger.info(
49
+ 'Handling response',
50
+ feature: 'railway_ipc_consumer',
51
+ exchange: self.class.exchange_name,
52
+ queue: self.class.queue_name,
53
+ protobuf: { type: message.class, data: message }
54
+ )
48
55
  RailwayIpc::Response.new(message, success: true)
49
56
  else
50
57
  @message = LearnIpc::ErrorMessage.decode(decoded_payload.message)
51
58
  raise RailwayIpc::UnhandledMessageError.new("#{self.class} does not know how to handle #{decoded_payload.type}")
52
59
  end
53
60
  end
61
+ # rubocop:enable Metrics/MethodLength
54
62
  # rubocop:enable Metrics/AbcSize
55
63
 
56
64
  def setup_rabbit_connection
@@ -78,10 +86,12 @@ module RailwayIpc
78
86
  private
79
87
 
80
88
  def log_exception(exception, payload)
81
- RailwayIpc.logger.log_exception(
82
- feature: 'railway_consumer',
89
+ RailwayIpc.logger.error(
90
+ exception.message,
91
+ feature: 'railway_ipc_consumer',
92
+ exchange: self.class.exchange_name,
93
+ queue: self.class.queue_name,
83
94
  error: exception.class,
84
- error_message: exception.message,
85
95
  payload: decode_for_error(exception, payload)
86
96
  )
87
97
  end
@@ -99,7 +109,12 @@ module RailwayIpc
99
109
  end
100
110
 
101
111
  def publish_message
102
- RailwayIpc.logger.info(request_message, 'Sending request')
112
+ RailwayIpc.logger.info(
113
+ 'Sending request',
114
+ feature: 'railway_ipc_publisher',
115
+ exchange: self.class.exchange_name,
116
+ protobuf: { type: request_message.class, data: request_message }
117
+ )
103
118
  rabbit_connection.publish(RailwayIpc::Rabbitmq::Payload.encode(request_message), routing_key: '')
104
119
  end
105
120
 
@@ -45,10 +45,12 @@ module RailwayIpc
45
45
  raise RailwayIpc::UnhandledMessageError.new("#{self.class} does not know how to handle #{decoded_payload.type}")
46
46
  end
47
47
  rescue StandardError => e
48
- RailwayIpc.logger.log_exception(
49
- feature: 'railway_consumer',
48
+ RailwayIpc.logger.error(
49
+ e.message,
50
+ feature: 'railway_ipc_consumer',
51
+ exchange: self.class.exchange_name,
52
+ queue: self.class.queue_name,
50
53
  error: e.class,
51
- error_message: e.message,
52
54
  payload: payload
53
55
  )
54
56
  raise e
@@ -56,10 +58,19 @@ module RailwayIpc
56
58
  # rubocop:enable Metrics/AbcSize
57
59
  # rubocop:enable Metrics/MethodLength
58
60
 
61
+ # rubocop:disable Metrics/AbcSize
62
+ # rubocop:disable Metrics/MethodLength
59
63
  def handle_request(payload)
60
64
  response = work(payload)
61
65
  rescue StandardError => e
62
- RailwayIpc.logger.error(message, "Error responding to message. Error: #{e.class}, #{e.message}")
66
+ RailwayIpc.logger.error(
67
+ 'Error responding to message.',
68
+ exception: e,
69
+ feature: 'railway_ipc_consumer',
70
+ exchange: self.class.exchange_name,
71
+ queue: self.class.queue_name,
72
+ protobuf: { type: message.class, data: message }
73
+ )
63
74
  response = self.class.rpc_error_adapter_class.error_message(e, message)
64
75
  ensure
65
76
  if response
@@ -68,6 +79,8 @@ module RailwayIpc
68
79
  )
69
80
  end
70
81
  end
82
+ # rubocop:enable Metrics/AbcSize
83
+ # rubocop:enable Metrics/MethodLength
71
84
 
72
85
  private
73
86
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RailwayIpc
4
- VERSION = '1.1.0'
4
+ VERSION = '2.0.0'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: railway-ipc
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - ''
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-08-07 00:00:00.000000000 Z
11
+ date: 2020-08-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -263,7 +263,7 @@ licenses:
263
263
  - MIT
264
264
  metadata:
265
265
  allowed_push_host: https://rubygems.org/
266
- post_install_message:
266
+ post_install_message:
267
267
  rdoc_options: []
268
268
  require_paths:
269
269
  - lib
@@ -278,9 +278,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
278
278
  - !ruby/object:Gem::Version
279
279
  version: '0'
280
280
  requirements: []
281
- rubyforge_project:
281
+ rubyforge_project:
282
282
  rubygems_version: 2.7.6
283
- signing_key:
283
+ signing_key:
284
284
  specification_version: 4
285
285
  summary: IPC components for Rails
286
286
  test_files: []