gruf 1.2.7 → 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 +4 -4
- data/CHANGELOG.md +11 -0
- data/README.md +98 -119
- data/bin/gruf +9 -3
- data/lib/gruf.rb +4 -4
- data/lib/gruf/configuration.rb +11 -20
- data/lib/gruf/controllers/base.rb +82 -0
- data/lib/gruf/controllers/request.rb +96 -0
- data/lib/gruf/controllers/service_binder.rb +86 -0
- data/lib/gruf/error.rb +9 -0
- data/lib/gruf/errors/helpers.rb +40 -0
- data/lib/gruf/{hooks → interceptors}/active_record/connection_reset.rb +4 -10
- data/lib/gruf/interceptors/authentication/basic.rb +80 -0
- data/lib/gruf/interceptors/base.rb +51 -0
- data/lib/gruf/{instrumentation/output_metadata_timer.rb → interceptors/context.rb} +25 -15
- data/lib/gruf/interceptors/instrumentation/output_metadata_timer.rb +59 -0
- data/lib/gruf/{instrumentation → interceptors/instrumentation}/request_logging/formatters/base.rb +15 -13
- data/lib/gruf/{instrumentation → interceptors/instrumentation}/request_logging/formatters/logstash.rb +15 -13
- data/lib/gruf/{instrumentation → interceptors/instrumentation}/request_logging/formatters/plain.rb +21 -19
- data/lib/gruf/interceptors/instrumentation/request_logging/interceptor.rb +191 -0
- data/lib/gruf/interceptors/instrumentation/statsd.rb +80 -0
- data/lib/gruf/interceptors/registry.rb +131 -0
- data/lib/gruf/{authentication/none.rb → interceptors/server_interceptor.rb} +8 -7
- data/lib/gruf/interceptors/timer.rb +79 -0
- data/lib/gruf/response.rb +1 -2
- data/lib/gruf/server.rb +40 -25
- data/lib/gruf/version.rb +1 -1
- metadata +19 -20
- data/lib/gruf/authentication.rb +0 -65
- data/lib/gruf/authentication/base.rb +0 -65
- data/lib/gruf/authentication/basic.rb +0 -74
- data/lib/gruf/authentication/strategies.rb +0 -107
- data/lib/gruf/hooks/base.rb +0 -66
- data/lib/gruf/hooks/registry.rb +0 -110
- data/lib/gruf/instrumentation/base.rb +0 -114
- data/lib/gruf/instrumentation/registry.rb +0 -104
- data/lib/gruf/instrumentation/request_context.rb +0 -82
- data/lib/gruf/instrumentation/request_logging/hook.rb +0 -185
- data/lib/gruf/instrumentation/statsd.rb +0 -80
- data/lib/gruf/service.rb +0 -333
@@ -1,65 +0,0 @@
|
|
1
|
-
# coding: utf-8
|
2
|
-
# Copyright (c) 2017-present, BigCommerce Pty. Ltd. All rights reserved
|
3
|
-
#
|
4
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
5
|
-
# documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
|
6
|
-
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
|
7
|
-
# persons to whom the Software is furnished to do so, subject to the following conditions:
|
8
|
-
#
|
9
|
-
# The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
|
10
|
-
# Software.
|
11
|
-
#
|
12
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
13
|
-
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
14
|
-
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
15
|
-
# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
16
|
-
#
|
17
|
-
module Gruf
|
18
|
-
module Authentication
|
19
|
-
##
|
20
|
-
# Base interface for Authentication strategies. All derived strategies must define the `valid?` method.
|
21
|
-
#
|
22
|
-
class Base
|
23
|
-
include Gruf::Loggable
|
24
|
-
|
25
|
-
# @return [String] The credentials sent in the request
|
26
|
-
attr_reader :credentials
|
27
|
-
# @return [Hash] A hash of authentication options
|
28
|
-
attr_reader :options
|
29
|
-
|
30
|
-
##
|
31
|
-
# Initialize the authentication middleware
|
32
|
-
#
|
33
|
-
# @param [String] credentials The credentials sent in the request
|
34
|
-
# @param [Hash] options A hash of authentication options
|
35
|
-
#
|
36
|
-
def initialize(credentials, options = {})
|
37
|
-
opts = Gruf.authentication_options || {}
|
38
|
-
@credentials = credentials
|
39
|
-
@options = opts.merge(options)
|
40
|
-
end
|
41
|
-
|
42
|
-
##
|
43
|
-
# Verify the credentials. Helper class method.
|
44
|
-
#
|
45
|
-
# @param [GRPC::ActiveCall] call The gRPC active call for the given operation
|
46
|
-
# @param [String] credentials The credentials sent in the request
|
47
|
-
# @param [Hash] options A hash of authentication options
|
48
|
-
#
|
49
|
-
def self.verify(call, credentials = '', options = {})
|
50
|
-
new(credentials, options).valid?(call)
|
51
|
-
end
|
52
|
-
|
53
|
-
##
|
54
|
-
# Abstract method that is required to be implemented in every derivative class.
|
55
|
-
# Return true if the call is authenticated, false if a permission denied error is to be sent.
|
56
|
-
#
|
57
|
-
# @param [GRPC::ActiveCall] _call The gRPC active call for the given operation
|
58
|
-
# @return [Boolean] True if the call was authenticated
|
59
|
-
#
|
60
|
-
def valid?(_call)
|
61
|
-
raise NotImplementedError
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
@@ -1,74 +0,0 @@
|
|
1
|
-
# coding: utf-8
|
2
|
-
# Copyright (c) 2017-present, BigCommerce Pty. Ltd. All rights reserved
|
3
|
-
#
|
4
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
5
|
-
# documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
|
6
|
-
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
|
7
|
-
# persons to whom the Software is furnished to do so, subject to the following conditions:
|
8
|
-
#
|
9
|
-
# The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
|
10
|
-
# Software.
|
11
|
-
#
|
12
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
13
|
-
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
14
|
-
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
15
|
-
# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
16
|
-
#
|
17
|
-
require 'base64'
|
18
|
-
|
19
|
-
module Gruf
|
20
|
-
module Authentication
|
21
|
-
##
|
22
|
-
# Handles basic authentication for gRPC requests
|
23
|
-
#
|
24
|
-
class Basic < Base
|
25
|
-
##
|
26
|
-
# @param [GRPC::ActiveCall] _call The gRPC active call for the given operation
|
27
|
-
# @return [Boolean] True if the basic authentication was valid
|
28
|
-
#
|
29
|
-
def valid?(_call)
|
30
|
-
server_credentials.any? do |cred|
|
31
|
-
username = cred.fetch(:username, '').to_s
|
32
|
-
password = cred.fetch(:password, '').to_s
|
33
|
-
if username.empty?
|
34
|
-
request_password == password
|
35
|
-
else
|
36
|
-
request_credentials == "#{username}:#{password}"
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
private
|
42
|
-
|
43
|
-
##
|
44
|
-
# @return [Array<Hash>] An array of valid server credentials for this service
|
45
|
-
#
|
46
|
-
def server_credentials
|
47
|
-
options.fetch(:credentials, [])
|
48
|
-
end
|
49
|
-
|
50
|
-
##
|
51
|
-
# @return [String] The decoded request credentials
|
52
|
-
#
|
53
|
-
def request_credentials
|
54
|
-
Base64.decode64(credentials.to_s.gsub('Basic ', '').strip)
|
55
|
-
end
|
56
|
-
|
57
|
-
##
|
58
|
-
# @return [String] The decoded request username
|
59
|
-
# @deprecated
|
60
|
-
# :nocov:
|
61
|
-
def request_username
|
62
|
-
@request_username ||= request_credentials.split(':').first
|
63
|
-
end
|
64
|
-
# :nocov:
|
65
|
-
|
66
|
-
##
|
67
|
-
# @return [String] The decoded request password
|
68
|
-
#
|
69
|
-
def request_password
|
70
|
-
@request_password ||= request_credentials.split(':').last
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
@@ -1,107 +0,0 @@
|
|
1
|
-
# coding: utf-8
|
2
|
-
# Copyright (c) 2017-present, BigCommerce Pty. Ltd. All rights reserved
|
3
|
-
#
|
4
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
5
|
-
# documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
|
6
|
-
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
|
7
|
-
# persons to whom the Software is furnished to do so, subject to the following conditions:
|
8
|
-
#
|
9
|
-
# The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
|
10
|
-
# Software.
|
11
|
-
#
|
12
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
13
|
-
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
14
|
-
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
15
|
-
# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
16
|
-
#
|
17
|
-
module Gruf
|
18
|
-
module Authentication
|
19
|
-
##
|
20
|
-
# Provides a modifiable repository of strategies for authentication
|
21
|
-
#
|
22
|
-
class Strategies
|
23
|
-
##
|
24
|
-
# Error class that represents when a strategy does not extend the base class
|
25
|
-
#
|
26
|
-
class StrategyDescendantError < StandardError; end
|
27
|
-
|
28
|
-
class << self
|
29
|
-
##
|
30
|
-
# Add an authentication strategy, either through a class or a block
|
31
|
-
#
|
32
|
-
# @param [String] name The vanity name of the strategy being loaded
|
33
|
-
# @param [Class|NilClass] strategy (Optional) The class that represents the strategy
|
34
|
-
# @param [Proc] &block If given, will attempt to build a strategy class from the base class with this block
|
35
|
-
# @return [Class] The loaded strategy
|
36
|
-
#
|
37
|
-
def add(name, strategy = nil, &block)
|
38
|
-
base = Gruf::Authentication::Base
|
39
|
-
strategy ||= Class.new(base)
|
40
|
-
strategy.class_eval(&block) if block_given?
|
41
|
-
|
42
|
-
# all strategies require the valid? method
|
43
|
-
raise NoMethodError unless strategy.method_defined?(:valid?)
|
44
|
-
|
45
|
-
raise StrategyDescendantError, "Strategies must descend from #{base}" unless strategy.ancestors.include?(base)
|
46
|
-
|
47
|
-
_strategies[name.to_sym] = strategy
|
48
|
-
end
|
49
|
-
|
50
|
-
##
|
51
|
-
# Return a strategy via a hash accessor syntax
|
52
|
-
#
|
53
|
-
# @param [Symbol] label The name of the strategy
|
54
|
-
# @return [Gruf::Authentication::Base] The requested strategy
|
55
|
-
#
|
56
|
-
def [](label)
|
57
|
-
_strategies[label.to_sym]
|
58
|
-
end
|
59
|
-
|
60
|
-
##
|
61
|
-
# Iterate over each strategy and yield it to the caller
|
62
|
-
#
|
63
|
-
def each
|
64
|
-
_strategies.each do |s|
|
65
|
-
yield s
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
##
|
70
|
-
# Return the loaded strategies as a hash
|
71
|
-
#
|
72
|
-
# @return [Hash<Class>] A name/strategy pair of loaded strategies
|
73
|
-
#
|
74
|
-
def to_h
|
75
|
-
_strategies
|
76
|
-
end
|
77
|
-
|
78
|
-
##
|
79
|
-
# Return if there are any loaded strategies
|
80
|
-
#
|
81
|
-
# @return [Boolean] True if there are loaded strategies
|
82
|
-
#
|
83
|
-
def any?
|
84
|
-
to_h.keys.count > 0
|
85
|
-
end
|
86
|
-
|
87
|
-
##
|
88
|
-
# Clear all given strategies
|
89
|
-
#
|
90
|
-
# @return [Hash] The newly empty hash
|
91
|
-
#
|
92
|
-
def clear
|
93
|
-
@strategies = {}
|
94
|
-
end
|
95
|
-
|
96
|
-
private
|
97
|
-
|
98
|
-
##
|
99
|
-
# @return [Hash<Class>]
|
100
|
-
#
|
101
|
-
def _strategies
|
102
|
-
@strategies ||= {}
|
103
|
-
end
|
104
|
-
end
|
105
|
-
end
|
106
|
-
end
|
107
|
-
end
|
data/lib/gruf/hooks/base.rb
DELETED
@@ -1,66 +0,0 @@
|
|
1
|
-
# coding: utf-8
|
2
|
-
# Copyright (c) 2017-present, BigCommerce Pty. Ltd. All rights reserved
|
3
|
-
#
|
4
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
5
|
-
# documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
|
6
|
-
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
|
7
|
-
# persons to whom the Software is furnished to do so, subject to the following conditions:
|
8
|
-
#
|
9
|
-
# The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
|
10
|
-
# Software.
|
11
|
-
#
|
12
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
13
|
-
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
14
|
-
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
15
|
-
# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
16
|
-
#
|
17
|
-
module Gruf
|
18
|
-
module Hooks
|
19
|
-
##
|
20
|
-
# Base class for a hook. Define before, around, outer_around, or after methods to utilize functionality.
|
21
|
-
#
|
22
|
-
class Base
|
23
|
-
include Gruf::Loggable
|
24
|
-
|
25
|
-
# @return [Gruf::Service] service The service to perform the hook against
|
26
|
-
attr_reader :service
|
27
|
-
# @return [Hash] options Options to use for the hook
|
28
|
-
attr_reader :options
|
29
|
-
|
30
|
-
##
|
31
|
-
# Initialize the hook and run setup
|
32
|
-
#
|
33
|
-
# @param [Gruf::Service] service The gruf service that the hook will perform against
|
34
|
-
# @param [Hash] options (Optional) A hash of options for this hook
|
35
|
-
#
|
36
|
-
def initialize(service, options = {})
|
37
|
-
@service = service
|
38
|
-
@options = options
|
39
|
-
setup
|
40
|
-
end
|
41
|
-
|
42
|
-
##
|
43
|
-
# Method that can be used to setup the hook prior to running it
|
44
|
-
#
|
45
|
-
def setup
|
46
|
-
# noop
|
47
|
-
end
|
48
|
-
|
49
|
-
##
|
50
|
-
# @return [String] Returns the service name as a translated name separated by periods
|
51
|
-
#
|
52
|
-
def service_key
|
53
|
-
service.class.name.underscore.tr('/', '.')
|
54
|
-
end
|
55
|
-
|
56
|
-
##
|
57
|
-
# Parse the method signature into a service.method name format
|
58
|
-
#
|
59
|
-
# @return [String] The parsed service method name
|
60
|
-
#
|
61
|
-
def method_key(call_signature)
|
62
|
-
"#{service_key}.#{call_signature.to_s.gsub('_without_intercept', '')}"
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
data/lib/gruf/hooks/registry.rb
DELETED
@@ -1,110 +0,0 @@
|
|
1
|
-
# coding: utf-8
|
2
|
-
# Copyright (c) 2017-present, BigCommerce Pty. Ltd. All rights reserved
|
3
|
-
#
|
4
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
5
|
-
# documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
|
6
|
-
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
|
7
|
-
# persons to whom the Software is furnished to do so, subject to the following conditions:
|
8
|
-
#
|
9
|
-
# The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
|
10
|
-
# Software.
|
11
|
-
#
|
12
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
13
|
-
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
14
|
-
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
15
|
-
# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
16
|
-
#
|
17
|
-
require_relative 'base'
|
18
|
-
require_relative 'active_record/connection_reset'
|
19
|
-
|
20
|
-
module Gruf
|
21
|
-
module Hooks
|
22
|
-
##
|
23
|
-
# Registry of all hooks added
|
24
|
-
#
|
25
|
-
class Registry
|
26
|
-
##
|
27
|
-
# Error class that represents when a gruf hook does not extend the base class
|
28
|
-
#
|
29
|
-
class HookDescendantError < StandardError; end
|
30
|
-
|
31
|
-
class << self
|
32
|
-
##
|
33
|
-
# Add an authentication strategy, either through a class or a block
|
34
|
-
#
|
35
|
-
# @param [String] name The name to represent the hook as
|
36
|
-
# @param [Gruf::Hooks::Base|NilClass] hook The strategy class to add. If nil, will expect
|
37
|
-
# a block that can be built as a hook instead
|
38
|
-
# @return [Class] The hook that was added
|
39
|
-
#
|
40
|
-
def add(name, hook = nil, &block)
|
41
|
-
base = Gruf::Hooks::Base
|
42
|
-
hook ||= Class.new(base)
|
43
|
-
hook.class_eval(&block) if block_given?
|
44
|
-
|
45
|
-
# all hooks require either the before, after, or around method
|
46
|
-
raise NoMethodError unless hook.method_defined?(:before) || hook.method_defined?(:after) || hook.method_defined?(:around) || hook.method_defined?(:outer_around)
|
47
|
-
|
48
|
-
raise HookDescendantError, "Hooks must descend from #{base}" unless hook.ancestors.include?(base)
|
49
|
-
|
50
|
-
_registry[name.to_sym] = hook
|
51
|
-
end
|
52
|
-
|
53
|
-
##
|
54
|
-
# Return a hook via a hash accessor syntax
|
55
|
-
#
|
56
|
-
# @return [Gruf::Instrumentation::Base|NilClass] The requested hook, if exists
|
57
|
-
#
|
58
|
-
def [](name)
|
59
|
-
_registry[name.to_sym]
|
60
|
-
end
|
61
|
-
|
62
|
-
##
|
63
|
-
# Iterate over each hook in the registry
|
64
|
-
#
|
65
|
-
def each
|
66
|
-
_registry.each do |name, s|
|
67
|
-
yield name, s
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
##
|
72
|
-
# @return [Hash<Class>] Return the registry represented as a Hash object
|
73
|
-
#
|
74
|
-
def to_h
|
75
|
-
_registry
|
76
|
-
end
|
77
|
-
|
78
|
-
##
|
79
|
-
# @return [Boolean] Return true if there are any registered hooks
|
80
|
-
#
|
81
|
-
def any?
|
82
|
-
count > 0
|
83
|
-
end
|
84
|
-
|
85
|
-
##
|
86
|
-
# @return [Integer] Return the number of registered hooks
|
87
|
-
#
|
88
|
-
def count
|
89
|
-
to_h.keys.count
|
90
|
-
end
|
91
|
-
|
92
|
-
##
|
93
|
-
# @return [Hash] Clear all existing hooks from the registry
|
94
|
-
#
|
95
|
-
def clear
|
96
|
-
@_registry = {}
|
97
|
-
end
|
98
|
-
|
99
|
-
private
|
100
|
-
|
101
|
-
##
|
102
|
-
# @return [Hash<Class>] Return the current registry
|
103
|
-
#
|
104
|
-
def _registry
|
105
|
-
@_registry ||= {}
|
106
|
-
end
|
107
|
-
end
|
108
|
-
end
|
109
|
-
end
|
110
|
-
end
|
@@ -1,114 +0,0 @@
|
|
1
|
-
# coding: utf-8
|
2
|
-
# Copyright (c) 2017-present, BigCommerce Pty. Ltd. All rights reserved
|
3
|
-
#
|
4
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
5
|
-
# documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
|
6
|
-
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
|
7
|
-
# persons to whom the Software is furnished to do so, subject to the following conditions:
|
8
|
-
#
|
9
|
-
# The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
|
10
|
-
# Software.
|
11
|
-
#
|
12
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
13
|
-
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
14
|
-
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
15
|
-
# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
16
|
-
#
|
17
|
-
require_relative 'request_context'
|
18
|
-
|
19
|
-
module Gruf
|
20
|
-
module Instrumentation
|
21
|
-
##
|
22
|
-
# Base class for an instrumentation strategy. Define a call method to utilize functionality.
|
23
|
-
#
|
24
|
-
class Base
|
25
|
-
include Gruf::Loggable
|
26
|
-
|
27
|
-
# @return [Gruf::Service] service The service to instrument
|
28
|
-
attr_reader :service
|
29
|
-
# @return [Hash] options Options to use when instrumenting the call
|
30
|
-
attr_reader :options
|
31
|
-
|
32
|
-
##
|
33
|
-
# @param [Gruf::Service] service The service to instrument
|
34
|
-
# @param [Hash] options (Optional) Options to use when instrumenting the call
|
35
|
-
#
|
36
|
-
def initialize(service, options = {})
|
37
|
-
@service = service
|
38
|
-
@options = options
|
39
|
-
setup
|
40
|
-
end
|
41
|
-
|
42
|
-
##
|
43
|
-
# Useful for setting up an instrumentation module post instantiation
|
44
|
-
#
|
45
|
-
def setup
|
46
|
-
# noop
|
47
|
-
end
|
48
|
-
|
49
|
-
##
|
50
|
-
# Was this call a success? If a response is a GRPC::BadStatus object, we assume that it was unsuccessful
|
51
|
-
#
|
52
|
-
# @param [Object] response The gRPC response object
|
53
|
-
# @return [Boolean] True if was a successful call
|
54
|
-
#
|
55
|
-
def success?(response)
|
56
|
-
!response.is_a?(GRPC::BadStatus)
|
57
|
-
end
|
58
|
-
|
59
|
-
##
|
60
|
-
# Abstract method that is required for implementing an instrumentation strategy.
|
61
|
-
#
|
62
|
-
# @abstract
|
63
|
-
# @param [Gruf::Instrumentation::RequestContext] _rc The current request context for the call
|
64
|
-
#
|
65
|
-
def call(_rc)
|
66
|
-
raise NotImplementedError
|
67
|
-
end
|
68
|
-
|
69
|
-
##
|
70
|
-
# Hook into the outer_around call to time the request, and pass that to the call method
|
71
|
-
#
|
72
|
-
# @param [Symbol] call_signature The method being called
|
73
|
-
# @param [Object] request The request object
|
74
|
-
# @param [GRPC::ActiveCall] active_call The gRPC active call object
|
75
|
-
# @param [Proc] &_block The execution block for the call
|
76
|
-
# @return [Object] result The result of the block that was called
|
77
|
-
#
|
78
|
-
def outer_around(call_signature, request, active_call, &_block)
|
79
|
-
timed = Timer.time do
|
80
|
-
yield
|
81
|
-
end
|
82
|
-
rc = RequestContext.new(
|
83
|
-
service: service,
|
84
|
-
request: request,
|
85
|
-
response: timed.result,
|
86
|
-
execution_time: timed.time,
|
87
|
-
call_signature: call_signature,
|
88
|
-
active_call: active_call
|
89
|
-
)
|
90
|
-
call(rc)
|
91
|
-
raise rc.response unless rc.success?
|
92
|
-
rc.response
|
93
|
-
end
|
94
|
-
|
95
|
-
##
|
96
|
-
# @return [String] Returns the service name as a translated name separated by periods
|
97
|
-
#
|
98
|
-
def service_key
|
99
|
-
service.class.name.underscore.tr('/', '.')
|
100
|
-
end
|
101
|
-
|
102
|
-
##
|
103
|
-
# Parse the method signature into a service.method name format
|
104
|
-
#
|
105
|
-
# @param [Symbol] call_signature The method call signature
|
106
|
-
# @param [String] delimiter The delimiter to separate service and method keys
|
107
|
-
# @return [String] The parsed service method name
|
108
|
-
#
|
109
|
-
def method_key(call_signature, delimiter: '.')
|
110
|
-
"#{service_key}#{delimiter}#{call_signature}"
|
111
|
-
end
|
112
|
-
end
|
113
|
-
end
|
114
|
-
end
|