protobuffy 3.1.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 +7 -0
- data/.gitignore +21 -0
- data/.travis.yml +12 -0
- data/.yardopts +5 -0
- data/CHANGES.md +261 -0
- data/CONTRIBUTING.md +16 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +14 -0
- data/README.md +58 -0
- data/Rakefile +61 -0
- data/bin/protoc-gen-ruby +17 -0
- data/bin/rpc_server +4 -0
- data/examples/bin/reverse-client-http +4 -0
- data/examples/bin/reverse-client-socket +4 -0
- data/examples/bin/reverse-client-zmq +4 -0
- data/examples/config.ru +6 -0
- data/examples/definitions/example/reverse.proto +12 -0
- data/examples/lib/example/reverse-client.rb +23 -0
- data/examples/lib/example/reverse-service.rb +9 -0
- data/examples/lib/example/reverse.pb.rb +36 -0
- data/lib/protobuf.rb +106 -0
- data/lib/protobuf/cli.rb +249 -0
- data/lib/protobuf/code_generator.rb +41 -0
- data/lib/protobuf/decoder.rb +74 -0
- data/lib/protobuf/deprecator.rb +42 -0
- data/lib/protobuf/descriptors.rb +3 -0
- data/lib/protobuf/descriptors/google/protobuf/compiler/plugin.pb.rb +52 -0
- data/lib/protobuf/descriptors/google/protobuf/descriptor.pb.rb +249 -0
- data/lib/protobuf/encoder.rb +62 -0
- data/lib/protobuf/enum.rb +319 -0
- data/lib/protobuf/exceptions.rb +9 -0
- data/lib/protobuf/field.rb +74 -0
- data/lib/protobuf/field/base_field.rb +280 -0
- data/lib/protobuf/field/bool_field.rb +53 -0
- data/lib/protobuf/field/bytes_field.rb +81 -0
- data/lib/protobuf/field/double_field.rb +26 -0
- data/lib/protobuf/field/enum_field.rb +57 -0
- data/lib/protobuf/field/field_array.rb +86 -0
- data/lib/protobuf/field/fixed32_field.rb +25 -0
- data/lib/protobuf/field/fixed64_field.rb +29 -0
- data/lib/protobuf/field/float_field.rb +38 -0
- data/lib/protobuf/field/int32_field.rb +22 -0
- data/lib/protobuf/field/int64_field.rb +22 -0
- data/lib/protobuf/field/integer_field.rb +24 -0
- data/lib/protobuf/field/message_field.rb +66 -0
- data/lib/protobuf/field/sfixed32_field.rb +28 -0
- data/lib/protobuf/field/sfixed64_field.rb +29 -0
- data/lib/protobuf/field/signed_integer_field.rb +30 -0
- data/lib/protobuf/field/sint32_field.rb +22 -0
- data/lib/protobuf/field/sint64_field.rb +22 -0
- data/lib/protobuf/field/string_field.rb +35 -0
- data/lib/protobuf/field/uint32_field.rb +22 -0
- data/lib/protobuf/field/uint64_field.rb +22 -0
- data/lib/protobuf/field/varint_field.rb +68 -0
- data/lib/protobuf/generators/base.rb +71 -0
- data/lib/protobuf/generators/enum_generator.rb +42 -0
- data/lib/protobuf/generators/extension_generator.rb +28 -0
- data/lib/protobuf/generators/field_generator.rb +132 -0
- data/lib/protobuf/generators/file_generator.rb +140 -0
- data/lib/protobuf/generators/group_generator.rb +113 -0
- data/lib/protobuf/generators/message_generator.rb +99 -0
- data/lib/protobuf/generators/printable.rb +161 -0
- data/lib/protobuf/generators/service_generator.rb +27 -0
- data/lib/protobuf/http.rb +20 -0
- data/lib/protobuf/lifecycle.rb +46 -0
- data/lib/protobuf/logger.rb +86 -0
- data/lib/protobuf/message.rb +182 -0
- data/lib/protobuf/message/fields.rb +122 -0
- data/lib/protobuf/message/serialization.rb +84 -0
- data/lib/protobuf/optionable.rb +23 -0
- data/lib/protobuf/rpc/buffer.rb +79 -0
- data/lib/protobuf/rpc/client.rb +168 -0
- data/lib/protobuf/rpc/connector.rb +21 -0
- data/lib/protobuf/rpc/connectors/base.rb +54 -0
- data/lib/protobuf/rpc/connectors/common.rb +172 -0
- data/lib/protobuf/rpc/connectors/http.rb +90 -0
- data/lib/protobuf/rpc/connectors/socket.rb +73 -0
- data/lib/protobuf/rpc/connectors/zmq.rb +205 -0
- data/lib/protobuf/rpc/dynamic_discovery.pb.rb +47 -0
- data/lib/protobuf/rpc/env.rb +58 -0
- data/lib/protobuf/rpc/error.rb +28 -0
- data/lib/protobuf/rpc/error/client_error.rb +31 -0
- data/lib/protobuf/rpc/error/server_error.rb +43 -0
- data/lib/protobuf/rpc/middleware.rb +25 -0
- data/lib/protobuf/rpc/middleware/exception_handler.rb +36 -0
- data/lib/protobuf/rpc/middleware/logger.rb +91 -0
- data/lib/protobuf/rpc/middleware/request_decoder.rb +83 -0
- data/lib/protobuf/rpc/middleware/response_encoder.rb +88 -0
- data/lib/protobuf/rpc/middleware/runner.rb +18 -0
- data/lib/protobuf/rpc/rpc.pb.rb +53 -0
- data/lib/protobuf/rpc/server.rb +39 -0
- data/lib/protobuf/rpc/servers/http/server.rb +101 -0
- data/lib/protobuf/rpc/servers/http_runner.rb +34 -0
- data/lib/protobuf/rpc/servers/socket/server.rb +113 -0
- data/lib/protobuf/rpc/servers/socket/worker.rb +56 -0
- data/lib/protobuf/rpc/servers/socket_runner.rb +34 -0
- data/lib/protobuf/rpc/servers/zmq/broker.rb +155 -0
- data/lib/protobuf/rpc/servers/zmq/server.rb +313 -0
- data/lib/protobuf/rpc/servers/zmq/util.rb +47 -0
- data/lib/protobuf/rpc/servers/zmq/worker.rb +105 -0
- data/lib/protobuf/rpc/servers/zmq_runner.rb +51 -0
- data/lib/protobuf/rpc/service.rb +179 -0
- data/lib/protobuf/rpc/service_directory.rb +245 -0
- data/lib/protobuf/rpc/service_dispatcher.rb +46 -0
- data/lib/protobuf/rpc/service_filters.rb +273 -0
- data/lib/protobuf/rpc/stat.rb +148 -0
- data/lib/protobuf/socket.rb +22 -0
- data/lib/protobuf/tasks.rb +1 -0
- data/lib/protobuf/tasks/compile.rake +61 -0
- data/lib/protobuf/version.rb +3 -0
- data/lib/protobuf/wire_type.rb +10 -0
- data/lib/protobuf/zmq.rb +21 -0
- data/proto/dynamic_discovery.proto +44 -0
- data/proto/google/protobuf/compiler/plugin.proto +147 -0
- data/proto/google/protobuf/descriptor.proto +620 -0
- data/proto/rpc.proto +62 -0
- data/protobuffy.gemspec +37 -0
- data/spec/benchmark/tasks.rb +113 -0
- data/spec/bin/protoc-gen-ruby_spec.rb +18 -0
- data/spec/data/data.bin +3 -0
- data/spec/data/types.bin +0 -0
- data/spec/encoding/all_types_spec.rb +91 -0
- data/spec/encoding/extreme_values_spec.rb +0 -0
- data/spec/functional/socket_server_spec.rb +59 -0
- data/spec/functional/zmq_server_spec.rb +103 -0
- data/spec/lib/protobuf/cli_spec.rb +267 -0
- data/spec/lib/protobuf/code_generator_spec.rb +60 -0
- data/spec/lib/protobuf/enum_spec.rb +239 -0
- data/spec/lib/protobuf/field/int32_field_spec.rb +7 -0
- data/spec/lib/protobuf/field/string_field_spec.rb +46 -0
- data/spec/lib/protobuf/field_spec.rb +194 -0
- data/spec/lib/protobuf/generators/base_spec.rb +87 -0
- data/spec/lib/protobuf/generators/enum_generator_spec.rb +68 -0
- data/spec/lib/protobuf/generators/extension_generator_spec.rb +43 -0
- data/spec/lib/protobuf/generators/field_generator_spec.rb +99 -0
- data/spec/lib/protobuf/generators/file_generator_spec.rb +29 -0
- data/spec/lib/protobuf/generators/message_generator_spec.rb +0 -0
- data/spec/lib/protobuf/generators/service_generator_spec.rb +43 -0
- data/spec/lib/protobuf/lifecycle_spec.rb +89 -0
- data/spec/lib/protobuf/logger_spec.rb +136 -0
- data/spec/lib/protobuf/message_spec.rb +368 -0
- data/spec/lib/protobuf/optionable_spec.rb +46 -0
- data/spec/lib/protobuf/rpc/client_spec.rb +66 -0
- data/spec/lib/protobuf/rpc/connector_spec.rb +26 -0
- data/spec/lib/protobuf/rpc/connectors/base_spec.rb +50 -0
- data/spec/lib/protobuf/rpc/connectors/common_spec.rb +170 -0
- data/spec/lib/protobuf/rpc/connectors/connector_spec.rb +13 -0
- data/spec/lib/protobuf/rpc/connectors/http_spec.rb +61 -0
- data/spec/lib/protobuf/rpc/connectors/socket_spec.rb +24 -0
- data/spec/lib/protobuf/rpc/connectors/zmq_spec.rb +129 -0
- data/spec/lib/protobuf/rpc/middleware/exception_handler_spec.rb +62 -0
- data/spec/lib/protobuf/rpc/middleware/logger_spec.rb +49 -0
- data/spec/lib/protobuf/rpc/middleware/request_decoder_spec.rb +115 -0
- data/spec/lib/protobuf/rpc/middleware/response_encoder_spec.rb +75 -0
- data/spec/lib/protobuf/rpc/servers/http/server_spec.rb +104 -0
- data/spec/lib/protobuf/rpc/servers/socket_server_spec.rb +38 -0
- data/spec/lib/protobuf/rpc/servers/zmq/server_spec.rb +41 -0
- data/spec/lib/protobuf/rpc/servers/zmq/util_spec.rb +55 -0
- data/spec/lib/protobuf/rpc/servers/zmq/worker_spec.rb +35 -0
- data/spec/lib/protobuf/rpc/service_directory_spec.rb +295 -0
- data/spec/lib/protobuf/rpc/service_dispatcher_spec.rb +52 -0
- data/spec/lib/protobuf/rpc/service_filters_spec.rb +484 -0
- data/spec/lib/protobuf/rpc/service_spec.rb +161 -0
- data/spec/lib/protobuf/rpc/stat_spec.rb +151 -0
- data/spec/lib/protobuf_spec.rb +78 -0
- data/spec/spec_helper.rb +57 -0
- data/spec/support/all.rb +7 -0
- data/spec/support/packed_field.rb +22 -0
- data/spec/support/server.rb +94 -0
- data/spec/support/test/all_types.data.bin +0 -0
- data/spec/support/test/all_types.data.txt +119 -0
- data/spec/support/test/defaults.pb.rb +25 -0
- data/spec/support/test/defaults.proto +9 -0
- data/spec/support/test/enum.pb.rb +59 -0
- data/spec/support/test/enum.proto +34 -0
- data/spec/support/test/extended.pb.rb +22 -0
- data/spec/support/test/extended.proto +10 -0
- data/spec/support/test/extreme_values.data.bin +0 -0
- data/spec/support/test/google_unittest.pb.rb +543 -0
- data/spec/support/test/google_unittest.proto +713 -0
- data/spec/support/test/google_unittest_import.pb.rb +37 -0
- data/spec/support/test/google_unittest_import.proto +64 -0
- data/spec/support/test/google_unittest_import_public.pb.rb +8 -0
- data/spec/support/test/google_unittest_import_public.proto +38 -0
- data/spec/support/test/multi_field_extensions.pb.rb +56 -0
- data/spec/support/test/multi_field_extensions.proto +33 -0
- data/spec/support/test/resource.pb.rb +117 -0
- data/spec/support/test/resource.proto +94 -0
- data/spec/support/test/resource_service.rb +26 -0
- data/spec/support/test_app_file.rb +2 -0
- data/spec/support/tolerance_matcher.rb +40 -0
- metadata +367 -0
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'protobuf/logger'
|
2
|
+
|
3
|
+
module Protobuf
|
4
|
+
module Rpc
|
5
|
+
class ServiceDispatcher
|
6
|
+
include ::Protobuf::Logger::LogMethods
|
7
|
+
|
8
|
+
attr_reader :env
|
9
|
+
|
10
|
+
def initialize(app)
|
11
|
+
# End of the line...
|
12
|
+
end
|
13
|
+
|
14
|
+
def call(env)
|
15
|
+
@env = env
|
16
|
+
|
17
|
+
env.response = dispatch_rpc_request
|
18
|
+
env
|
19
|
+
end
|
20
|
+
|
21
|
+
def rpc_service
|
22
|
+
@rpc_service ||= env.rpc_service.new(env)
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
# Call the given service method.
|
28
|
+
def dispatch_rpc_request
|
29
|
+
unless rpc_service.respond_to?(method_name)
|
30
|
+
raise MethodNotFound.new("#{service_name}##{method_name} is not a publicly defined method.")
|
31
|
+
end
|
32
|
+
|
33
|
+
rpc_service.callable_rpc_method(method_name).call
|
34
|
+
rpc_service.response
|
35
|
+
end
|
36
|
+
|
37
|
+
def method_name
|
38
|
+
env.method_name
|
39
|
+
end
|
40
|
+
|
41
|
+
def service_name
|
42
|
+
env.service_name
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,273 @@
|
|
1
|
+
module Protobuf
|
2
|
+
module Rpc
|
3
|
+
module ServiceFilters
|
4
|
+
|
5
|
+
def self.included(other)
|
6
|
+
other.class_eval do
|
7
|
+
extend Protobuf::Rpc::ServiceFilters::ClassMethods
|
8
|
+
include Protobuf::Rpc::ServiceFilters::InstanceMethods
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
module ClassMethods
|
13
|
+
|
14
|
+
[:after, :around, :before].each do |type|
|
15
|
+
# Setter DSL method for given filter types.
|
16
|
+
#
|
17
|
+
define_method "#{type}_filter" do |*args|
|
18
|
+
set_filters(type, *args)
|
19
|
+
end
|
20
|
+
alias_method "#{type}_action", "#{type}_filter"
|
21
|
+
end
|
22
|
+
|
23
|
+
# Filters hash keyed based on filter type (e.g. :before, :after, :around),
|
24
|
+
# whose values are Sets.
|
25
|
+
#
|
26
|
+
def filters
|
27
|
+
@filters ||= Hash.new { |h,k| h[k] = [] }
|
28
|
+
end
|
29
|
+
|
30
|
+
# Filters hash keyed based on filter type (e.g. :before, :after, :around),
|
31
|
+
# whose values are Sets.
|
32
|
+
#
|
33
|
+
def rescue_filters
|
34
|
+
@rescue_filters ||= {}
|
35
|
+
end
|
36
|
+
|
37
|
+
def rescue_from(*ex_klasses, &block)
|
38
|
+
options = ex_klasses.last.is_a?(Hash) ? ex_klasses.pop : {}
|
39
|
+
callable = options.delete(:with) { block }
|
40
|
+
raise ArgumentError, 'Option :with missing from rescue_from options' if callable.nil?
|
41
|
+
ex_klasses.each { |ex_klass| rescue_filters[ex_klass] = callable }
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def define_filter(type, filter, options = {})
|
47
|
+
return if filter_defined?(type, filter)
|
48
|
+
filters[type] << options.merge({ :callable => filter })
|
49
|
+
remember_filter(type, filter)
|
50
|
+
end
|
51
|
+
|
52
|
+
def defined_filters
|
53
|
+
@defined_filters ||= Hash.new { |h,k| h[k] = Set.new }
|
54
|
+
end
|
55
|
+
|
56
|
+
# Check to see if the filter has been defined.
|
57
|
+
#
|
58
|
+
def filter_defined?(type, filter)
|
59
|
+
defined_filters[type].include?(filter)
|
60
|
+
end
|
61
|
+
|
62
|
+
# Remember that we stored the filter.
|
63
|
+
#
|
64
|
+
def remember_filter(type, filter)
|
65
|
+
defined_filters[type] << filter
|
66
|
+
end
|
67
|
+
|
68
|
+
# Takes a list of actually (or potentially) callable objects.
|
69
|
+
# TODO add support for if/unless
|
70
|
+
# TODO add support for only/except sub-filters
|
71
|
+
#
|
72
|
+
def set_filters(type, *args)
|
73
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
74
|
+
args.each do |filter|
|
75
|
+
define_filter(type, filter, options)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
module InstanceMethods
|
82
|
+
|
83
|
+
private
|
84
|
+
|
85
|
+
# Get back to class filters.
|
86
|
+
#
|
87
|
+
def filters
|
88
|
+
self.class.filters
|
89
|
+
end
|
90
|
+
|
91
|
+
# Predicate which uses the filter options to determine if the filter
|
92
|
+
# should be called. Specifically checks the :if, :unless, :only, and :except
|
93
|
+
# options for every filter. Each option check is expected to return false
|
94
|
+
# if the filter should not be invoked, true if invocation should occur.
|
95
|
+
#
|
96
|
+
def invoke_filter?(rpc_method, filter)
|
97
|
+
return invoke_via_only?(rpc_method, filter) \
|
98
|
+
&& invoke_via_except?(rpc_method, filter) \
|
99
|
+
&& invoke_via_if?(rpc_method, filter) \
|
100
|
+
&& invoke_via_unless?(rpc_method, filter)
|
101
|
+
end
|
102
|
+
|
103
|
+
# If the target rpc endpoint method is listed under an :except option,
|
104
|
+
# return false to indicate that the filter should not be invoked. Any
|
105
|
+
# other target rpc endpoint methods not listed should be invoked.
|
106
|
+
# This option is the opposite of :only.
|
107
|
+
#
|
108
|
+
# Value should be a symbol/string or an array of symbols/strings.
|
109
|
+
#
|
110
|
+
def invoke_via_except?(rpc_method, filter)
|
111
|
+
except = [ filter.fetch(:except) { [] } ].flatten
|
112
|
+
return except.empty? || ! except.include?(rpc_method)
|
113
|
+
end
|
114
|
+
|
115
|
+
# Invoke the given :if callable (if any) and return its return value.
|
116
|
+
# Used by `invoke_filter?` which expects a true/false
|
117
|
+
# return value to determine if we should invoke the target filter.
|
118
|
+
#
|
119
|
+
# Value can either be a symbol/string indicating an instance method to call
|
120
|
+
# or an object that responds to `call`.
|
121
|
+
#
|
122
|
+
def invoke_via_if?(rpc_method, filter)
|
123
|
+
if_check = filter.fetch(:if) { lambda { |service| return true } }
|
124
|
+
do_invoke = case
|
125
|
+
when if_check.nil? then
|
126
|
+
true
|
127
|
+
else
|
128
|
+
call_or_send(if_check)
|
129
|
+
end
|
130
|
+
|
131
|
+
return do_invoke
|
132
|
+
end
|
133
|
+
|
134
|
+
# If the target rpc endpoint method is listed in the :only option,
|
135
|
+
# it should be invoked. Any target rpc endpoint methods not listed in this
|
136
|
+
# option should not be invoked. This option is the opposite of :except.
|
137
|
+
#
|
138
|
+
# Value should be a symbol/string or an array of symbols/strings.
|
139
|
+
#
|
140
|
+
def invoke_via_only?(rpc_method, filter)
|
141
|
+
only = [ filter.fetch(:only) { [] } ].flatten
|
142
|
+
return only.empty? || only.include?(rpc_method)
|
143
|
+
end
|
144
|
+
|
145
|
+
# Invoke the given :unless callable (if any) and return the opposite
|
146
|
+
# of it's return value. Used by `invoke_filter?` which expects a true/false
|
147
|
+
# return value to determine if we should invoke the target filter.
|
148
|
+
#
|
149
|
+
# Value can either be a symbol/string indicating an instance method to call
|
150
|
+
# or an object that responds to `call`.
|
151
|
+
#
|
152
|
+
def invoke_via_unless?(rpc_method, filter)
|
153
|
+
unless_check = filter.fetch(:unless) { lambda { |service| return false } }
|
154
|
+
skip_invoke = case
|
155
|
+
when unless_check.nil? then
|
156
|
+
false
|
157
|
+
else
|
158
|
+
call_or_send(unless_check)
|
159
|
+
end
|
160
|
+
|
161
|
+
return ! skip_invoke
|
162
|
+
end
|
163
|
+
|
164
|
+
def rescue_filters
|
165
|
+
self.class.rescue_filters
|
166
|
+
end
|
167
|
+
|
168
|
+
# Loop over the unwrapped filters and invoke them. An unwrapped filter
|
169
|
+
# is either a before or after filter, not an around filter.
|
170
|
+
#
|
171
|
+
def run_unwrapped_filters(unwrapped_filters, rpc_method, stop_on_false_return = false)
|
172
|
+
unwrapped_filters.each do |filter|
|
173
|
+
if invoke_filter?(rpc_method, filter)
|
174
|
+
return_value = call_or_send(filter[:callable])
|
175
|
+
return false if stop_on_false_return && return_value == false
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
return true
|
180
|
+
end
|
181
|
+
|
182
|
+
# Reverse build a chain of around filters. To implement an around chain,
|
183
|
+
# simply build a method that yields control when it expects the underlying
|
184
|
+
# method to be invoked. If the endpoint should not be run (due to some
|
185
|
+
# condition), simply do not yield.
|
186
|
+
#
|
187
|
+
# Around filters are invoked in the order they are defined, outer to inner,
|
188
|
+
# with the inner-most method called being the actual rpc endpoint.
|
189
|
+
#
|
190
|
+
# Let's say you have a class defined with the following filters:
|
191
|
+
#
|
192
|
+
# class MyService
|
193
|
+
# around_filter :filter1, :filter2, :filter3
|
194
|
+
#
|
195
|
+
# def my_endpoint
|
196
|
+
# # do stuff
|
197
|
+
# end
|
198
|
+
# end
|
199
|
+
#
|
200
|
+
# When the my_endpoint method is invoked using Service#callable_rpc_method,
|
201
|
+
# It is similar to this call chain:
|
202
|
+
#
|
203
|
+
# filter1 do
|
204
|
+
# filter2 do
|
205
|
+
# filter3 do
|
206
|
+
# my_endpoint
|
207
|
+
# end
|
208
|
+
# end
|
209
|
+
# end
|
210
|
+
#
|
211
|
+
def run_around_filters(rpc_method)
|
212
|
+
final = lambda { __send__(rpc_method) }
|
213
|
+
filters[:around].reverse.inject(final) { |previous, filter|
|
214
|
+
if invoke_filter?(rpc_method, filter)
|
215
|
+
lambda { call_or_send(filter[:callable], &previous) }
|
216
|
+
else
|
217
|
+
previous
|
218
|
+
end
|
219
|
+
}.call
|
220
|
+
end
|
221
|
+
|
222
|
+
|
223
|
+
# Entry method to call each filter type in the appropriate order. This should
|
224
|
+
# be used instead of the other run methods directly.
|
225
|
+
#
|
226
|
+
def run_filters(rpc_method)
|
227
|
+
run_rescue_filters do
|
228
|
+
continue = run_unwrapped_filters(filters[:before], rpc_method, true)
|
229
|
+
if continue
|
230
|
+
run_around_filters(rpc_method)
|
231
|
+
run_unwrapped_filters(filters[:after], rpc_method)
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
def run_rescue_filters
|
237
|
+
if rescue_filters.keys.empty?
|
238
|
+
yield
|
239
|
+
else
|
240
|
+
begin
|
241
|
+
yield
|
242
|
+
rescue *rescue_filters.keys => ex
|
243
|
+
callable = rescue_filters.fetch(ex.class) {
|
244
|
+
mapped_klass = rescue_filters.keys.detect { |child_klass| ex.class < child_klass }
|
245
|
+
rescue_filters[mapped_klass]
|
246
|
+
}
|
247
|
+
|
248
|
+
call_or_send(callable, ex)
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
# Call the object if it is callable, otherwise invoke the method using
|
254
|
+
# __send__ assuming that we respond_to it. Return the call's return value.
|
255
|
+
#
|
256
|
+
def call_or_send(callable, *args, &block)
|
257
|
+
return_value = case
|
258
|
+
when callable.respond_to?(:call) then
|
259
|
+
callable.call(self, *args, &block)
|
260
|
+
when respond_to?(callable, true) then
|
261
|
+
__send__(callable, *args, &block)
|
262
|
+
else
|
263
|
+
raise "Object #{callable} is not callable"
|
264
|
+
end
|
265
|
+
|
266
|
+
return return_value
|
267
|
+
end
|
268
|
+
|
269
|
+
end
|
270
|
+
|
271
|
+
end
|
272
|
+
end
|
273
|
+
end
|
@@ -0,0 +1,148 @@
|
|
1
|
+
require 'date'
|
2
|
+
require 'time'
|
3
|
+
require 'protobuf/logger'
|
4
|
+
|
5
|
+
module Protobuf
|
6
|
+
module Rpc
|
7
|
+
class Stat
|
8
|
+
attr_accessor :mode, :start_time, :end_time, :request_size, :dispatcher
|
9
|
+
attr_accessor :response_size, :client, :server, :service, :method_name
|
10
|
+
|
11
|
+
MODES = [:SERVER, :CLIENT].freeze
|
12
|
+
|
13
|
+
# Set the StatsD Client to send stats to. The client must match
|
14
|
+
# the interface provided by lookout-statsd
|
15
|
+
# (https://github.com/lookout/statsd).
|
16
|
+
def self.statsd_client=(statsd_client)
|
17
|
+
@statsd_client = statsd_client
|
18
|
+
end
|
19
|
+
|
20
|
+
# The StatsD Client configured, if any.
|
21
|
+
def self.statsd_client
|
22
|
+
@statsd_client
|
23
|
+
end
|
24
|
+
|
25
|
+
def initialize(mode = :SERVER)
|
26
|
+
@mode = mode
|
27
|
+
@request_size = 0
|
28
|
+
@response_size = 0
|
29
|
+
@success = false
|
30
|
+
@failure_code = nil
|
31
|
+
start
|
32
|
+
end
|
33
|
+
|
34
|
+
def client=(client_host)
|
35
|
+
@client = client_host
|
36
|
+
end
|
37
|
+
|
38
|
+
def client
|
39
|
+
@client || nil
|
40
|
+
end
|
41
|
+
|
42
|
+
def elapsed_time
|
43
|
+
(start_time && end_time ? "#{(end_time - start_time).round(4)}s" : nil)
|
44
|
+
end
|
45
|
+
|
46
|
+
def method_name
|
47
|
+
@method_name ||= @dispatcher.try(:service).try(:method_name)
|
48
|
+
end
|
49
|
+
|
50
|
+
def server=(peer)
|
51
|
+
@server = {:port => peer[0], :ip => peer[1]}
|
52
|
+
end
|
53
|
+
|
54
|
+
def server
|
55
|
+
@server ? "#{@server[:ip]}:#{@server[:port]}" : nil
|
56
|
+
end
|
57
|
+
|
58
|
+
def service
|
59
|
+
@service ||= @dispatcher.try(:service).class.name
|
60
|
+
end
|
61
|
+
|
62
|
+
def sizes
|
63
|
+
if stopped?
|
64
|
+
"#{@request_size}B/#{@response_size}B"
|
65
|
+
else
|
66
|
+
"#{@request_size}B/-"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def start
|
71
|
+
@start_time ||= ::Time.now
|
72
|
+
end
|
73
|
+
|
74
|
+
def stop
|
75
|
+
start unless @start_time
|
76
|
+
@end_time ||= ::Time.now
|
77
|
+
call_statsd_client
|
78
|
+
end
|
79
|
+
|
80
|
+
def success
|
81
|
+
@success = true
|
82
|
+
end
|
83
|
+
|
84
|
+
def failure(code)
|
85
|
+
@failure_code = code
|
86
|
+
end
|
87
|
+
|
88
|
+
def stopped?
|
89
|
+
! end_time.nil?
|
90
|
+
end
|
91
|
+
|
92
|
+
def rpc
|
93
|
+
service && method_name ? "#{service}##{method_name}" : nil
|
94
|
+
end
|
95
|
+
|
96
|
+
def server?
|
97
|
+
@mode == :SERVER
|
98
|
+
end
|
99
|
+
|
100
|
+
def client?
|
101
|
+
@mode == :CLIENT
|
102
|
+
end
|
103
|
+
|
104
|
+
def to_s
|
105
|
+
[
|
106
|
+
server? ? "[SRV]" : "[CLT]",
|
107
|
+
server? ? client : server,
|
108
|
+
trace_id,
|
109
|
+
rpc,
|
110
|
+
sizes,
|
111
|
+
elapsed_time,
|
112
|
+
@end_time.try(:iso8601)
|
113
|
+
].compact.join(' - ')
|
114
|
+
end
|
115
|
+
|
116
|
+
def trace_id
|
117
|
+
::Thread.current.object_id.to_s(16)
|
118
|
+
end
|
119
|
+
|
120
|
+
# Return base path for StatsD metrics
|
121
|
+
def statsd_base_path
|
122
|
+
"rpc.#{service}.#{method_name}".gsub('::', '.').downcase
|
123
|
+
end
|
124
|
+
|
125
|
+
# If a StatsD Client has been configured, send stats to it upon
|
126
|
+
# completion.
|
127
|
+
def call_statsd_client
|
128
|
+
path = statsd_base_path
|
129
|
+
statsd_client = self.class.statsd_client
|
130
|
+
return unless statsd_client
|
131
|
+
|
132
|
+
if @success
|
133
|
+
statsd_client.increment("#{path}.success")
|
134
|
+
elsif @failure_code
|
135
|
+
statsd_client.increment("#{path}.failure.total")
|
136
|
+
statsd_client.increment("#{path}.failure.#{@failure_code}")
|
137
|
+
end
|
138
|
+
|
139
|
+
if start_time && end_time
|
140
|
+
duration = end_time - start_time
|
141
|
+
statsd_client.timing("#{path}.time", duration)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
private :call_statsd_client
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|