grpc_interceptors 0.1.5 → 0.2.0.rc1

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: ef558aae01335bdd0b85294c24c56c259d1c3e2121b4f1085350a9bdb7a66865
4
- data.tar.gz: 517e6c4a507442f71f296a313ba48640dc69ae54723631ac27c0b1699eeb5090
3
+ metadata.gz: '0299aaae1513e603f87075759a05a21f189261de4148ff7011d9e1185800e16b'
4
+ data.tar.gz: fe5c8bc7c0b3b6d08c753cde51c2c9e7364e38412ce0f9e14f1c1de43cdea2e5
5
5
  SHA512:
6
- metadata.gz: f19be2edc9078da2cdfaa817342b91fcabfa465b37610bbf1ff8fc5f82c1926fa5e3fdb8bc9fed63a6ffaecf24eae4ae2b3afe138053559389c93e4cdff47f83
7
- data.tar.gz: e65412d18e6d79cc8d39f3fdaeaeeb3d3213bd25517b7241808682f1fba219eb230362ac14bfdf50e006933067a8ffae1f1a57e5929137d1a2a2e36109d8b487
6
+ metadata.gz: 32b8cb86b89c5ef463c1509e222531187af223e84f7784782689648d0d0a47084e78fa9041f441cc1ade9d3d70cce827900070867c255b7b8d68386b872bd0e4
7
+ data.tar.gz: d5ebfebd144ae7b2dc7d57fa1d4041308652ae6f6bc40e8b519acc3eb4d3fdc3f2df25f980f9d75357c058af649192e1a7aa45d535c8572716dfe4ac78cdb58b
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../common/grpc_helper'
4
+ require_relative '../common/logging'
5
+
6
+ module GrpcInterceptors
7
+ module Client
8
+ class LoggingInterceptor < ::GRPC::ClientInterceptor
9
+ def initialize(logger)
10
+ @logger = logger
11
+
12
+ super()
13
+ end
14
+
15
+ def request_response(
16
+ request: nil, call: nil, method: nil, metadata: nil, &block
17
+ )
18
+ Common::Logging.yield_and_log(
19
+ logger: @logger, request: request, method: method,
20
+ method_type: 'unary', kind: KIND, &block
21
+ )
22
+ end
23
+
24
+ def client_streamer(
25
+ requests: nil, call: nil, method: nil, metadata: nil, &block
26
+ )
27
+ requests.each do |request|
28
+ Common::Logging.log(request: request, method: method, method_type: 'client_stream')
29
+ end
30
+
31
+ Common::Logging.yield_and_log(method: method, method_type: 'client_stream', &block)
32
+ end
33
+
34
+ def server_streamer(
35
+ request: nil, call: nil, method: nil, metadata: nil, &block
36
+ )
37
+ Common::Logging.yield_and_log(
38
+ logger: @logger, request: request, method: method,
39
+ method_type: 'server_stream', kind: KIND, &block
40
+ )
41
+ end
42
+
43
+ # def bidi_streamer(_requests: nil, call: nil, method: nil, metadata: nil)
44
+ # yield
45
+ # end
46
+ end
47
+ end
48
+ end
@@ -5,13 +5,12 @@ require_relative '../common/opentelemetry_helper'
5
5
 
6
6
  module GrpcInterceptors
7
7
  module Client
8
- class OpenTelemetryTracingInstrument < ::GRPC::ClientInterceptor
8
+ class OpenTelemetryTracingInterceptor < ::GRPC::ClientInterceptor
9
9
  def request_response(request: nil, call: nil, method: nil, metadata: nil)
10
- kind = OpenTelemetry::Trace::SpanKind::CLIENT
11
10
  attributes = Common::OpenTelemetryHelper.tracing_attributes(method)
12
11
 
13
12
  Common::OpenTelemetryHelper.tracer.in_span(
14
- method, kind: kind, attributes: attributes
13
+ method, kind: KIND, attributes: attributes
15
14
  ) do
16
15
  OpenTelemetry.propagation.inject(metadata)
17
16
  yield
@@ -22,9 +21,16 @@ module GrpcInterceptors
22
21
  # yield
23
22
  # end
24
23
 
