gruf 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,104 @@
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
+ class HookDescendantError < StandardError; end
27
+
28
+ class << self
29
+ ##
30
+ # Add an authentication strategy, either through a class or a block
31
+ #
32
+ # @param [String] name
33
+ # @param [Gruf::Hooks::Base|NilClass] hook
34
+ # @return [Class]
35
+ #
36
+ def add(name, hook = nil, &block)
37
+ base = Gruf::Hooks::Base
38
+ hook ||= Class.new(base)
39
+ hook.class_eval(&block) if block_given?
40
+
41
+ # all hooks require either the before, after, or around method
42
+ raise NoMethodError unless hook.method_defined?(:before) || hook.method_defined?(:after) || hook.method_defined?(:around) || hook.method_defined?(:outer_around)
43
+
44
+ raise HookDescendantError, "Hooks must descend from #{base}" unless hook.ancestors.include?(base)
45
+
46
+ _registry[name.to_sym] = hook
47
+ end
48
+
49
+ ##
50
+ # Return a strategy type registry via a hash accessor syntax
51
+ #
52
+ def [](name)
53
+ _registry[name.to_sym]
54
+ end
55
+
56
+ ##
57
+ # Iterate over each hook in the registry
58
+ #
59
+ def each
60
+ _registry.each do |name, s|
61
+ yield name, s
62
+ end
63
+ end
64
+
65
+ ##
66
+ # @return [Hash<Class>]
67
+ #
68
+ def to_h
69
+ _registry
70
+ end
71
+
72
+ ##
73
+ # @return [Boolean]
74
+ #
75
+ def any?
76
+ count > 0
77
+ end
78
+
79
+ ##
80
+ # @return [Integer]
81
+ #
82
+ def count
83
+ to_h.keys.count
84
+ end
85
+
86
+ ##
87
+ # @return [Hash]
88
+ #
89
+ def clear
90
+ @_registry = {}
91
+ end
92
+
93
+ private
94
+
95
+ ##
96
+ # @return [Hash<Class>]
97
+ #
98
+ def _registry
99
+ @_registry ||= {}
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,59 @@
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 Instrumentation
19
+ ##
20
+ # Base class for a hook. Define before, around, or after methods to utilize functionality.
21
+ #
22
+ class Base
23
+ include Gruf::Loggable
24
+
25
+ attr_reader :options, :service, :response, :request, :execution_time, :call_signature, :active_call
26
+
27
+ def initialize(service, request, response, execution_time, call_signature, active_call, options = {})
28
+ @service = service
29
+ @request = request
30
+ @response = response
31
+ @execution_time = execution_time
32
+ @call_signature = call_signature.to_s.gsub('_without_intercept', '').to_sym
33
+ @active_call = active_call
34
+ @options = options
35
+ setup
36
+ end
37
+
38
+ ##
39
+ # Useful for setting up an instrumentation module post instantiation
40
+ #
41
+ def setup
42
+ # noop
43
+ end
44
+
45
+ ##
46
+ # @return [Boolean]
47
+ #
48
+ def success?
49
+ !response.is_a?(GRPC::BadStatus)
50
+ end
51
+
52
+ ##
53
+ #
54
+ def call
55
+ raise NotImplementedError
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,40 @@
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 Instrumentation
19
+ ##
20
+ # Appends the timer metadata to the active call output metadata
21
+ #
22
+ class OutputMetadataTimer < Gruf::Instrumentation::Base
23
+ ##
24
+ # Handle the instrumented response. Note: this will only instrument timings of _successful_ responses.
25
+ #
26
+ def call
27
+ active_call.output_metadata.update(metadata_key => execution_time.to_s)
28
+ end
29
+
30
+ private
31
+
32
+ ##
33
+ # @return [Symbol]
34
+ #
35
+ def metadata_key
36
+ options.fetch(:output_metadata_timer, {}).fetch(:metadata_key, :timer).to_sym
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,95 @@
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 'statsd'
19
+ require_relative 'output_metadata_timer'
20
+
21
+ module Gruf
22
+ module Instrumentation
23
+ ##
24
+ # Registry of all hooks added
25
+ #
26
+ class Registry
27
+ class HookDescendantError < StandardError; end
28
+
29
+ class << self
30
+ ##
31
+ # Add an authentication strategy, either through a class or a block
32
+ #
33
+ # @param [String] name
34
+ # @param [Gruf::Hooks::Base|NilClass] hook
35
+ # @return [Class]
36
+ #
37
+ def add(name, hook = nil, &block)
38
+ base = Gruf::Instrumentation::Base
39
+ hook ||= Class.new(base)
40
+ hook.class_eval(&block) if block_given?
41
+
42
+ raise HookDescendantError, "Hooks must descend from #{base}" unless hook.ancestors.include?(base)
43
+
44
+ _registry[name.to_sym] = hook
45
+ end
46
+
47
+ ##
48
+ # Return a strategy type registry via a hash accessor syntax
49
+ #
50
+ def [](name)
51
+ _registry[name.to_sym]
52
+ end
53
+
54
+ ##
55
+ # Iterate over each hook in the registry
56
+ #
57
+ def each
58
+ _registry.each do |name, s|
59
+ yield name, s
60
+ end
61
+ end
62
+
63
+ ##
64
+ # @return [Hash<Class>]
65
+ #
66
+ def to_h
67
+ _registry
68
+ end
69
+
70
+ ##
71
+ # @return [Boolean]
72
+ #
73
+ def any?
74
+ to_h.keys.count > 0
75
+ end
76
+
77
+ ##
78
+ # @return [Hash]
79
+ #
80
+ def clear
81
+ @_registry = {}
82
+ end
83
+
84
+ private
85
+
86
+ ##
87
+ # @return [Hash<Class>]
88
+ #
89
+ def _registry
90
+ @_registry ||= {}
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,74 @@
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 Instrumentation
19
+ ##
20
+ # Adds increment and timing stats to gRPC routes, pushing data to StatsD
21
+ #
22
+ class Statsd < Gruf::Instrumentation::Base
23
+ ##
24
+ # Push data to StatsD, only doing so if a client is set
25
+ #
26
+ def call
27
+ if client
28
+ client.increment(route_key)
29
+ client.timing(route_key, execution_time)
30
+ else
31
+ Gruf.logger.error 'Statsd module loaded, but no client configured!'
32
+ end
33
+ end
34
+
35
+ private
36
+
37
+ ##
38
+ # @return [String]
39
+ #
40
+ def route_key
41
+ "#{key_prefix}#{service_key}.#{call_signature}"
42
+ end
43
+
44
+ ##
45
+ # @return [String]
46
+ #
47
+ def service_key
48
+ service.class.name.underscore.tr('/', '.')
49
+ end
50
+
51
+ ##
52
+ # @return [String]
53
+ #
54
+ def key_prefix
55
+ prefix = options.fetch(:prefix, '').to_s
56
+ prefix.empty? ? '' : "#{prefix}."
57
+ end
58
+
59
+ ##
60
+ # @return [::Statsd]
61
+ #
62
+ def client
63
+ @client ||= options.fetch(:client, nil)
64
+ end
65
+
66
+ ##
67
+ # @return [Hash]
68
+ #
69
+ def options
70
+ @options.fetch(:statsd, {})
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,26 @@
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 Loggable
19
+ ##
20
+ # @return [Logger]
21
+ #
22
+ def logger
23
+ Gruf.logger
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,33 @@
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 Logger
19
+ def logger
20
+ Gruf.logger
21
+ end
22
+ end
23
+
24
+ module GrpcLogger
25
+ def logger
26
+ Gruf.grpc_logger
27
+ end
28
+ end
29
+ end
30
+
31
+ module GRPC
32
+ extend Gruf::GrpcLogger
33
+ end
@@ -0,0 +1,55 @@
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
+ ##
19
+ # Wraps the active call operation to provide metadata and timing around the request
20
+ #
21
+ class Response
22
+ attr_reader :operation, :metadata, :trailing_metadata, :deadline, :cancelled, :execution_time
23
+
24
+ ##
25
+ # @param [GRPC::ActiveCall::Operation] op
26
+ # @param [Float] execution_time
27
+ #
28
+ def initialize(op, execution_time = nil)
29
+ @operation = op
30
+ @message = op.execute
31
+ @metadata = op.metadata
32
+ @trailing_metadata = op.trailing_metadata
33
+ @deadline = op.deadline
34
+ @cancelled = op.cancelled?
35
+ @execution_time = execution_time || 0.0
36
+ end
37
+
38
+ ##
39
+ # Return the message returned by the request
40
+ #
41
+ def message
42
+ @message ||= op.execute
43
+ end
44
+
45
+ ##
46
+ # Return execution time of the call internally on the server in ms
47
+ #
48
+ # @return [Integer]
49
+ #
50
+ def internal_execution_time
51
+ key = Gruf.instrumentation_options.fetch(:output_metadata_timer, {}).fetch(:metadata_key, 'timer')
52
+ trailing_metadata[key].to_f
53
+ end
54
+ end
55
+ end