25
- # def server_streamer(_request: nil, call: nil, method: nil, metadata: nil)
26
- # yield
27
- # end
24
+ def server_streamer(request: nil, call: nil, method: nil, metadata: nil)
25
+ attributes = Common::OpenTelemetryHelper.tracing_attributes(method)
26
+
27
+ Common::OpenTelemetryHelper.tracer.in_span(
28
+ method, kind: KIND, attributes: attributes
29
+ ) do
30
+ OpenTelemetry.propagation.inject(metadata)
31
+ yield
32
+ end
33
+ end
28
34
 
29
35
  # def bidi_streamer(_requests: nil, call: nil, method: nil, metadata: nil)
30
36
  # yield
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GrpcInterceptors
4
+ module Client
5
+ KIND = :client
6
+ end
7
+ end
@@ -45,8 +45,8 @@ module GrpcInterceptors
45
45
 
46
46
  # converts proto message to a Ruby hash preserving the original fields' names
47
47
  # and including default values
48
- # WARNING! It can be slow and not 100% accurate. In this gem it's onyl used in the DEBUG mode
49
- # related comment # related comment https://github.com/protocolbuffers/protobuf/issues/6755#issuecomment-733880977
48
+ # WARNING! It can be slow and not 100% accurate. In this gem it's only used in the DEBUG mode
49
+ # related comment: https://github.com/protocolbuffers/protobuf/issues/6755#issuecomment-733880977
50
50
  def self.proto_to_h(proto)
51
51
  JSON(
52
52
  proto.to_json(
@@ -2,8 +2,50 @@
2
2
 
3
3
  module GrpcInterceptors
4
4
  module Common
5
- module LogPayload
6
- def self.build(method, method_type, grpc_code, kind)
5
+ module Logger
6
+ ##
7
+ # Log a gRPC interaction from the client side.
8
+ #
9
+ # If the current log level is INFO, then it logs out basic facts.
10
+ # If the current log level is DEBUG, then it additionally adds to the log request and response.
11
+ # If the server responds with error, then the error is added to the log.
12
+ #
13
+ # @param [Object] request The request object
14
+ # @param [String] method The method passed to the intercepting function
15
+ # @param [String] method_type The used method_type, unary or one of the streams
16
+ #
17
+ def self.log(
18
+ logger: nil, request: nil, method: nil, method_type: nil, kind: nil
19
+ )
20
+ payload = build_payload(method, method_type, kind)
21
+
22
+ if block_given?
23
+ grpc_code = ::GRPC::Core::StatusCodes::OK
24
+ begin
25
+ response = yield
26
+ rescue StandardError => e
27
+ grpc_code = e.is_a?(::GRPC::BadStatus) ? e.code : ::GRPC::Core::StatusCodes::UNKNOWN
28
+
29
+ payload['error'] = e.class.to_s
30
+ payload['error_message'] = e.message
31
+ payload['backtrace'] = e.backtrace
32
+
33
+ raise
34
+ end
35
+ end
36
+ ensure
37
+ payload['grpc_code'] = grpc_code unless grpc_code.nil?
38
+
39
+ if logger.level == Logger::Severity::INFO
40
+ logger.info(payload)
41
+ elsif logger.level == Logger::Severity::DEBUG
42
+ payload['request'] = Common::GrpcHelper.proto_to_h(request) unless request.nil?
43
+ payload['response'] = Common::GrpcHelper.proto_to_h(response) unless response.nil?
44
+ logger.debug(payload)
45
+ end
46
+ end
47
+
48
+ def self.build_payload(method, method_type, kind)
7
49
  service = GrpcHelper.service_name(method)
8
50
  method = GrpcHelper.method_name(method)
9
51
 
@@ -12,8 +54,7 @@ module GrpcInterceptors
12
54
  'grpc.component' => kind, # the caller, server or client
13
55
  'grpc.service' => service,
14
56
  'grpc.method' => method,
15
- 'grpc.method_type' => method_type,
16
- 'grpc.code' => grpc_code
57
+ 'grpc.method_type' => method_type
17
58
  }
18
59
 
19
60
  if defined?(OpenTelemetry) && OpenTelemetry::Trace.current_span.recording?
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GrpcInterceptors
4
+ module Common
5
+ module Logging
6
+ def self.yield_and_log(
7
+ logger: nil, request: nil, method: nil, method_type: nil, kind: nil
8
+ )
9
+ grpc_code = ::GRPC::Core::StatusCodes::OK
10
+ response = yield
11
+ rescue StandardError => e
12
+ grpc_code = e.is_a?(::GRPC::BadStatus) ? e.code : ::GRPC::Core::StatusCodes::UNKNOWN
13
+ extra_fields = {
14
+ 'error' => e.class.to_s,
15
+ 'error_message' => e.message,
16
+ 'backtrace' => e.backtrace
17
+ }
18
+
19
+ raise
20
+ ensure
21
+ extra_fields ||= {}
22
+ extra_fields['grpc.code'] = grpc_code
23
+
24
+ if logger.level == ::Logger::Severity::DEBUG && !response.nil? && !response.is_a?(Enumerator)
25
+ extra_fields['response'] = Common::GrpcHelper.proto_to_h(response)
26
+ end
27
+
28
+ log(
29
+ logger: logger, request: request, method: method,
30
+ method_type: method_type, kind: kind, extra_fields: extra_fields
31
+ )
32
+ end
33
+
34
+ ##
35
+ # Log a gRPC interaction.
36
+ #
37
+ # If the current log level is INFO, then it logs out basic facts.
38
+ # If the current log level is DEBUG, then it additionally adds to the log request and response.
39
+ # If the server responds with error, then the error is added to the log.
40
+ #
41
+ # @param [Object] request The request object
42
+ # @param [String] method The method passed to the intercepting function
43
+ # @param [String] method_type The used method_type, unary or one of the streams
44
+ #
45
+ def self.log(
46
+ logger: nil, request: nil, method: nil, method_type: nil, kind: nil,
47
+ extra_fields: {}
48
+ )
49
+ payload = build_payload(method, method_type, kind)
50
+ payload.merge!(extra_fields)
51
+
52
+ if logger.level == ::Logger::Severity::INFO
53
+ logger.info(payload)
54
+ elsif logger.level == ::Logger::Severity::DEBUG
55
+ payload['request'] = Common::GrpcHelper.proto_to_h(request) unless request.nil?
56
+ logger.debug(payload)
57
+ end
58
+ end
59
+
60
+ def self.build_payload(method, method_type, kind)
61
+ service = GrpcHelper.service_name(method)
62
+ method = GrpcHelper.method_name(method)
63
+
64
+ payload = {
65
+ 'pid' => Process.pid,
66
+ 'grpc.component' => kind, # the caller, server or client
67
+ 'grpc.service' => service,
68
+ 'grpc.method' => method,
69
+ 'grpc.method_type' => method_type
70
+ }
71
+
72
+ if defined?(OpenTelemetry) && OpenTelemetry::Trace.current_span.recording?
73
+ tracing_context = OpenTelemetry::Trace.current_span.context
74
+ payload['span_id'] = tracing_context.hex_span_id
75
+ payload['trace_id'] = tracing_context.hex_trace_id
76
+ end
77
+
78
+ payload
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../common/grpc_helper'
4
+ require_relative '../common/logging'
5
+
6
+ module GrpcInterceptors
7
+ module Server
8
+ class LoggingInterceptor < ::GRPC::ServerInterceptor
9
+ def initialize(logger)
10
+ @logger = logger
11
+
12
+ super()
13
+ end
14
+
15
+ def request_response(request: nil, call: nil, method: nil, &block)
16
+ Common::Logging.yield_and_log(
17
+ logger: @logger, request: request, method: method,
18
+ method_type: 'unary', kind: KIND, &block
19
+ )
20
+ end
21
+
22
+ # def client_streamer(call: nil, method: nil)
23
+ # yield
24
+ # end
25
+
26
+ # def server_streamer(_request: nil, call: nil, method: nil)
27
+ # yield
28
+ # end
29
+
30
+ # def bidi_streamer(_requests: nil, call: nil, method: nil)
31
+ # yield
32
+ # end
33
+ end
34
+ end
35
+ end
@@ -6,18 +6,17 @@ require_relative '../common/opentelemetry_helper'
6
6
  module GrpcInterceptors
7
7
  module Server
8
8
  # https://github.com/grpc/grpc/blob/master/src/ruby/lib/grpc/generic/interceptors.rb
9
- class OpenTelemetryTracingInstrument < ::GRPC::ServerInterceptor
9
+ class OpenTelemetryTracingInterceptor < ::GRPC::ServerInterceptor
10
10
  def request_response(request: nil, call: nil, method: nil, &block)
11
11
  context = OpenTelemetry.propagation.extract(call.metadata)
12
12
  route_name = Common::GrpcHelper.route_name(method)
13
13
  attributes = Common::OpenTelemetryHelper.tracing_attributes(method)
14
- kind = OpenTelemetry::Trace::SpanKind::SERVER
15
14
 
16
15
  OpenTelemetry::Context.with_current(context) do
17
16
  Common::OpenTelemetryHelper.tracer.in_span(
18
17
  route_name,
19
18
  attributes: attributes,
20
- kind: kind,
19
+ kind: KIND,
21
20
  &block
22
21
  )
23
22
  end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GrpcInterceptors
4
+ module Server
5
+ KIND = :server
6
+ end
7
+ end
metadata CHANGED
@@ -1,43 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: grpc_interceptors
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.2.0.rc1
5
5
  platform: ruby
6
6
  authors:
7
7
  - michal-kazmierczak
8
- autorequire:
8
+ - andykimchris
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-03-07 00:00:00.000000000 Z
11
+ date: 1980-01-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: grpc
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - '='
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.61'
19
+ version: '1.67'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - '='
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '1.61'
26
+ version: '1.67'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: grpc-tools
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - '='
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '1.61'
33
+ version: '1.67'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - '='
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '1.61'
40
+ version: '1.67'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: guard
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -236,7 +236,6 @@ dependencies:
236
236
  version: '3.6'
237
237
  description: A collection of Ruby interceptors (middlewares) for gRPC servers and
238
238
  clients.
239
- email:
240
239
  executables: []
241
240
  extensions: []
242
241
  extra_rdoc_files: []
@@ -244,13 +243,16 @@ files:
244
243
  - LICENSE
245
244
  - README.md
246
245
  - lib/grpc_interceptors.rb
247
- - lib/grpc_interceptors/client/logging.rb
248
- - lib/grpc_interceptors/client/opentelemetry_tracing_instrument.rb
246
+ - lib/grpc_interceptors/client.rb
247
+ - lib/grpc_interceptors/client/logging_interceptor.rb
248
+ - lib/grpc_interceptors/client/opentelemetry_tracing_interceptor.rb
249
249
  - lib/grpc_interceptors/common/grpc_helper.rb
250
250
  - lib/grpc_interceptors/common/log_payload.rb
251
+ - lib/grpc_interceptors/common/logging.rb
251
252
  - lib/grpc_interceptors/common/opentelemetry_helper.rb
252
- - lib/grpc_interceptors/server/logging.rb
253
- - lib/grpc_interceptors/server/opentelemetry_tracing_instrument.rb
253
+ - lib/grpc_interceptors/server.rb
254
+ - lib/grpc_interceptors/server/logging_interceptor.rb
255
+ - lib/grpc_interceptors/server/opentelemetry_tracing_interceptor.rb
254
256
  - lib/grpc_interceptors/server/statsd_metrics.rb
255
257
  homepage: https://github.com/michal-kazmierczak/ruby-grpc-interceptors
256
258
  licenses:
@@ -258,7 +260,6 @@ licenses:
258
260
  metadata:
259
261
  allowed_push_host: https://rubygems.org
260
262
  rubygems_mfa_required: 'true'
261
- post_install_message:
262
263
  rdoc_options: []
263
264
  require_paths:
264
265
  - lib
@@ -273,8 +274,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
273
274
  - !ruby/object:Gem::Version
274
275
  version: '0'
275
276
  requirements: []
276
- rubygems_version: 3.5.3
277
- signing_key:
277
+ rubygems_version: 3.6.9
278
278
  specification_version: 4
279
279
  summary: A collection of Ruby interceptors (middlewares) for gRPC servers and clients.
280
280
  test_files: []
@@ -1,67 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative '../common/grpc_helper'
4
- require_relative '../common/log_payload'
5
-
6
- module GrpcInterceptors
7
- module Client
8
- class Logging < ::GRPC::ServerInterceptor
9
- def initialize(logger)
10
- @logger = logger
11
-
12
- super()
13
- end
14
-
15
- def request_response(
16
- request: nil, call: nil, method: nil, metadata: nil, &block
17
- )
18
- log(request, method, 'unary', &block)
19
- end
20
-
21
- # def client_streamer(_requests: nil, call: nil, method: nil, metadata: nil)
22
- # yield
23
- # end
24
-
25
- # def server_streamer(_request: nil, call: nil, method: nil, metadata: nil)
26
- # yield
27
- # end
28
-
29
- # def bidi_streamer(_requests: nil, call: nil, method: nil, metadata: nil)
30
- # yield
31
- # end
32
-
33
- private
34
-
35
- # if the server responds with error, then the error is attached to the log
36
- # if the current level is INFO, then it logs out basic facts
37
- # if the current level is DEBUG, then it additionally includes the request
38
- def log(request, method, method_type)
39
- grpc_code = ::GRPC::Core::StatusCodes::OK
40
-
41
- response = yield
42
- rescue StandardError => e
43
- grpc_code = e.is_a?(::GRPC::BadStatus) ? e.code : ::GRPC::Core::StatusCodes::UNKNOWN
44
-
45
- raise
46
- ensure
47
- payload = Common::LogPayload.build(
48
- method, method_type, grpc_code, 'client'
49
- )
50
-
51
- if e
52
- payload['error'] = e.class.to_s
53
- payload['error_message'] = e.message
54
- payload['backtrace'] = e.backtrace
55
- end
56
-
57
- if @logger.level == Logger::Severity::INFO
58
- @logger.info(payload)
59
- elsif @logger.level == Logger::Severity::DEBUG
60
- payload['request'] = Common::GrpcHelper.proto_to_h(request)
61
- payload['response'] = Common::GrpcHelper.proto_to_h(response)
62
- @logger.debug(payload)
63
- end
64
- end
65
- end
66
- end
67
- end
@@ -1,63 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative '../common/grpc_helper'
4
- require_relative '../common/log_payload'
5
-
6
- module GrpcInterceptors
7
- module Server
8
- class Logging < ::GRPC::ServerInterceptor
9
- def initialize(logger)
10
- @logger = logger
11
-
12
- super()
13
- end
14
-
15
- def request_response(request: nil, call: nil, method: nil, &block)
16
- log(request, method, 'unary', &block)
17
- end
18
-
19
- # def client_streamer(call: nil, method: nil)
20
- # yield
21
- # end
22
-
23
- # def server_streamer(_request: nil, call: nil, method: nil)
24
- # yield
25
- # end
26
-
27
- # def bidi_streamer(_requests: nil, call: nil, method: nil)
28
- # yield
29
- # end
30
-
31
- private
32
-
33
- # in case of an exception, it logs out on the ERROR level including error details
34
- # if the current level is INFO, then it logs out basic facts
35
- # if the current level is DEBUG, then it additionally includes the request
36
- def log(request, method, method_type)
37
- grpc_code = ::GRPC::Core::StatusCodes::OK
38
-
39
- yield
40
- rescue StandardError => e
41
- grpc_code = e.is_a?(::GRPC::BadStatus) ? e.code : ::GRPC::Core::StatusCodes::UNKNOWN
42
-
43
- raise
44
- ensure
45
- payload = Common::LogPayload.build(
46
- method, method_type, grpc_code, 'server'
47
- )
48
-
49
- if e
50
- payload['error'] = e.class.to_s
51
- payload['error_message'] = e.message
52
- payload['backtrace'] = e.backtrace
53
- @logger.error(payload)
54
- elsif @logger.level == Logger::Severity::INFO
55
- @logger.info(payload)
56
- elsif @logger.level == Logger::Severity::DEBUG
57
- payload['request'] = Common::GrpcHelper.proto_to_h(request)
58
- @logger.debug(payload)
59
- end
60
- end
61
- end
62
- end
63
- end