TUN-528: Move cloudflared into a separate repo

This commit is contained in:
Areg Harutyunyan
2018-05-01 18:45:06 -05:00
parent e8c621a648
commit d06fc520c7
4726 changed files with 1763680 additions and 0 deletions

View File

@@ -0,0 +1,94 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*,cover
.hypothesis/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# pyenv
.python-version
# celery beat schedule file
celerybeat-schedule
# SageMath parsed files
*.sage.py
# dotenv
.env
# virtualenv
.venv
venv/
ENV/
# Spyder project settings
.spyderproject
# Rope project settings
.ropeproject

View File

@@ -0,0 +1,2 @@
[style]
based_on_style = google

View File

@@ -0,0 +1,4 @@
The repo has moved.
-------------------
https://github.com/opentracing-contrib/python-grpc

View File

@@ -0,0 +1,8 @@
An example showing how to connect gRPC's OpenTracing spans to other OpenTracing
spans.
## Usage
```
python integration_server.py &
python integration_client.py
```

View File

@@ -0,0 +1,213 @@
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: command_line.proto
import sys
_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from google.protobuf import reflection as _reflection
from google.protobuf import symbol_database as _symbol_database
from google.protobuf import descriptor_pb2
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor.FileDescriptor(
name='command_line.proto',
package='command_line',
syntax='proto3',
serialized_pb=_b('\n\x12\x63ommand_line.proto\x12\x0c\x63ommand_line\"\x1e\n\x0e\x43ommandRequest\x12\x0c\n\x04text\x18\x01 \x01(\t\"\x1f\n\x0f\x43ommandResponse\x12\x0c\n\x04text\x18\x01 \x01(\t2T\n\x0b\x43ommandLine\x12\x45\n\x04\x45\x63ho\x12\x1c.command_line.CommandRequest\x1a\x1d.command_line.CommandResponse\"\x00\x62\x06proto3')
)
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
_COMMANDREQUEST = _descriptor.Descriptor(
name='CommandRequest',
full_name='command_line.CommandRequest',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='text', full_name='command_line.CommandRequest.text', index=0,
number=1, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
],
extensions=[
],
nested_types=[],
enum_types=[
],
options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=36,
serialized_end=66,
)
_COMMANDRESPONSE = _descriptor.Descriptor(
name='CommandResponse',
full_name='command_line.CommandResponse',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='text', full_name='command_line.CommandResponse.text', index=0,
number=1, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
],
extensions=[
],
nested_types=[],
enum_types=[
],
options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=68,
serialized_end=99,
)
DESCRIPTOR.message_types_by_name['CommandRequest'] = _COMMANDREQUEST
DESCRIPTOR.message_types_by_name['CommandResponse'] = _COMMANDRESPONSE
CommandRequest = _reflection.GeneratedProtocolMessageType('CommandRequest', (_message.Message,), dict(
DESCRIPTOR = _COMMANDREQUEST,
__module__ = 'command_line_pb2'
# @@protoc_insertion_point(class_scope:command_line.CommandRequest)
))
_sym_db.RegisterMessage(CommandRequest)
CommandResponse = _reflection.GeneratedProtocolMessageType('CommandResponse', (_message.Message,), dict(
DESCRIPTOR = _COMMANDRESPONSE,
__module__ = 'command_line_pb2'
# @@protoc_insertion_point(class_scope:command_line.CommandResponse)
))
_sym_db.RegisterMessage(CommandResponse)
try:
# THESE ELEMENTS WILL BE DEPRECATED.
# Please use the generated *_pb2_grpc.py files instead.
import grpc
from grpc.framework.common import cardinality
from grpc.framework.interfaces.face import utilities as face_utilities
from grpc.beta import implementations as beta_implementations
from grpc.beta import interfaces as beta_interfaces
class CommandLineStub(object):
def __init__(self, channel):
"""Constructor.
Args:
channel: A grpc.Channel.
"""
self.Echo = channel.unary_unary(
'/command_line.CommandLine/Echo',
request_serializer=CommandRequest.SerializeToString,
response_deserializer=CommandResponse.FromString,
)
class CommandLineServicer(object):
def Echo(self, request, context):
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def add_CommandLineServicer_to_server(servicer, server):
rpc_method_handlers = {
'Echo': grpc.unary_unary_rpc_method_handler(
servicer.Echo,
request_deserializer=CommandRequest.FromString,
response_serializer=CommandResponse.SerializeToString,
),
}
generic_handler = grpc.method_handlers_generic_handler(
'command_line.CommandLine', rpc_method_handlers)
server.add_generic_rpc_handlers((generic_handler,))
class BetaCommandLineServicer(object):
"""The Beta API is deprecated for 0.15.0 and later.
It is recommended to use the GA API (classes and functions in this
file not marked beta) for all further purposes. This class was generated
only to ease transition from grpcio<0.15.0 to grpcio>=0.15.0."""
def Echo(self, request, context):
context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)
class BetaCommandLineStub(object):
"""The Beta API is deprecated for 0.15.0 and later.
It is recommended to use the GA API (classes and functions in this
file not marked beta) for all further purposes. This class was generated
only to ease transition from grpcio<0.15.0 to grpcio>=0.15.0."""
def Echo(self, request, timeout, metadata=None, with_call=False, protocol_options=None):
raise NotImplementedError()
Echo.future = None
def beta_create_CommandLine_server(servicer, pool=None, pool_size=None, default_timeout=None, maximum_timeout=None):
"""The Beta API is deprecated for 0.15.0 and later.
It is recommended to use the GA API (classes and functions in this
file not marked beta) for all further purposes. This function was
generated only to ease transition from grpcio<0.15.0 to grpcio>=0.15.0"""
request_deserializers = {
('command_line.CommandLine', 'Echo'): CommandRequest.FromString,
}
response_serializers = {
('command_line.CommandLine', 'Echo'): CommandResponse.SerializeToString,
}
method_implementations = {
('command_line.CommandLine', 'Echo'): face_utilities.unary_unary_inline(servicer.Echo),
}
server_options = beta_implementations.server_options(request_deserializers=request_deserializers, response_serializers=response_serializers, thread_pool=pool, thread_pool_size=pool_size, default_timeout=default_timeout, maximum_timeout=maximum_timeout)
return beta_implementations.server(method_implementations, options=server_options)
def beta_create_CommandLine_stub(channel, host=None, metadata_transformer=None, pool=None, pool_size=None):
"""The Beta API is deprecated for 0.15.0 and later.
It is recommended to use the GA API (classes and functions in this
file not marked beta) for all further purposes. This function was
generated only to ease transition from grpcio<0.15.0 to grpcio>=0.15.0"""
request_serializers = {
('command_line.CommandLine', 'Echo'): CommandRequest.SerializeToString,
}
response_deserializers = {
('command_line.CommandLine', 'Echo'): CommandResponse.FromString,
}
cardinalities = {
'Echo': cardinality.Cardinality.UNARY_UNARY,
}
stub_options = beta_implementations.stub_options(host=host, metadata_transformer=metadata_transformer, request_serializers=request_serializers, response_deserializers=response_deserializers, thread_pool=pool, thread_pool_size=pool_size)
return beta_implementations.dynamic_stub(channel, 'command_line.CommandLine', cardinalities, options=stub_options)
except ImportError:
pass
# @@protoc_insertion_point(module_scope)

View File

@@ -0,0 +1,42 @@
# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
import grpc
from grpc.framework.common import cardinality
from grpc.framework.interfaces.face import utilities as face_utilities
import command_line_pb2 as command__line__pb2
class CommandLineStub(object):
def __init__(self, channel):
"""Constructor.
Args:
channel: A grpc.Channel.
"""
self.Echo = channel.unary_unary(
'/command_line.CommandLine/Echo',
request_serializer=command__line__pb2.CommandRequest.SerializeToString,
response_deserializer=command__line__pb2.CommandResponse.FromString,
)
class CommandLineServicer(object):
def Echo(self, request, context):
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def add_CommandLineServicer_to_server(servicer, server):
rpc_method_handlers = {
'Echo': grpc.unary_unary_rpc_method_handler(
servicer.Echo,
request_deserializer=command__line__pb2.CommandRequest.FromString,
response_serializer=command__line__pb2.CommandResponse.SerializeToString,
),
}
generic_handler = grpc.method_handlers_generic_handler(
'command_line.CommandLine', rpc_method_handlers)
server.add_generic_rpc_handlers((generic_handler,))

View File

@@ -0,0 +1,67 @@
from __future__ import print_function
import time
import argparse
import grpc
from jaeger_client import Config
from grpc_opentracing import open_tracing_client_interceptor, ActiveSpanSource
from grpc_opentracing.grpcext import intercept_channel
import command_line_pb2
class FixedActiveSpanSource(ActiveSpanSource):
def __init__(self):
self.active_span = None
def get_active_span(self):
return self.active_span
def echo(tracer, active_span_source, stub):
with tracer.start_span('command_line_client_span') as span:
active_span_source.active_span = span
response = stub.Echo(
command_line_pb2.CommandRequest(text='Hello, hello'))
print(response.text)
def run():
parser = argparse.ArgumentParser()
parser.add_argument(
'--log_payloads',
action='store_true',
help='log request/response objects to open-tracing spans')
args = parser.parse_args()
config = Config(
config={
'sampler': {
'type': 'const',
'param': 1,
},
'logging': True,
},
service_name='integration-client')
tracer = config.initialize_tracer()
active_span_source = FixedActiveSpanSource()
tracer_interceptor = open_tracing_client_interceptor(
tracer,
active_span_source=active_span_source,
log_payloads=args.log_payloads)
channel = grpc.insecure_channel('localhost:50051')
channel = intercept_channel(channel, tracer_interceptor)
stub = command_line_pb2.CommandLineStub(channel)
echo(tracer, active_span_source, stub)
time.sleep(2)
tracer.close()
time.sleep(2)
if __name__ == '__main__':
run()

View File

@@ -0,0 +1,69 @@
from __future__ import print_function
import time
import argparse
import grpc
from concurrent import futures
from jaeger_client import Config
from grpc_opentracing import open_tracing_server_interceptor
from grpc_opentracing.grpcext import intercept_server
import command_line_pb2
_ONE_DAY_IN_SECONDS = 60 * 60 * 24
class CommandLine(command_line_pb2.CommandLineServicer):
def __init__(self, tracer):
self._tracer = tracer
def Echo(self, request, context):
with self._tracer.start_span(
'command_line_server_span',
child_of=context.get_active_span().context):
return command_line_pb2.CommandResponse(text=request.text)
def serve():
parser = argparse.ArgumentParser()
parser.add_argument(
'--log_payloads',
action='store_true',
help='log request/response objects to open-tracing spans')
args = parser.parse_args()
config = Config(
config={
'sampler': {
'type': 'const',
'param': 1,
},
'logging': True,
},
service_name='integration-server')
tracer = config.initialize_tracer()
tracer_interceptor = open_tracing_server_interceptor(
tracer, log_payloads=args.log_payloads)
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
server = intercept_server(server, tracer_interceptor)
command_line_pb2.add_CommandLineServicer_to_server(
CommandLine(tracer), server)
server.add_insecure_port('[::]:50051')
server.start()
try:
while True:
time.sleep(_ONE_DAY_IN_SECONDS)
except KeyboardInterrupt:
server.stop(0)
time.sleep(2)
tracer.close()
time.sleep(2)
if __name__ == '__main__':
serve()

View File

@@ -0,0 +1,4 @@
from grpc_tools import protoc
protoc.main(('', '-I../protos', '--python_out=.', '--grpc_python_out=.',
'../protos/command_line.proto'))

View File

@@ -0,0 +1,15 @@
syntax = "proto3";
package command_line;
service CommandLine {
rpc Echo(CommandRequest) returns (CommandResponse) {}
}
message CommandRequest {
string text = 1;
}
message CommandResponse {
string text = 1;
}

View File

@@ -0,0 +1,37 @@
syntax = "proto3";
package store;
service Store {
rpc AddItem(AddItemRequest) returns (Empty) {}
rpc AddItems(stream AddItemRequest) returns (Empty) {}
rpc RemoveItem(RemoveItemRequest) returns (RemoveItemResponse) {}
rpc RemoveItems(stream RemoveItemRequest) returns (RemoveItemResponse) {}
rpc ListInventory(Empty) returns (stream QuantityResponse) {}
rpc QueryQuantity(QueryItemRequest) returns (QuantityResponse) {}
rpc QueryQuantities(stream QueryItemRequest)
returns (stream QuantityResponse) {}
}
message Empty {}
message AddItemRequest {
string name = 1;
}
message RemoveItemRequest {
string name = 1;
}
message RemoveItemResponse {
bool was_successful = 1;
}
message QueryItemRequest {
string name = 1;
}
message QuantityResponse {
string name = 1;
int32 count = 2;
}

View File

@@ -0,0 +1,2 @@
grpcio-opentracing>=1.0
jaeger-client>=3.4.0

View File

@@ -0,0 +1,8 @@
An example that demonstrates how the OpenTracing extensions work with
asynchronous and streaming RPC calls.
## Usage
```
python store_server.py &
python store_client.py
```

View File

@@ -0,0 +1,4 @@
from grpc_tools import protoc
protoc.main(('', '-I../protos', '--python_out=.', '--grpc_python_out=.',
'../protos/store.proto'))

View File

@@ -0,0 +1,211 @@
# A OpenTraced client for a Python service that implements the store interface.
from __future__ import print_function
import time
import argparse
from builtins import input, range
import grpc
from jaeger_client import Config
from grpc_opentracing import open_tracing_client_interceptor, \
SpanDecorator
from grpc_opentracing.grpcext import intercept_channel
import store_pb2
class CommandExecuter(object):
def __init__(self, stub):
self._stub = stub
def _execute_rpc(self, method, via, timeout, request_or_iterator):
if via == 'future':
result = getattr(self._stub, method).future(request_or_iterator,
timeout)
return result.result()
elif via == 'with_call':
return getattr(self._stub, method).with_call(request_or_iterator,
timeout)[0]
else:
return getattr(self._stub, method)(request_or_iterator, timeout)
def do_stock_item(self, via, timeout, arguments):
if len(arguments) != 1:
print('must input a single item')
return
request = store_pb2.AddItemRequest(name=arguments[0])
self._execute_rpc('AddItem', via, timeout, request)
def do_stock_items(self, via, timeout, arguments):
if not arguments:
print('must input at least one item')
return
requests = [store_pb2.AddItemRequest(name=name) for name in arguments]
self._execute_rpc('AddItems', via, timeout, iter(requests))
def do_sell_item(self, via, timeout, arguments):
if len(arguments) != 1:
print('must input a single item')
return
request = store_pb2.RemoveItemRequest(name=arguments[0])
response = self._execute_rpc('RemoveItem', via, timeout, request)
if not response.was_successful:
print('unable to sell')
def do_sell_items(self, via, timeout, arguments):
if not arguments:
print('must input at least one item')
return
requests = [
store_pb2.RemoveItemRequest(name=name) for name in arguments
]
response = self._execute_rpc('RemoveItems', via, timeout,
iter(requests))
if not response.was_successful:
print('unable to sell')
def do_inventory(self, via, timeout, arguments):
if arguments:
print('inventory does not take any arguments')
return
if via != 'functor':
print('inventory can only be called via functor')
return
request = store_pb2.Empty()
result = self._execute_rpc('ListInventory', via, timeout, request)
for query in result:
print(query.name, '\t', query.count)
def do_query_item(self, via, timeout, arguments):
if len(arguments) != 1:
print('must input a single item')
return
request = store_pb2.QueryItemRequest(name=arguments[0])
query = self._execute_rpc('QueryQuantity', via, timeout, request)
print(query.name, '\t', query.count)
def do_query_items(self, via, timeout, arguments):
if not arguments:
print('must input at least one item')
return
if via != 'functor':
print('query_items can only be called via functor')
return
requests = [store_pb2.QueryItemRequest(name=name) for name in arguments]
result = self._execute_rpc('QueryQuantities', via, timeout,
iter(requests))
for query in result:
print(query.name, '\t', query.count)
def execute_command(command_executer, command, arguments):
via = 'functor'
timeout = None
for argument_index in range(0, len(arguments), 2):
argument = arguments[argument_index]
if argument == '--via' and argument_index + 1 < len(arguments):
if via not in ('functor', 'with_call', 'future'):
print('invalid --via option')
return
via = arguments[argument_index + 1]
elif argument == '--timeout' and argument_index + 1 < len(arguments):
timeout = float(arguments[argument_index + 1])
else:
arguments = arguments[argument_index:]
break
try:
getattr(command_executer, 'do_' + command)(via, timeout, arguments)
except AttributeError:
print('unknown command: \"%s\"' % command)
INSTRUCTIONS = \
"""Enter commands to interact with the store service:
stock_item Stock a single item.
stock_items Stock one or more items.
sell_item Sell a single item.
sell_items Sell one or more items.
inventory List the store's inventory.
query_item Query the inventory for a single item.
query_items Query the inventory for one or more items.
You can also optionally provide a --via argument to instruct the RPC to be
initiated via either the functor, with_call, or future method; or provide a
--timeout argument to set a deadline for the RPC to be completed.
Example:
> stock_item apple
> stock_items --via future apple milk
> inventory
apple 2
milk 1
"""
def read_and_execute(command_executer):
print(INSTRUCTIONS)
while True:
try:
line = input('> ')
components = line.split()
if not components:
continue
command = components[0]
arguments = components[1:]
execute_command(command_executer, command, arguments)
except EOFError:
break
class StoreSpanDecorator(SpanDecorator):
def __call__(self, span, rpc_info):
span.set_tag('grpc.method', rpc_info.full_method)
span.set_tag('grpc.headers', str(rpc_info.metadata))
span.set_tag('grpc.deadline', str(rpc_info.timeout))
def run():
parser = argparse.ArgumentParser()
parser.add_argument(
'--log_payloads',
action='store_true',
help='log request/response objects to open-tracing spans')
parser.add_argument(
'--include_grpc_tags',
action='store_true',
help='set gRPC-specific tags on spans')
args = parser.parse_args()
config = Config(
config={
'sampler': {
'type': 'const',
'param': 1,
},
'logging': True,
},
service_name='store-client')
tracer = config.initialize_tracer()
span_decorator = None
if args.include_grpc_tags:
span_decorator = StoreSpanDecorator()
tracer_interceptor = open_tracing_client_interceptor(
tracer, log_payloads=args.log_payloads, span_decorator=span_decorator)
channel = grpc.insecure_channel('localhost:50051')
channel = intercept_channel(channel, tracer_interceptor)
stub = store_pb2.StoreStub(channel)
read_and_execute(CommandExecuter(stub))
time.sleep(2)
tracer.close()
time.sleep(2)
if __name__ == '__main__':
run()

View File

@@ -0,0 +1,523 @@
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: store.proto
import sys
_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from google.protobuf import reflection as _reflection
from google.protobuf import symbol_database as _symbol_database
from google.protobuf import descriptor_pb2
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor.FileDescriptor(
name='store.proto',
package='store',
syntax='proto3',
serialized_pb=_b('\n\x0bstore.proto\x12\x05store\"\x07\n\x05\x45mpty\"\x1e\n\x0e\x41\x64\x64ItemRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\"!\n\x11RemoveItemRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\",\n\x12RemoveItemResponse\x12\x16\n\x0ewas_successful\x18\x01 \x01(\x08\" \n\x10QueryItemRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\"/\n\x10QuantityResponse\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\r\n\x05\x63ount\x18\x02 \x01(\x05\x32\xc7\x03\n\x05Store\x12\x30\n\x07\x41\x64\x64Item\x12\x15.store.AddItemRequest\x1a\x0c.store.Empty\"\x00\x12\x33\n\x08\x41\x64\x64Items\x12\x15.store.AddItemRequest\x1a\x0c.store.Empty\"\x00(\x01\x12\x43\n\nRemoveItem\x12\x18.store.RemoveItemRequest\x1a\x19.store.RemoveItemResponse\"\x00\x12\x46\n\x0bRemoveItems\x12\x18.store.RemoveItemRequest\x1a\x19.store.RemoveItemResponse\"\x00(\x01\x12:\n\rListInventory\x12\x0c.store.Empty\x1a\x17.store.QuantityResponse\"\x00\x30\x01\x12\x43\n\rQueryQuantity\x12\x17.store.QueryItemRequest\x1a\x17.store.QuantityResponse\"\x00\x12I\n\x0fQueryQuantities\x12\x17.store.QueryItemRequest\x1a\x17.store.QuantityResponse\"\x00(\x01\x30\x01\x62\x06proto3')
)
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
_EMPTY = _descriptor.Descriptor(
name='Empty',
full_name='store.Empty',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
],
extensions=[
],
nested_types=[],
enum_types=[
],
options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=22,
serialized_end=29,
)
_ADDITEMREQUEST = _descriptor.Descriptor(
name='AddItemRequest',
full_name='store.AddItemRequest',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='name', full_name='store.AddItemRequest.name', index=0,
number=1, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
],
extensions=[
],
nested_types=[],
enum_types=[
],
options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=31,
serialized_end=61,
)
_REMOVEITEMREQUEST = _descriptor.Descriptor(
name='RemoveItemRequest',
full_name='store.RemoveItemRequest',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='name', full_name='store.RemoveItemRequest.name', index=0,
number=1, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
],
extensions=[
],
nested_types=[],
enum_types=[
],
options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=63,
serialized_end=96,
)
_REMOVEITEMRESPONSE = _descriptor.Descriptor(
name='RemoveItemResponse',
full_name='store.RemoveItemResponse',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='was_successful', full_name='store.RemoveItemResponse.was_successful', index=0,
number=1, type=8, cpp_type=7, label=1,
has_default_value=False, default_value=False,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
],
extensions=[
],
nested_types=[],
enum_types=[
],
options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=98,
serialized_end=142,
)
_QUERYITEMREQUEST = _descriptor.Descriptor(
name='QueryItemRequest',
full_name='store.QueryItemRequest',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='name', full_name='store.QueryItemRequest.name', index=0,
number=1, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
],
extensions=[
],
nested_types=[],
enum_types=[
],
options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=144,
serialized_end=176,
)
_QUANTITYRESPONSE = _descriptor.Descriptor(
name='QuantityResponse',
full_name='store.QuantityResponse',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='name', full_name='store.QuantityResponse.name', index=0,
number=1, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
_descriptor.FieldDescriptor(
name='count', full_name='store.QuantityResponse.count', index=1,
number=2, type=5, cpp_type=1, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
],
extensions=[
],
nested_types=[],
enum_types=[
],
options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=178,
serialized_end=225,
)
DESCRIPTOR.message_types_by_name['Empty'] = _EMPTY
DESCRIPTOR.message_types_by_name['AddItemRequest'] = _ADDITEMREQUEST
DESCRIPTOR.message_types_by_name['RemoveItemRequest'] = _REMOVEITEMREQUEST
DESCRIPTOR.message_types_by_name['RemoveItemResponse'] = _REMOVEITEMRESPONSE
DESCRIPTOR.message_types_by_name['QueryItemRequest'] = _QUERYITEMREQUEST
DESCRIPTOR.message_types_by_name['QuantityResponse'] = _QUANTITYRESPONSE
Empty = _reflection.GeneratedProtocolMessageType('Empty', (_message.Message,), dict(
DESCRIPTOR = _EMPTY,
__module__ = 'store_pb2'
# @@protoc_insertion_point(class_scope:store.Empty)
))
_sym_db.RegisterMessage(Empty)
AddItemRequest = _reflection.GeneratedProtocolMessageType('AddItemRequest', (_message.Message,), dict(
DESCRIPTOR = _ADDITEMREQUEST,
__module__ = 'store_pb2'
# @@protoc_insertion_point(class_scope:store.AddItemRequest)
))
_sym_db.RegisterMessage(AddItemRequest)
RemoveItemRequest = _reflection.GeneratedProtocolMessageType('RemoveItemRequest', (_message.Message,), dict(
DESCRIPTOR = _REMOVEITEMREQUEST,
__module__ = 'store_pb2'
# @@protoc_insertion_point(class_scope:store.RemoveItemRequest)
))
_sym_db.RegisterMessage(RemoveItemRequest)
RemoveItemResponse = _reflection.GeneratedProtocolMessageType('RemoveItemResponse', (_message.Message,), dict(
DESCRIPTOR = _REMOVEITEMRESPONSE,
__module__ = 'store_pb2'
# @@protoc_insertion_point(class_scope:store.RemoveItemResponse)
))
_sym_db.RegisterMessage(RemoveItemResponse)
QueryItemRequest = _reflection.GeneratedProtocolMessageType('QueryItemRequest', (_message.Message,), dict(
DESCRIPTOR = _QUERYITEMREQUEST,
__module__ = 'store_pb2'
# @@protoc_insertion_point(class_scope:store.QueryItemRequest)
))
_sym_db.RegisterMessage(QueryItemRequest)
QuantityResponse = _reflection.GeneratedProtocolMessageType('QuantityResponse', (_message.Message,), dict(
DESCRIPTOR = _QUANTITYRESPONSE,
__module__ = 'store_pb2'
# @@protoc_insertion_point(class_scope:store.QuantityResponse)
))
_sym_db.RegisterMessage(QuantityResponse)
try:
# THESE ELEMENTS WILL BE DEPRECATED.
# Please use the generated *_pb2_grpc.py files instead.
import grpc
from grpc.framework.common import cardinality
from grpc.framework.interfaces.face import utilities as face_utilities
from grpc.beta import implementations as beta_implementations
from grpc.beta import interfaces as beta_interfaces
class StoreStub(object):
def __init__(self, channel):
"""Constructor.
Args:
channel: A grpc.Channel.
"""
self.AddItem = channel.unary_unary(
'/store.Store/AddItem',
request_serializer=AddItemRequest.SerializeToString,
response_deserializer=Empty.FromString,
)
self.AddItems = channel.stream_unary(
'/store.Store/AddItems',
request_serializer=AddItemRequest.SerializeToString,
response_deserializer=Empty.FromString,
)
self.RemoveItem = channel.unary_unary(
'/store.Store/RemoveItem',
request_serializer=RemoveItemRequest.SerializeToString,
response_deserializer=RemoveItemResponse.FromString,
)
self.RemoveItems = channel.stream_unary(
'/store.Store/RemoveItems',
request_serializer=RemoveItemRequest.SerializeToString,
response_deserializer=RemoveItemResponse.FromString,
)
self.ListInventory = channel.unary_stream(
'/store.Store/ListInventory',
request_serializer=Empty.SerializeToString,
response_deserializer=QuantityResponse.FromString,
)
self.QueryQuantity = channel.unary_unary(
'/store.Store/QueryQuantity',
request_serializer=QueryItemRequest.SerializeToString,
response_deserializer=QuantityResponse.FromString,
)
self.QueryQuantities = channel.stream_stream(
'/store.Store/QueryQuantities',
request_serializer=QueryItemRequest.SerializeToString,
response_deserializer=QuantityResponse.FromString,
)
class StoreServicer(object):
def AddItem(self, request, context):
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def AddItems(self, request_iterator, context):
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def RemoveItem(self, request, context):
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def RemoveItems(self, request_iterator, context):
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def ListInventory(self, request, context):
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def QueryQuantity(self, request, context):
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def QueryQuantities(self, request_iterator, context):
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def add_StoreServicer_to_server(servicer, server):
rpc_method_handlers = {
'AddItem': grpc.unary_unary_rpc_method_handler(
servicer.AddItem,
request_deserializer=AddItemRequest.FromString,
response_serializer=Empty.SerializeToString,
),
'AddItems': grpc.stream_unary_rpc_method_handler(
servicer.AddItems,
request_deserializer=AddItemRequest.FromString,
response_serializer=Empty.SerializeToString,
),
'RemoveItem': grpc.unary_unary_rpc_method_handler(
servicer.RemoveItem,
request_deserializer=RemoveItemRequest.FromString,
response_serializer=RemoveItemResponse.SerializeToString,
),
'RemoveItems': grpc.stream_unary_rpc_method_handler(
servicer.RemoveItems,
request_deserializer=RemoveItemRequest.FromString,
response_serializer=RemoveItemResponse.SerializeToString,
),
'ListInventory': grpc.unary_stream_rpc_method_handler(
servicer.ListInventory,
request_deserializer=Empty.FromString,
response_serializer=QuantityResponse.SerializeToString,
),
'QueryQuantity': grpc.unary_unary_rpc_method_handler(
servicer.QueryQuantity,
request_deserializer=QueryItemRequest.FromString,
response_serializer=QuantityResponse.SerializeToString,
),
'QueryQuantities': grpc.stream_stream_rpc_method_handler(
servicer.QueryQuantities,
request_deserializer=QueryItemRequest.FromString,
response_serializer=QuantityResponse.SerializeToString,
),
}
generic_handler = grpc.method_handlers_generic_handler(
'store.Store', rpc_method_handlers)
server.add_generic_rpc_handlers((generic_handler,))
class BetaStoreServicer(object):
"""The Beta API is deprecated for 0.15.0 and later.
It is recommended to use the GA API (classes and functions in this
file not marked beta) for all further purposes. This class was generated
only to ease transition from grpcio<0.15.0 to grpcio>=0.15.0."""
def AddItem(self, request, context):
context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)
def AddItems(self, request_iterator, context):
context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)
def RemoveItem(self, request, context):
context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)
def RemoveItems(self, request_iterator, context):
context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)
def ListInventory(self, request, context):
context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)
def QueryQuantity(self, request, context):
context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)
def QueryQuantities(self, request_iterator, context):
context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)
class BetaStoreStub(object):
"""The Beta API is deprecated for 0.15.0 and later.
It is recommended to use the GA API (classes and functions in this
file not marked beta) for all further purposes. This class was generated
only to ease transition from grpcio<0.15.0 to grpcio>=0.15.0."""
def AddItem(self, request, timeout, metadata=None, with_call=False, protocol_options=None):
raise NotImplementedError()
AddItem.future = None
def AddItems(self, request_iterator, timeout, metadata=None, with_call=False, protocol_options=None):
raise NotImplementedError()
AddItems.future = None
def RemoveItem(self, request, timeout, metadata=None, with_call=False, protocol_options=None):
raise NotImplementedError()
RemoveItem.future = None
def RemoveItems(self, request_iterator, timeout, metadata=None, with_call=False, protocol_options=None):
raise NotImplementedError()
RemoveItems.future = None
def ListInventory(self, request, timeout, metadata=None, with_call=False, protocol_options=None):
raise NotImplementedError()
def QueryQuantity(self, request, timeout, metadata=None, with_call=False, protocol_options=None):
raise NotImplementedError()
QueryQuantity.future = None
def QueryQuantities(self, request_iterator, timeout, metadata=None, with_call=False, protocol_options=None):
raise NotImplementedError()
def beta_create_Store_server(servicer, pool=None, pool_size=None, default_timeout=None, maximum_timeout=None):
"""The Beta API is deprecated for 0.15.0 and later.
It is recommended to use the GA API (classes and functions in this
file not marked beta) for all further purposes. This function was
generated only to ease transition from grpcio<0.15.0 to grpcio>=0.15.0"""
request_deserializers = {
('store.Store', 'AddItem'): AddItemRequest.FromString,
('store.Store', 'AddItems'): AddItemRequest.FromString,
('store.Store', 'ListInventory'): Empty.FromString,
('store.Store', 'QueryQuantities'): QueryItemRequest.FromString,
('store.Store', 'QueryQuantity'): QueryItemRequest.FromString,
('store.Store', 'RemoveItem'): RemoveItemRequest.FromString,
('store.Store', 'RemoveItems'): RemoveItemRequest.FromString,
}
response_serializers = {
('store.Store', 'AddItem'): Empty.SerializeToString,
('store.Store', 'AddItems'): Empty.SerializeToString,
('store.Store', 'ListInventory'): QuantityResponse.SerializeToString,
('store.Store', 'QueryQuantities'): QuantityResponse.SerializeToString,
('store.Store', 'QueryQuantity'): QuantityResponse.SerializeToString,
('store.Store', 'RemoveItem'): RemoveItemResponse.SerializeToString,
('store.Store', 'RemoveItems'): RemoveItemResponse.SerializeToString,
}
method_implementations = {
('store.Store', 'AddItem'): face_utilities.unary_unary_inline(servicer.AddItem),
('store.Store', 'AddItems'): face_utilities.stream_unary_inline(servicer.AddItems),
('store.Store', 'ListInventory'): face_utilities.unary_stream_inline(servicer.ListInventory),
('store.Store', 'QueryQuantities'): face_utilities.stream_stream_inline(servicer.QueryQuantities),
('store.Store', 'QueryQuantity'): face_utilities.unary_unary_inline(servicer.QueryQuantity),
('store.Store', 'RemoveItem'): face_utilities.unary_unary_inline(servicer.RemoveItem),
('store.Store', 'RemoveItems'): face_utilities.stream_unary_inline(servicer.RemoveItems),
}
server_options = beta_implementations.server_options(request_deserializers=request_deserializers, response_serializers=response_serializers, thread_pool=pool, thread_pool_size=pool_size, default_timeout=default_timeout, maximum_timeout=maximum_timeout)
return beta_implementations.server(method_implementations, options=server_options)
def beta_create_Store_stub(channel, host=None, metadata_transformer=None, pool=None, pool_size=None):
"""The Beta API is deprecated for 0.15.0 and later.
It is recommended to use the GA API (classes and functions in this
file not marked beta) for all further purposes. This function was
generated only to ease transition from grpcio<0.15.0 to grpcio>=0.15.0"""
request_serializers = {
('store.Store', 'AddItem'): AddItemRequest.SerializeToString,
('store.Store', 'AddItems'): AddItemRequest.SerializeToString,
('store.Store', 'ListInventory'): Empty.SerializeToString,
('store.Store', 'QueryQuantities'): QueryItemRequest.SerializeToString,
('store.Store', 'QueryQuantity'): QueryItemRequest.SerializeToString,
('store.Store', 'RemoveItem'): RemoveItemRequest.SerializeToString,
('store.Store', 'RemoveItems'): RemoveItemRequest.SerializeToString,
}
response_deserializers = {
('store.Store', 'AddItem'): Empty.FromString,
('store.Store', 'AddItems'): Empty.FromString,
('store.Store', 'ListInventory'): QuantityResponse.FromString,
('store.Store', 'QueryQuantities'): QuantityResponse.FromString,
('store.Store', 'QueryQuantity'): QuantityResponse.FromString,
('store.Store', 'RemoveItem'): RemoveItemResponse.FromString,
('store.Store', 'RemoveItems'): RemoveItemResponse.FromString,
}
cardinalities = {
'AddItem': cardinality.Cardinality.UNARY_UNARY,
'AddItems': cardinality.Cardinality.STREAM_UNARY,
'ListInventory': cardinality.Cardinality.UNARY_STREAM,
'QueryQuantities': cardinality.Cardinality.STREAM_STREAM,
'QueryQuantity': cardinality.Cardinality.UNARY_UNARY,
'RemoveItem': cardinality.Cardinality.UNARY_UNARY,
'RemoveItems': cardinality.Cardinality.STREAM_UNARY,
}
stub_options = beta_implementations.stub_options(host=host, metadata_transformer=metadata_transformer, request_serializers=request_serializers, response_deserializers=response_deserializers, thread_pool=pool, thread_pool_size=pool_size)
return beta_implementations.dynamic_stub(channel, 'store.Store', cardinalities, options=stub_options)
except ImportError:
pass
# @@protoc_insertion_point(module_scope)

View File

@@ -0,0 +1,132 @@
# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
import grpc
from grpc.framework.common import cardinality
from grpc.framework.interfaces.face import utilities as face_utilities
import store_pb2 as store__pb2
class StoreStub(object):
def __init__(self, channel):
"""Constructor.
Args:
channel: A grpc.Channel.
"""
self.AddItem = channel.unary_unary(
'/store.Store/AddItem',
request_serializer=store__pb2.AddItemRequest.SerializeToString,
response_deserializer=store__pb2.Empty.FromString,
)
self.AddItems = channel.stream_unary(
'/store.Store/AddItems',
request_serializer=store__pb2.AddItemRequest.SerializeToString,
response_deserializer=store__pb2.Empty.FromString,
)
self.RemoveItem = channel.unary_unary(
'/store.Store/RemoveItem',
request_serializer=store__pb2.RemoveItemRequest.SerializeToString,
response_deserializer=store__pb2.RemoveItemResponse.FromString,
)
self.RemoveItems = channel.stream_unary(
'/store.Store/RemoveItems',
request_serializer=store__pb2.RemoveItemRequest.SerializeToString,
response_deserializer=store__pb2.RemoveItemResponse.FromString,
)
self.ListInventory = channel.unary_stream(
'/store.Store/ListInventory',
request_serializer=store__pb2.Empty.SerializeToString,
response_deserializer=store__pb2.QuantityResponse.FromString,
)
self.QueryQuantity = channel.unary_unary(
'/store.Store/QueryQuantity',
request_serializer=store__pb2.QueryItemRequest.SerializeToString,
response_deserializer=store__pb2.QuantityResponse.FromString,
)
self.QueryQuantities = channel.stream_stream(
'/store.Store/QueryQuantities',
request_serializer=store__pb2.QueryItemRequest.SerializeToString,
response_deserializer=store__pb2.QuantityResponse.FromString,
)
class StoreServicer(object):
def AddItem(self, request, context):
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def AddItems(self, request_iterator, context):
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def RemoveItem(self, request, context):
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def RemoveItems(self, request_iterator, context):
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def ListInventory(self, request, context):
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def QueryQuantity(self, request, context):
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def QueryQuantities(self, request_iterator, context):
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def add_StoreServicer_to_server(servicer, server):
rpc_method_handlers = {
'AddItem': grpc.unary_unary_rpc_method_handler(
servicer.AddItem,
request_deserializer=store__pb2.AddItemRequest.FromString,
response_serializer=store__pb2.Empty.SerializeToString,
),
'AddItems': grpc.stream_unary_rpc_method_handler(
servicer.AddItems,
request_deserializer=store__pb2.AddItemRequest.FromString,
response_serializer=store__pb2.Empty.SerializeToString,
),
'RemoveItem': grpc.unary_unary_rpc_method_handler(
servicer.RemoveItem,
request_deserializer=store__pb2.RemoveItemRequest.FromString,
response_serializer=store__pb2.RemoveItemResponse.SerializeToString,
),
'RemoveItems': grpc.stream_unary_rpc_method_handler(
servicer.RemoveItems,
request_deserializer=store__pb2.RemoveItemRequest.FromString,
response_serializer=store__pb2.RemoveItemResponse.SerializeToString,
),
'ListInventory': grpc.unary_stream_rpc_method_handler(
servicer.ListInventory,
request_deserializer=store__pb2.Empty.FromString,
response_serializer=store__pb2.QuantityResponse.SerializeToString,
),
'QueryQuantity': grpc.unary_unary_rpc_method_handler(
servicer.QueryQuantity,
request_deserializer=store__pb2.QueryItemRequest.FromString,
response_serializer=store__pb2.QuantityResponse.SerializeToString,
),
'QueryQuantities': grpc.stream_stream_rpc_method_handler(
servicer.QueryQuantities,
request_deserializer=store__pb2.QueryItemRequest.FromString,
response_serializer=store__pb2.QuantityResponse.SerializeToString,
),
}
generic_handler = grpc.method_handlers_generic_handler(
'store.Store', rpc_method_handlers)
server.add_generic_rpc_handlers((generic_handler,))

View File

@@ -0,0 +1,122 @@
# A OpenTraced server for a Python service that implements the store interface.
from __future__ import print_function
import time
import argparse
from collections import defaultdict
from six import iteritems
import grpc
from concurrent import futures
from jaeger_client import Config
from grpc_opentracing import open_tracing_server_interceptor, \
SpanDecorator
from grpc_opentracing.grpcext import intercept_server
import store_pb2
_ONE_DAY_IN_SECONDS = 60 * 60 * 24
class Store(store_pb2.StoreServicer):
def __init__(self):
self._inventory = defaultdict(int)
def AddItem(self, request, context):
self._inventory[request.name] += 1
return store_pb2.Empty()
def AddItems(self, request_iter, context):
for request in request_iter:
self._inventory[request.name] += 1
return store_pb2.Empty()
def RemoveItem(self, request, context):
new_quantity = self._inventory[request.name] - 1
if new_quantity < 0:
return store_pb2.RemoveItemResponse(was_successful=False)
self._inventory[request.name] = new_quantity
return store_pb2.RemoveItemResponse(was_successful=True)
def RemoveItems(self, request_iter, context):
response = store_pb2.RemoveItemResponse(was_successful=True)
for request in request_iter:
response = self.RemoveItem(request, context)
if not response.was_successful:
break
return response
def ListInventory(self, request, context):
for name, count in iteritems(self._inventory):
if not count:
continue
else:
yield store_pb2.QuantityResponse(name=name, count=count)
def QueryQuantity(self, request, context):
count = self._inventory[request.name]
return store_pb2.QuantityResponse(name=request.name, count=count)
def QueryQuantities(self, request_iter, context):
for request in request_iter:
count = self._inventory[request.name]
yield store_pb2.QuantityResponse(name=request.name, count=count)
class StoreSpanDecorator(SpanDecorator):
def __call__(self, span, rpc_info):
span.set_tag('grpc.method', rpc_info.full_method)
span.set_tag('grpc.headers', str(rpc_info.metadata))
span.set_tag('grpc.deadline', str(rpc_info.timeout))
def serve():
parser = argparse.ArgumentParser()
parser.add_argument(
'--log_payloads',
action='store_true',
help='log request/response objects to open-tracing spans')
parser.add_argument(
'--include_grpc_tags',
action='store_true',
help='set gRPC-specific tags on spans')
args = parser.parse_args()
config = Config(
config={
'sampler': {
'type': 'const',
'param': 1,
},
'logging': True,
},
service_name='store-server')
tracer = config.initialize_tracer()
span_decorator = None
if args.include_grpc_tags:
span_decorator = StoreSpanDecorator()
tracer_interceptor = open_tracing_server_interceptor(
tracer, log_payloads=args.log_payloads, span_decorator=span_decorator)
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
server = intercept_server(server, tracer_interceptor)
store_pb2.add_StoreServicer_to_server(Store(), server)
server.add_insecure_port('[::]:50051')
server.start()
try:
while True:
time.sleep(_ONE_DAY_IN_SECONDS)
except KeyboardInterrupt:
server.stop(0)
time.sleep(2)
tracer.close()
time.sleep(2)
if __name__ == '__main__':
serve()

View File

@@ -0,0 +1,7 @@
A simple example showing how to set gRPC up to use OpenTracing.
## Usage
```
python trivial_server.py &
python trivial_client.py
```

View File

@@ -0,0 +1,213 @@
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: command_line.proto
import sys
_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from google.protobuf import reflection as _reflection
from google.protobuf import symbol_database as _symbol_database
from google.protobuf import descriptor_pb2
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor.FileDescriptor(
name='command_line.proto',
package='command_line',
syntax='proto3',
serialized_pb=_b('\n\x12\x63ommand_line.proto\x12\x0c\x63ommand_line\"\x1e\n\x0e\x43ommandRequest\x12\x0c\n\x04text\x18\x01 \x01(\t\"\x1f\n\x0f\x43ommandResponse\x12\x0c\n\x04text\x18\x01 \x01(\t2T\n\x0b\x43ommandLine\x12\x45\n\x04\x45\x63ho\x12\x1c.command_line.CommandRequest\x1a\x1d.command_line.CommandResponse\"\x00\x62\x06proto3')
)
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
_COMMANDREQUEST = _descriptor.Descriptor(
name='CommandRequest',
full_name='command_line.CommandRequest',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='text', full_name='command_line.CommandRequest.text', index=0,
number=1, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
],
extensions=[
],
nested_types=[],
enum_types=[
],
options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=36,
serialized_end=66,
)
_COMMANDRESPONSE = _descriptor.Descriptor(
name='CommandResponse',
full_name='command_line.CommandResponse',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='text', full_name='command_line.CommandResponse.text', index=0,
number=1, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
],
extensions=[
],
nested_types=[],
enum_types=[
],
options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=68,
serialized_end=99,
)
DESCRIPTOR.message_types_by_name['CommandRequest'] = _COMMANDREQUEST
DESCRIPTOR.message_types_by_name['CommandResponse'] = _COMMANDRESPONSE
CommandRequest = _reflection.GeneratedProtocolMessageType('CommandRequest', (_message.Message,), dict(
DESCRIPTOR = _COMMANDREQUEST,
__module__ = 'command_line_pb2'
# @@protoc_insertion_point(class_scope:command_line.CommandRequest)
))
_sym_db.RegisterMessage(CommandRequest)
CommandResponse = _reflection.GeneratedProtocolMessageType('CommandResponse', (_message.Message,), dict(
DESCRIPTOR = _COMMANDRESPONSE,
__module__ = 'command_line_pb2'
# @@protoc_insertion_point(class_scope:command_line.CommandResponse)
))
_sym_db.RegisterMessage(CommandResponse)
try:
# THESE ELEMENTS WILL BE DEPRECATED.
# Please use the generated *_pb2_grpc.py files instead.
import grpc
from grpc.framework.common import cardinality
from grpc.framework.interfaces.face import utilities as face_utilities
from grpc.beta import implementations as beta_implementations
from grpc.beta import interfaces as beta_interfaces
class CommandLineStub(object):
def __init__(self, channel):
"""Constructor.
Args:
channel: A grpc.Channel.
"""
self.Echo = channel.unary_unary(
'/command_line.CommandLine/Echo',
request_serializer=CommandRequest.SerializeToString,
response_deserializer=CommandResponse.FromString,
)
class CommandLineServicer(object):
def Echo(self, request, context):
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def add_CommandLineServicer_to_server(servicer, server):
rpc_method_handlers = {
'Echo': grpc.unary_unary_rpc_method_handler(
servicer.Echo,
request_deserializer=CommandRequest.FromString,
response_serializer=CommandResponse.SerializeToString,
),
}
generic_handler = grpc.method_handlers_generic_handler(
'command_line.CommandLine', rpc_method_handlers)
server.add_generic_rpc_handlers((generic_handler,))
class BetaCommandLineServicer(object):
"""The Beta API is deprecated for 0.15.0 and later.
It is recommended to use the GA API (classes and functions in this
file not marked beta) for all further purposes. This class was generated
only to ease transition from grpcio<0.15.0 to grpcio>=0.15.0."""
def Echo(self, request, context):
context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)
class BetaCommandLineStub(object):
"""The Beta API is deprecated for 0.15.0 and later.
It is recommended to use the GA API (classes and functions in this
file not marked beta) for all further purposes. This class was generated
only to ease transition from grpcio<0.15.0 to grpcio>=0.15.0."""
def Echo(self, request, timeout, metadata=None, with_call=False, protocol_options=None):
raise NotImplementedError()
Echo.future = None
def beta_create_CommandLine_server(servicer, pool=None, pool_size=None, default_timeout=None, maximum_timeout=None):
"""The Beta API is deprecated for 0.15.0 and later.
It is recommended to use the GA API (classes and functions in this
file not marked beta) for all further purposes. This function was
generated only to ease transition from grpcio<0.15.0 to grpcio>=0.15.0"""
request_deserializers = {
('command_line.CommandLine', 'Echo'): CommandRequest.FromString,
}
response_serializers = {
('command_line.CommandLine', 'Echo'): CommandResponse.SerializeToString,
}
method_implementations = {
('command_line.CommandLine', 'Echo'): face_utilities.unary_unary_inline(servicer.Echo),
}
server_options = beta_implementations.server_options(request_deserializers=request_deserializers, response_serializers=response_serializers, thread_pool=pool, thread_pool_size=pool_size, default_timeout=default_timeout, maximum_timeout=maximum_timeout)
return beta_implementations.server(method_implementations, options=server_options)
def beta_create_CommandLine_stub(channel, host=None, metadata_transformer=None, pool=None, pool_size=None):
"""The Beta API is deprecated for 0.15.0 and later.
It is recommended to use the GA API (classes and functions in this
file not marked beta) for all further purposes. This function was
generated only to ease transition from grpcio<0.15.0 to grpcio>=0.15.0"""
request_serializers = {
('command_line.CommandLine', 'Echo'): CommandRequest.SerializeToString,
}
response_deserializers = {
('command_line.CommandLine', 'Echo'): CommandResponse.FromString,
}
cardinalities = {
'Echo': cardinality.Cardinality.UNARY_UNARY,
}
stub_options = beta_implementations.stub_options(host=host, metadata_transformer=metadata_transformer, request_serializers=request_serializers, response_deserializers=response_deserializers, thread_pool=pool, thread_pool_size=pool_size)
return beta_implementations.dynamic_stub(channel, 'command_line.CommandLine', cardinalities, options=stub_options)
except ImportError:
pass
# @@protoc_insertion_point(module_scope)

View File

@@ -0,0 +1,42 @@
# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
import grpc
from grpc.framework.common import cardinality
from grpc.framework.interfaces.face import utilities as face_utilities
import command_line_pb2 as command__line__pb2
class CommandLineStub(object):
def __init__(self, channel):
"""Constructor.
Args:
channel: A grpc.Channel.
"""
self.Echo = channel.unary_unary(
'/command_line.CommandLine/Echo',
request_serializer=command__line__pb2.CommandRequest.SerializeToString,
response_deserializer=command__line__pb2.CommandResponse.FromString,
)
class CommandLineServicer(object):
def Echo(self, request, context):
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def add_CommandLineServicer_to_server(servicer, server):
rpc_method_handlers = {
'Echo': grpc.unary_unary_rpc_method_handler(
servicer.Echo,
request_deserializer=command__line__pb2.CommandRequest.FromString,
response_serializer=command__line__pb2.CommandResponse.SerializeToString,
),
}
generic_handler = grpc.method_handlers_generic_handler(
'command_line.CommandLine', rpc_method_handlers)
server.add_generic_rpc_handlers((generic_handler,))

View File

@@ -0,0 +1,4 @@
from grpc_tools import protoc
protoc.main(('', '-I../protos', '--python_out=.', '--grpc_python_out=.',
'../protos/command_line.proto'))

View File

@@ -0,0 +1,47 @@
from __future__ import print_function
import time
import argparse
import grpc
from jaeger_client import Config
from grpc_opentracing import open_tracing_client_interceptor
from grpc_opentracing.grpcext import intercept_channel
import command_line_pb2
def run():
parser = argparse.ArgumentParser()
parser.add_argument(
'--log_payloads',
action='store_true',
help='log request/response objects to open-tracing spans')
args = parser.parse_args()
config = Config(
config={
'sampler': {
'type': 'const',
'param': 1,
},
'logging': True,
},
service_name='trivial-client')
tracer = config.initialize_tracer()
tracer_interceptor = open_tracing_client_interceptor(
tracer, log_payloads=args.log_payloads)
channel = grpc.insecure_channel('localhost:50051')
channel = intercept_channel(channel, tracer_interceptor)
stub = command_line_pb2.CommandLineStub(channel)
response = stub.Echo(command_line_pb2.CommandRequest(text='Hello, hello'))
print(response.text)
time.sleep(2)
tracer.close()
time.sleep(2)
if __name__ == '__main__':
run()

View File

@@ -0,0 +1,62 @@
from __future__ import print_function
import time
import argparse
import grpc
from concurrent import futures
from jaeger_client import Config
from grpc_opentracing import open_tracing_server_interceptor
from grpc_opentracing.grpcext import intercept_server
import command_line_pb2
_ONE_DAY_IN_SECONDS = 60 * 60 * 24
class CommandLine(command_line_pb2.CommandLineServicer):
def Echo(self, request, context):
return command_line_pb2.CommandResponse(text=request.text)
def serve():
parser = argparse.ArgumentParser()
parser.add_argument(
'--log_payloads',
action='store_true',
help='log request/response objects to open-tracing spans')
args = parser.parse_args()
config = Config(
config={
'sampler': {
'type': 'const',
'param': 1,
},
'logging': True,
},
service_name='trivial-server')
tracer = config.initialize_tracer()
tracer_interceptor = open_tracing_server_interceptor(
tracer, log_payloads=args.log_payloads)
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
server = intercept_server(server, tracer_interceptor)
command_line_pb2.add_CommandLineServicer_to_server(CommandLine(), server)
server.add_insecure_port('[::]:50051')
server.start()
try:
while True:
time.sleep(_ONE_DAY_IN_SECONDS)
except KeyboardInterrupt:
server.stop(0)
time.sleep(2)
tracer.close()
time.sleep(2)
if __name__ == '__main__':
serve()

View File

@@ -0,0 +1,96 @@
import abc
import enum
import six
import grpc
class ActiveSpanSource(six.with_metaclass(abc.ABCMeta)):
"""Provides a way to access an the active span."""
@abc.abstractmethod
def get_active_span(self):
"""Identifies the active span.
Returns:
An object that implements the opentracing.Span interface.
"""
raise NotImplementedError()
class RpcInfo(six.with_metaclass(abc.ABCMeta)):
"""Provides information for an RPC call.
Attributes:
full_method: A string of the full RPC method, i.e., /package.service/method.
metadata: The initial :term:`metadata`.
timeout: The length of time in seconds to wait for the computation to
terminate or be cancelled.
request: The RPC request or None for request-streaming RPCs.
response: The RPC response or None for response-streaming or erroring RPCs.
error: The RPC error or None for successful RPCs.
"""
class SpanDecorator(six.with_metaclass(abc.ABCMeta)):
"""Provides a mechanism to add arbitrary tags/logs/etc to the
opentracing.Span associated with client and/or server RPCs."""
@abc.abstractmethod
def __call__(self, span, rpc_info):
"""Customizes an RPC span.
Args:
span: The client-side or server-side opentracing.Span for the RPC.
rpc_info: An RpcInfo describing the RPC.
"""
raise NotImplementedError()
def open_tracing_client_interceptor(tracer,
active_span_source=None,
log_payloads=False,
span_decorator=None):
"""Creates an invocation-side interceptor that can be use with gRPC to add
OpenTracing information.
Args:
tracer: An object implmenting the opentracing.Tracer interface.
active_span_source: An optional ActiveSpanSource to customize how the
active span is determined.
log_payloads: Indicates whether requests should be logged.
span_decorator: An optional SpanDecorator.
Returns:
An invocation-side interceptor object.
"""
from grpc_opentracing import _client
return _client.OpenTracingClientInterceptor(tracer, active_span_source,
log_payloads, span_decorator)
def open_tracing_server_interceptor(tracer,
log_payloads=False,
span_decorator=None):
"""Creates a service-side interceptor that can be use with gRPC to add
OpenTracing information.
Args:
tracer: An object implmenting the opentracing.Tracer interface.
log_payloads: Indicates whether requests should be logged.
span_decorator: An optional SpanDecorator.
Returns:
A service-side interceptor object.
"""
from grpc_opentracing import _server
return _server.OpenTracingServerInterceptor(tracer, log_payloads,
span_decorator)
################################### __all__ #################################
__all__ = ('ActiveSpanSource', 'RpcInfo', 'SpanDecorator',
'open_tracing_client_interceptor',
'open_tracing_server_interceptor',)

View File

@@ -0,0 +1,209 @@
"""Implementation of the invocation-side open-tracing interceptor."""
import sys
import logging
import time
from six import iteritems
import grpc
from grpc_opentracing import grpcext
from grpc_opentracing._utilities import get_method_type, get_deadline_millis,\
log_or_wrap_request_or_iterator, RpcInfo
import opentracing
from opentracing.ext import tags as ot_tags
class _GuardedSpan(object):
def __init__(self, span):
self.span = span
self._engaged = True
def __enter__(self):
self.span.__enter__()
return self
def __exit__(self, *args, **kwargs):
if self._engaged:
return self.span.__exit__(*args, **kwargs)
else:
return False
def release(self):
self._engaged = False
return self.span
def _inject_span_context(tracer, span, metadata):
headers = {}
try:
tracer.inject(span.context, opentracing.Format.HTTP_HEADERS, headers)
except (opentracing.UnsupportedFormatException,
opentracing.InvalidCarrierException,
opentracing.SpanContextCorruptedException) as e:
logging.exception('tracer.inject() failed')
span.log_kv({'event': 'error', 'error.object': e})
return metadata
metadata = () if metadata is None else tuple(metadata)
return metadata + tuple(iteritems(headers))
def _make_future_done_callback(span, rpc_info, log_payloads, span_decorator):
def callback(response_future):
with span:
code = response_future.code()
if code != grpc.StatusCode.OK:
span.set_tag('error', True)
error_log = {'event': 'error', 'error.kind': str(code)}
details = response_future.details()
if details is not None:
error_log['message'] = details
span.log_kv(error_log)
rpc_info.error = code
if span_decorator is not None:
span_decorator(span, rpc_info)
return
response = response_future.result()
rpc_info.response = response
if log_payloads:
span.log_kv({'response': response})
if span_decorator is not None:
span_decorator(span, rpc_info)
return callback
class OpenTracingClientInterceptor(grpcext.UnaryClientInterceptor,
grpcext.StreamClientInterceptor):
def __init__(self, tracer, active_span_source, log_payloads,
span_decorator):
self._tracer = tracer
self._active_span_source = active_span_source
self._log_payloads = log_payloads
self._span_decorator = span_decorator
def _start_span(self, method):
active_span_context = None
if self._active_span_source is not None:
active_span = self._active_span_source.get_active_span()
if active_span is not None:
active_span_context = active_span.context
tags = {
ot_tags.COMPONENT: 'grpc',
ot_tags.SPAN_KIND: ot_tags.SPAN_KIND_RPC_CLIENT
}
return self._tracer.start_span(
operation_name=method, child_of=active_span_context, tags=tags)
def _trace_result(self, guarded_span, rpc_info, result):
# If the RPC is called asynchronously, release the guard and add a callback
# so that the span can be finished once the future is done.
if isinstance(result, grpc.Future):
result.add_done_callback(
_make_future_done_callback(guarded_span.release(
), rpc_info, self._log_payloads, self._span_decorator))
return result
response = result
# Handle the case when the RPC is initiated via the with_call
# method and the result is a tuple with the first element as the
# response.
# http://www.grpc.io/grpc/python/grpc.html#grpc.UnaryUnaryMultiCallable.with_call
if isinstance(result, tuple):
response = result[0]
rpc_info.response = response
if self._log_payloads:
guarded_span.span.log_kv({'response': response})
if self._span_decorator is not None:
self._span_decorator(guarded_span.span, rpc_info)
return result
def _start_guarded_span(self, *args, **kwargs):
return _GuardedSpan(self._start_span(*args, **kwargs))
def intercept_unary(self, request, metadata, client_info, invoker):
with self._start_guarded_span(client_info.full_method) as guarded_span:
metadata = _inject_span_context(self._tracer, guarded_span.span,
metadata)
rpc_info = RpcInfo(
full_method=client_info.full_method,
metadata=metadata,
timeout=client_info.timeout,
request=request)
if self._log_payloads:
guarded_span.span.log_kv({'request': request})
try:
result = invoker(request, metadata)
except:
e = sys.exc_info()[0]
guarded_span.span.set_tag('error', True)
guarded_span.span.log_kv({'event': 'error', 'error.object': e})
rpc_info.error = e
if self._span_decorator is not None:
self._span_decorator(guarded_span.span, rpc_info)
raise
return self._trace_result(guarded_span, rpc_info, result)
# For RPCs that stream responses, the result can be a generator. To record
# the span across the generated responses and detect any errors, we wrap the
# result in a new generator that yields the response values.
def _intercept_server_stream(self, request_or_iterator, metadata,
client_info, invoker):
with self._start_span(client_info.full_method) as span:
metadata = _inject_span_context(self._tracer, span, metadata)
rpc_info = RpcInfo(
full_method=client_info.full_method,
metadata=metadata,
timeout=client_info.timeout)
if client_info.is_client_stream:
rpc_info.request = request_or_iterator
if self._log_payloads:
request_or_iterator = log_or_wrap_request_or_iterator(
span, client_info.is_client_stream, request_or_iterator)
try:
result = invoker(request_or_iterator, metadata)
for response in result:
if self._log_payloads:
span.log_kv({'response': response})
yield response
except:
e = sys.exc_info()[0]
span.set_tag('error', True)
span.log_kv({'event': 'error', 'error.object': e})
rpc_info.error = e
if self._span_decorator is not None:
self._span_decorator(span, rpc_info)
raise
if self._span_decorator is not None:
self._span_decorator(span, rpc_info)
def intercept_stream(self, request_or_iterator, metadata, client_info,
invoker):
if client_info.is_server_stream:
return self._intercept_server_stream(request_or_iterator, metadata,
client_info, invoker)
with self._start_guarded_span(client_info.full_method) as guarded_span:
metadata = _inject_span_context(self._tracer, guarded_span.span,
metadata)
rpc_info = RpcInfo(
full_method=client_info.full_method,
metadata=metadata,
timeout=client_info.timeout,
request=request_or_iterator)
if self._log_payloads:
request_or_iterator = log_or_wrap_request_or_iterator(
guarded_span.span, client_info.is_client_stream,
request_or_iterator)
try:
result = invoker(request_or_iterator, metadata)
except:
e = sys.exc_info()[0]
guarded_span.span.set_tag('error', True)
guarded_span.span.log_kv({'event': 'error', 'error.object': e})
rpc_info.error = e
if self._span_decorator is not None:
self._span_decorator(guarded_span.span, rpc_info)
raise
return self._trace_result(guarded_span, rpc_info, result)

View File

@@ -0,0 +1,227 @@
"""Implementation of the service-side open-tracing interceptor."""
import sys
import logging
import re
import grpc
from grpc_opentracing import grpcext, ActiveSpanSource
from grpc_opentracing._utilities import get_method_type, get_deadline_millis,\
log_or_wrap_request_or_iterator, RpcInfo
import opentracing
from opentracing.ext import tags as ot_tags
class _OpenTracingServicerContext(grpc.ServicerContext, ActiveSpanSource):
def __init__(self, servicer_context, active_span):
self._servicer_context = servicer_context
self._active_span = active_span
self.code = grpc.StatusCode.OK
self.details = None
def is_active(self, *args, **kwargs):
return self._servicer_context.is_active(*args, **kwargs)
def time_remaining(self, *args, **kwargs):
return self._servicer_context.time_remaining(*args, **kwargs)
def cancel(self, *args, **kwargs):
return self._servicer_context.cancel(*args, **kwargs)
def add_callback(self, *args, **kwargs):
return self._servicer_context.add_callback(*args, **kwargs)
def invocation_metadata(self, *args, **kwargs):
return self._servicer_context.invocation_metadata(*args, **kwargs)
def peer(self, *args, **kwargs):
return self._servicer_context.peer(*args, **kwargs)
def peer_identities(self, *args, **kwargs):
return self._servicer_context.peer_identities(*args, **kwargs)
def peer_identity_key(self, *args, **kwargs):
return self._servicer_context.peer_identity_key(*args, **kwargs)
def auth_context(self, *args, **kwargs):
return self._servicer_context.auth_context(*args, **kwargs)
def send_initial_metadata(self, *args, **kwargs):
return self._servicer_context.send_initial_metadata(*args, **kwargs)
def set_trailing_metadata(self, *args, **kwargs):
return self._servicer_context.set_trailing_metadata(*args, **kwargs)
def set_code(self, code):
self.code = code
return self._servicer_context.set_code(code)
def set_details(self, details):
self.details = details
return self._servicer_context.set_details(details)
def get_active_span(self):
return self._active_span
def _add_peer_tags(peer_str, tags):
ipv4_re = r"ipv4:(?P<address>.+):(?P<port>\d+)"
match = re.match(ipv4_re, peer_str)
if match:
tags[ot_tags.PEER_HOST_IPV4] = match.group('address')
tags[ot_tags.PEER_PORT] = match.group('port')
return
ipv6_re = r"ipv6:\[(?P<address>.+)\]:(?P<port>\d+)"
match = re.match(ipv6_re, peer_str)
if match:
tags[ot_tags.PEER_HOST_IPV6] = match.group('address')
tags[ot_tags.PEER_PORT] = match.group('port')
return
logging.warning('Unrecognized peer: \"%s\"', peer_str)
# On the service-side, errors can be signaled either by exceptions or by calling
# `set_code` on the `servicer_context`. This function checks for the latter and
# updates the span accordingly.
def _check_error_code(span, servicer_context, rpc_info):
if servicer_context.code != grpc.StatusCode.OK:
span.set_tag('error', True)
error_log = {'event': 'error', 'error.kind': str(servicer_context.code)}
if servicer_context.details is not None:
error_log['message'] = servicer_context.details
span.log_kv(error_log)
rpc_info.error = servicer_context.code
class OpenTracingServerInterceptor(grpcext.UnaryServerInterceptor,
grpcext.StreamServerInterceptor):
def __init__(self, tracer, log_payloads, span_decorator):
self._tracer = tracer
self._log_payloads = log_payloads
self._span_decorator = span_decorator
def _start_span(self, servicer_context, method):
span_context = None
error = None
metadata = servicer_context.invocation_metadata()
try:
if metadata:
span_context = self._tracer.extract(
opentracing.Format.HTTP_HEADERS, dict(metadata))
except (opentracing.UnsupportedFormatException,
opentracing.InvalidCarrierException,
opentracing.SpanContextCorruptedException) as e:
logging.exception('tracer.extract() failed')
error = e
tags = {
ot_tags.COMPONENT: 'grpc',
ot_tags.SPAN_KIND: ot_tags.SPAN_KIND_RPC_SERVER
}
_add_peer_tags(servicer_context.peer(), tags)
span = self._tracer.start_span(
operation_name=method, child_of=span_context, tags=tags)
if error is not None:
span.log_kv({'event': 'error', 'error.object': error})
return span
def intercept_unary(self, request, servicer_context, server_info, handler):
with self._start_span(servicer_context,
server_info.full_method) as span:
rpc_info = RpcInfo(
full_method=server_info.full_method,
metadata=servicer_context.invocation_metadata(),
timeout=servicer_context.time_remaining(),
request=request)
if self._log_payloads:
span.log_kv({'request': request})
servicer_context = _OpenTracingServicerContext(
servicer_context, span)
try:
response = handler(request, servicer_context)
except:
e = sys.exc_info()[0]
span.set_tag('error', True)
span.log_kv({'event': 'error', 'error.object': e})
rpc_info.error = e
if self._span_decorator is not None:
self._span_decorator(span, rpc_info)
raise
if self._log_payloads:
span.log_kv({'response': response})
_check_error_code(span, servicer_context, rpc_info)
rpc_info.response = response
if self._span_decorator is not None:
self._span_decorator(span, rpc_info)
return response
# For RPCs that stream responses, the result can be a generator. To record
# the span across the generated responses and detect any errors, we wrap the
# result in a new generator that yields the response values.
def _intercept_server_stream(self, request_or_iterator, servicer_context,
server_info, handler):
with self._start_span(servicer_context,
server_info.full_method) as span:
rpc_info = RpcInfo(
full_method=server_info.full_method,
metadata=servicer_context.invocation_metadata(),
timeout=servicer_context.time_remaining())
if not server_info.is_client_stream:
rpc_info.request = request_or_iterator
if self._log_payloads:
request_or_iterator = log_or_wrap_request_or_iterator(
span, server_info.is_client_stream, request_or_iterator)
servicer_context = _OpenTracingServicerContext(
servicer_context, span)
try:
result = handler(request_or_iterator, servicer_context)
for response in result:
if self._log_payloads:
span.log_kv({'response': response})
yield response
except:
e = sys.exc_info()[0]
span.set_tag('error', True)
span.log_kv({'event': 'error', 'error.object': e})
rpc_info.error = e
if self._span_decorator is not None:
self._span_decorator(span, rpc_info)
raise
_check_error_code(span, servicer_context, rpc_info)
if self._span_decorator is not None:
self._span_decorator(span, rpc_info)
def intercept_stream(self, request_or_iterator, servicer_context,
server_info, handler):
if server_info.is_server_stream:
return self._intercept_server_stream(
request_or_iterator, servicer_context, server_info, handler)
with self._start_span(servicer_context,
server_info.full_method) as span:
rpc_info = RpcInfo(
full_method=server_info.full_method,
metadata=servicer_context.invocation_metadata(),
timeout=servicer_context.time_remaining())
if self._log_payloads:
request_or_iterator = log_or_wrap_request_or_iterator(
span, server_info.is_client_stream, request_or_iterator)
servicer_context = _OpenTracingServicerContext(
servicer_context, span)
try:
response = handler(request_or_iterator, servicer_context)
except:
e = sys.exc_info()[0]
span.set_tag('error', True)
span.log_kv({'event': 'error', 'error.object': e})
rpc_info.error = e
if self._span_decorator is not None:
self._span_decorator(span, rpc_info)
raise
if self._log_payloads:
span.log_kv({'response': response})
_check_error_code(span, servicer_context, rpc_info)
rpc_info.response = response
if self._span_decorator is not None:
self._span_decorator(span, rpc_info)
return response

View File

@@ -0,0 +1,65 @@
"""Internal utilities for gRPC OpenTracing."""
import collections
import grpc_opentracing
class RpcInfo(grpc_opentracing.RpcInfo):
def __init__(self,
full_method=None,
metadata=None,
timeout=None,
request=None,
response=None,
error=None):
self.full_method = full_method
self.metadata = metadata
self.timeout = timeout
self.request = request
self.response = response
self.error = error
def get_method_type(is_client_stream, is_server_stream):
if is_client_stream and is_server_stream:
return 'BIDI_STREAMING'
elif is_client_stream:
return 'CLIENT_STREAMING'
elif is_server_stream:
return 'SERVER_STREAMING'
else:
return 'UNARY'
def get_deadline_millis(timeout):
if timeout is None:
return 'None'
return str(int(round(timeout * 1000)))
class _RequestLoggingIterator(object):
def __init__(self, request_iterator, span):
self._request_iterator = request_iterator
self._span = span
def __iter__(self):
return self
def next(self):
request = next(self._request_iterator)
self._span.log_kv({'request': request})
return request
def __next__(self):
return self.next()
def log_or_wrap_request_or_iterator(span, is_client_stream,
request_or_iterator):
if is_client_stream:
return _RequestLoggingIterator(request_or_iterator, span)
else:
span.log_kv({'request': request_or_iterator})
return request_or_iterator

View File

@@ -0,0 +1,185 @@
import abc
import six
class UnaryClientInfo(six.with_metaclass(abc.ABCMeta)):
"""Consists of various information about a unary RPC on the invocation-side.
Attributes:
full_method: A string of the full RPC method, i.e., /package.service/method.
timeout: The length of time in seconds to wait for the computation to
terminate or be cancelled, or None if this method should block until
the computation is terminated or is cancelled no matter how long that
takes.
"""
class StreamClientInfo(six.with_metaclass(abc.ABCMeta)):
"""Consists of various information about a stream RPC on the invocation-side.
Attributes:
full_method: A string of the full RPC method, i.e., /package.service/method.
is_client_stream: Indicates whether the RPC is client-streaming.
is_server_stream: Indicates whether the RPC is server-streaming.
timeout: The length of time in seconds to wait for the computation to
terminate or be cancelled, or None if this method should block until
the computation is terminated or is cancelled no matter how long that
takes.
"""
class UnaryClientInterceptor(six.with_metaclass(abc.ABCMeta)):
"""Affords intercepting unary-unary RPCs on the invocation-side."""
@abc.abstractmethod
def intercept_unary(self, request, metadata, client_info, invoker):
"""Intercepts unary-unary RPCs on the invocation-side.
Args:
request: The request value for the RPC.
metadata: Optional :term:`metadata` to be transmitted to the
service-side of the RPC.
client_info: A UnaryClientInfo containing various information about
the RPC.
invoker: The handler to complete the RPC on the client. It is the
interceptor's responsibility to call it.
Returns:
The result from calling invoker(request, metadata).
"""
raise NotImplementedError()
class StreamClientInterceptor(six.with_metaclass(abc.ABCMeta)):
"""Affords intercepting stream RPCs on the invocation-side."""
@abc.abstractmethod
def intercept_stream(self, request_or_iterator, metadata, client_info,
invoker):
"""Intercepts stream RPCs on the invocation-side.
Args:
request_or_iterator: The request value for the RPC if
`client_info.is_client_stream` is `false`; otherwise, an iterator of
request values.
metadata: Optional :term:`metadata` to be transmitted to the service-side
of the RPC.
client_info: A StreamClientInfo containing various information about
the RPC.
invoker: The handler to complete the RPC on the client. It is the
interceptor's responsibility to call it.
Returns:
The result from calling invoker(metadata).
"""
raise NotImplementedError()
def intercept_channel(channel, *interceptors):
"""Creates an intercepted channel.
Args:
channel: A Channel.
interceptors: Zero or more UnaryClientInterceptors or
StreamClientInterceptors
Returns:
A Channel.
Raises:
TypeError: If an interceptor derives from neither UnaryClientInterceptor
nor StreamClientInterceptor.
"""
from grpc_opentracing.grpcext import _interceptor
return _interceptor.intercept_channel(channel, *interceptors)
class UnaryServerInfo(six.with_metaclass(abc.ABCMeta)):
"""Consists of various information about a unary RPC on the service-side.
Attributes:
full_method: A string of the full RPC method, i.e., /package.service/method.
"""
class StreamServerInfo(six.with_metaclass(abc.ABCMeta)):
"""Consists of various information about a stream RPC on the service-side.
Attributes:
full_method: A string of the full RPC method, i.e., /package.service/method.
is_client_stream: Indicates whether the RPC is client-streaming.
is_server_stream: Indicates whether the RPC is server-streaming.
"""
class UnaryServerInterceptor(six.with_metaclass(abc.ABCMeta)):
"""Affords intercepting unary-unary RPCs on the service-side."""
@abc.abstractmethod
def intercept_unary(self, request, servicer_context, server_info, handler):
"""Intercepts unary-unary RPCs on the service-side.
Args:
request: The request value for the RPC.
servicer_context: A ServicerContext.
server_info: A UnaryServerInfo containing various information about
the RPC.
handler: The handler to complete the RPC on the server. It is the
interceptor's responsibility to call it.
Returns:
The result from calling handler(request, servicer_context).
"""
raise NotImplementedError()
class StreamServerInterceptor(six.with_metaclass(abc.ABCMeta)):
"""Affords intercepting stream RPCs on the service-side."""
@abc.abstractmethod
def intercept_stream(self, request_or_iterator, servicer_context,
server_info, handler):
"""Intercepts stream RPCs on the service-side.
Args:
request_or_iterator: The request value for the RPC if
`server_info.is_client_stream` is `False`; otherwise, an iterator of
request values.
servicer_context: A ServicerContext.
server_info: A StreamServerInfo containing various information about
the RPC.
handler: The handler to complete the RPC on the server. It is the
interceptor's responsibility to call it.
Returns:
The result from calling handler(servicer_context).
"""
raise NotImplementedError()
def intercept_server(server, *interceptors):
"""Creates an intercepted server.
Args:
server: A Server.
interceptors: Zero or more UnaryServerInterceptors or
StreamServerInterceptors
Returns:
A Server.
Raises:
TypeError: If an interceptor derives from neither UnaryServerInterceptor
nor StreamServerInterceptor.
"""
from grpc_opentracing.grpcext import _interceptor
return _interceptor.intercept_server(server, *interceptors)
################################### __all__ #################################
__all__ = ('UnaryClientInterceptor', 'StreamClientInfo',
'StreamClientInterceptor', 'UnaryServerInfo', 'StreamServerInfo',
'UnaryServerInterceptor', 'StreamServerInterceptor',
'intercept_channel', 'intercept_server',)

View File

@@ -0,0 +1,373 @@
"""Implementation of gRPC Python interceptors."""
import collections
import grpc
from grpc_opentracing import grpcext
class _UnaryClientInfo(
collections.namedtuple('_UnaryClientInfo',
('full_method', 'timeout',))):
pass
class _StreamClientInfo(
collections.namedtuple('_StreamClientInfo', (
'full_method', 'is_client_stream', 'is_server_stream', 'timeout'))):
pass
class _InterceptorUnaryUnaryMultiCallable(grpc.UnaryUnaryMultiCallable):
def __init__(self, method, base_callable, interceptor):
self._method = method
self._base_callable = base_callable
self._interceptor = interceptor
def __call__(self, request, timeout=None, metadata=None, credentials=None):
def invoker(request, metadata):
return self._base_callable(request, timeout, metadata, credentials)
client_info = _UnaryClientInfo(self._method, timeout)
return self._interceptor.intercept_unary(request, metadata, client_info,
invoker)
def with_call(self, request, timeout=None, metadata=None, credentials=None):
def invoker(request, metadata):
return self._base_callable.with_call(request, timeout, metadata,
credentials)
client_info = _UnaryClientInfo(self._method, timeout)
return self._interceptor.intercept_unary(request, metadata, client_info,
invoker)
def future(self, request, timeout=None, metadata=None, credentials=None):
def invoker(request, metadata):
return self._base_callable.future(request, timeout, metadata,
credentials)
client_info = _UnaryClientInfo(self._method, timeout)
return self._interceptor.intercept_unary(request, metadata, client_info,
invoker)
class _InterceptorUnaryStreamMultiCallable(grpc.UnaryStreamMultiCallable):
def __init__(self, method, base_callable, interceptor):
self._method = method
self._base_callable = base_callable
self._interceptor = interceptor
def __call__(self, request, timeout=None, metadata=None, credentials=None):
def invoker(request, metadata):
return self._base_callable(request, timeout, metadata, credentials)
client_info = _StreamClientInfo(self._method, False, True, timeout)
return self._interceptor.intercept_stream(request, metadata,
client_info, invoker)
class _InterceptorStreamUnaryMultiCallable(grpc.StreamUnaryMultiCallable):
def __init__(self, method, base_callable, interceptor):
self._method = method
self._base_callable = base_callable
self._interceptor = interceptor
def __call__(self,
request_iterator,
timeout=None,
metadata=None,
credentials=None):
def invoker(request_iterator, metadata):
return self._base_callable(request_iterator, timeout, metadata,
credentials)
client_info = _StreamClientInfo(self._method, True, False, timeout)
return self._interceptor.intercept_stream(request_iterator, metadata,
client_info, invoker)
def with_call(self,
request_iterator,
timeout=None,
metadata=None,
credentials=None):
def invoker(request_iterator, metadata):
return self._base_callable.with_call(request_iterator, timeout,
metadata, credentials)
client_info = _StreamClientInfo(self._method, True, False, timeout)
return self._interceptor.intercept_stream(request_iterator, metadata,
client_info, invoker)
def future(self,
request_iterator,
timeout=None,
metadata=None,
credentials=None):
def invoker(request_iterator, metadata):
return self._base_callable.future(request_iterator, timeout,
metadata, credentials)
client_info = _StreamClientInfo(self._method, True, False, timeout)
return self._interceptor.intercept_stream(request_iterator, metadata,
client_info, invoker)
class _InterceptorStreamStreamMultiCallable(grpc.StreamStreamMultiCallable):
def __init__(self, method, base_callable, interceptor):
self._method = method
self._base_callable = base_callable
self._interceptor = interceptor
def __call__(self,
request_iterator,
timeout=None,
metadata=None,
credentials=None):
def invoker(request_iterator, metadata):
return self._base_callable(request_iterator, timeout, metadata,
credentials)
client_info = _StreamClientInfo(self._method, True, True, timeout)
return self._interceptor.intercept_stream(request_iterator, metadata,
client_info, invoker)
class _InterceptorChannel(grpc.Channel):
def __init__(self, channel, interceptor):
self._channel = channel
self._interceptor = interceptor
def subscribe(self, *args, **kwargs):
self._channel.subscribe(*args, **kwargs)
def unsubscribe(self, *args, **kwargs):
self._channel.unsubscribe(*args, **kwargs)
def unary_unary(self,
method,
request_serializer=None,
response_deserializer=None):
base_callable = self._channel.unary_unary(method, request_serializer,
response_deserializer)
if isinstance(self._interceptor, grpcext.UnaryClientInterceptor):
return _InterceptorUnaryUnaryMultiCallable(method, base_callable,
self._interceptor)
else:
return base_callable
def unary_stream(self,
method,
request_serializer=None,
response_deserializer=None):
base_callable = self._channel.unary_stream(method, request_serializer,
response_deserializer)
if isinstance(self._interceptor, grpcext.StreamClientInterceptor):
return _InterceptorUnaryStreamMultiCallable(method, base_callable,
self._interceptor)
else:
return base_callable
def stream_unary(self,
method,
request_serializer=None,
response_deserializer=None):
base_callable = self._channel.stream_unary(method, request_serializer,
response_deserializer)
if isinstance(self._interceptor, grpcext.StreamClientInterceptor):
return _InterceptorStreamUnaryMultiCallable(method, base_callable,
self._interceptor)
else:
return base_callable
def stream_stream(self,
method,
request_serializer=None,
response_deserializer=None):
base_callable = self._channel.stream_stream(method, request_serializer,
response_deserializer)
if isinstance(self._interceptor, grpcext.StreamClientInterceptor):
return _InterceptorStreamStreamMultiCallable(method, base_callable,
self._interceptor)
else:
return base_callable
def intercept_channel(channel, *interceptors):
result = channel
for interceptor in interceptors:
if not isinstance(interceptor, grpcext.UnaryClientInterceptor) and \
not isinstance(interceptor, grpcext.StreamClientInterceptor):
raise TypeError('interceptor must be either a '
'grpcext.UnaryClientInterceptor or a '
'grpcext.StreamClientInterceptor')
result = _InterceptorChannel(result, interceptor)
return result
class _UnaryServerInfo(
collections.namedtuple('_UnaryServerInfo', ('full_method',))):
pass
class _StreamServerInfo(
collections.namedtuple('_StreamServerInfo', (
'full_method', 'is_client_stream', 'is_server_stream'))):
pass
class _InterceptorRpcMethodHandler(grpc.RpcMethodHandler):
def __init__(self, rpc_method_handler, method, interceptor):
self._rpc_method_handler = rpc_method_handler
self._method = method
self._interceptor = interceptor
@property
def request_streaming(self):
return self._rpc_method_handler.request_streaming
@property
def response_streaming(self):
return self._rpc_method_handler.response_streaming
@property
def request_deserializer(self):
return self._rpc_method_handler.request_deserializer
@property
def response_serializer(self):
return self._rpc_method_handler.response_serializer
@property
def unary_unary(self):
if not isinstance(self._interceptor, grpcext.UnaryServerInterceptor):
return self._rpc_method_handler.unary_unary
def adaptation(request, servicer_context):
def handler(request, servicer_context):
return self._rpc_method_handler.unary_unary(request,
servicer_context)
return self._interceptor.intercept_unary(
request, servicer_context,
_UnaryServerInfo(self._method), handler)
return adaptation
@property
def unary_stream(self):
if not isinstance(self._interceptor, grpcext.StreamServerInterceptor):
return self._rpc_method_handler.unary_stream
def adaptation(request, servicer_context):
def handler(request, servicer_context):
return self._rpc_method_handler.unary_stream(request,
servicer_context)
return self._interceptor.intercept_stream(
request, servicer_context,
_StreamServerInfo(self._method, False, True), handler)
return adaptation
@property
def stream_unary(self):
if not isinstance(self._interceptor, grpcext.StreamServerInterceptor):
return self._rpc_method_handler.stream_unary
def adaptation(request_iterator, servicer_context):
def handler(request_iterator, servicer_context):
return self._rpc_method_handler.stream_unary(request_iterator,
servicer_context)
return self._interceptor.intercept_stream(
request_iterator, servicer_context,
_StreamServerInfo(self._method, True, False), handler)
return adaptation
@property
def stream_stream(self):
if not isinstance(self._interceptor, grpcext.StreamServerInterceptor):
return self._rpc_method_handler.stream_stream
def adaptation(request_iterator, servicer_context):
def handler(request_iterator, servicer_context):
return self._rpc_method_handler.stream_stream(request_iterator,
servicer_context)
return self._interceptor.intercept_stream(
request_iterator, servicer_context,
_StreamServerInfo(self._method, True, True), handler)
return adaptation
class _InterceptorGenericRpcHandler(grpc.GenericRpcHandler):
def __init__(self, generic_rpc_handler, interceptor):
self.generic_rpc_handler = generic_rpc_handler
self._interceptor = interceptor
def service(self, handler_call_details):
result = self.generic_rpc_handler.service(handler_call_details)
if result:
result = _InterceptorRpcMethodHandler(
result, handler_call_details.method, self._interceptor)
return result
class _InterceptorServer(grpc.Server):
def __init__(self, server, interceptor):
self._server = server
self._interceptor = interceptor
def add_generic_rpc_handlers(self, generic_rpc_handlers):
generic_rpc_handlers = [
_InterceptorGenericRpcHandler(generic_rpc_handler,
self._interceptor)
for generic_rpc_handler in generic_rpc_handlers
]
return self._server.add_generic_rpc_handlers(generic_rpc_handlers)
def add_insecure_port(self, *args, **kwargs):
return self._server.add_insecure_port(*args, **kwargs)
def add_secure_port(self, *args, **kwargs):
return self._server.add_secure_port(*args, **kwargs)
def start(self, *args, **kwargs):
return self._server.start(*args, **kwargs)
def stop(self, *args, **kwargs):
return self._server.stop(*args, **kwargs)
def intercept_server(server, *interceptors):
result = server
for interceptor in interceptors:
if not isinstance(interceptor, grpcext.UnaryServerInterceptor) and \
not isinstance(interceptor, grpcext.StreamServerInterceptor):
raise TypeError('interceptor must be either a '
'grpcext.UnaryServerInterceptor or a '
'grpcext.StreamServerInterceptor')
result = _InterceptorServer(result, interceptor)
return result

View File

@@ -0,0 +1,5 @@
# add dependencies in setup.py
-r requirements.txt
-e .[tests]

View File

@@ -0,0 +1,3 @@
# add dependencies in setup.py
-e .

View File

@@ -0,0 +1,2 @@
[aliases]
test=pytest

View File

@@ -0,0 +1,36 @@
import os
import logging
import sys
import tempfile
from setuptools import setup, find_packages
def readme():
"""Use `pandoc` to convert `README.md` into a `README.rst` file."""
if os.path.isfile('README.md') and any('dist' in x for x in sys.argv[1:]):
if os.system('pandoc -s README.md -o %s/README.rst' %
tempfile.mkdtemp()) != 0:
logging.warning('Unable to generate README.rst')
if os.path.isfile('README.rst'):
with open('README.rst') as fd:
return fd.read()
return ''
setup(
name='grpcio-opentracing',
version='1.0',
description='Python OpenTracing Extensions for gRPC',
long_description=readme(),
author='LightStep',
license='',
install_requires=['opentracing>=1.2.2', 'grpcio>=1.1.3', 'six>=1.10'],
setup_requires=['pytest-runner'],
tests_require=['pytest', 'future'],
keywords=['opentracing'],
classifiers=[
'Operating System :: OS Independent',
'Programming Language :: Python :: 2.7',
],
packages=find_packages(exclude=['docs*', 'tests*', 'examples*']))

View File

@@ -0,0 +1,192 @@
"""Creates a simple service on top of gRPC for testing."""
from builtins import input, range
import grpc
from grpc.framework.foundation import logging_pool
from grpc_opentracing import grpcext
_SERIALIZE_REQUEST = lambda bytestring: bytestring
_DESERIALIZE_REQUEST = lambda bytestring: bytestring
_SERIALIZE_RESPONSE = lambda bytestring: bytestring
_DESERIALIZE_RESPONSE = lambda bytestring: bytestring
_UNARY_UNARY = '/test/UnaryUnary'
_UNARY_STREAM = '/test/UnaryStream'
_STREAM_UNARY = '/test/StreamUnary'
_STREAM_STREAM = '/test/StreamStream'
_STREAM_LENGTH = 5
class _MethodHandler(grpc.RpcMethodHandler):
def __init__(self,
request_streaming=False,
response_streaming=False,
unary_unary=None,
unary_stream=None,
stream_unary=None,
stream_stream=None):
self.request_streaming = request_streaming
self.response_streaming = response_streaming
self.request_deserializer = _DESERIALIZE_REQUEST
self.response_serializer = _SERIALIZE_RESPONSE
self.unary_unary = unary_unary
self.unary_stream = unary_stream
self.stream_unary = stream_unary
self.stream_stream = stream_stream
class Handler(object):
def __init__(self):
self.invocation_metadata = None
self.trailing_metadata = None
def handle_unary_unary(self, request, servicer_context):
if servicer_context is not None:
self.invocation_metadata = servicer_context.invocation_metadata()
if self.trailing_metadata is not None:
servicer_context.set_trailing_metadata(self.trailing_metadata)
return request
def handle_unary_stream(self, request, servicer_context):
if servicer_context is not None:
self.invocation_metadata = servicer_context.invocation_metadata()
if self.trailing_metadata is not None:
servicer_context.set_trailing_metadata(self.trailing_metadata)
for _ in range(_STREAM_LENGTH):
yield request
def handle_stream_unary(self, request_iterator, servicer_context):
if servicer_context is not None:
self.invocation_metadata = servicer_context.invocation_metadata()
if self.trailing_metadata is not None:
servicer_context.set_trailing_metadata(self.trailing_metadata)
return b''.join(list(request_iterator))
def handle_stream_stream(self, request_iterator, servicer_context):
if servicer_context is not None:
self.invocation_metadata = servicer_context.invocation_metadata()
if self.trailing_metadata is not None:
servicer_context.set_trailing_metadata(self.trailing_metadata)
for request in request_iterator:
yield request
def _set_error_code(servicer_context):
servicer_context.set_code(grpc.StatusCode.INVALID_ARGUMENT)
servicer_context.set_details('ErroringHandler')
class ErroringHandler(Handler):
def __init__(self):
super(ErroringHandler, self).__init__()
def handle_unary_unary(self, request, servicer_context):
_set_error_code(servicer_context)
return super(ErroringHandler, self).handle_unary_unary(request,
servicer_context)
def handle_unary_stream(self, request, servicer_context):
_set_error_code(servicer_context)
return super(ErroringHandler, self).handle_unary_stream(
request, servicer_context)
def handle_stream_unary(self, request_iterator, servicer_context):
_set_error_code(servicer_context)
return super(ErroringHandler, self).handle_stream_unary(
request_iterator, servicer_context)
def handle_stream_stream(self, request_iterator, servicer_context):
_set_error_code(servicer_context)
return super(ErroringHandler, self).handle_stream_stream(
request_iterator, servicer_context)
class ExceptionErroringHandler(Handler):
def __init__(self):
super(ExceptionErroringHandler, self).__init__()
def handle_unary_unary(self, request, servicer_context):
raise IndexError()
def handle_unary_stream(self, request, servicer_context):
raise IndexError()
def handle_stream_unary(self, request_iterator, servicer_context):
raise IndexError()
def handle_stream_stream(self, request_iterator, servicer_context):
raise IndexError()
class _GenericHandler(grpc.GenericRpcHandler):
def __init__(self, handler):
self._handler = handler
def service(self, handler_call_details):
method = handler_call_details.method
if method == _UNARY_UNARY:
return _MethodHandler(unary_unary=self._handler.handle_unary_unary)
elif method == _UNARY_STREAM:
return _MethodHandler(
response_streaming=True,
unary_stream=self._handler.handle_unary_stream)
elif method == _STREAM_UNARY:
return _MethodHandler(
request_streaming=True,
stream_unary=self._handler.handle_stream_unary)
elif method == _STREAM_STREAM:
return _MethodHandler(
request_streaming=True,
response_streaming=True,
stream_stream=self._handler.handle_stream_stream)
else:
return None
class Service(object):
def __init__(self,
client_interceptors,
server_interceptors,
handler=Handler()):
self.handler = handler
self._server_pool = logging_pool.pool(2)
self._server = grpcext.intercept_server(
grpc.server(self._server_pool), *server_interceptors)
port = self._server.add_insecure_port('[::]:0')
self._server.add_generic_rpc_handlers((_GenericHandler(self.handler),))
self._server.start()
self.channel = grpcext.intercept_channel(
grpc.insecure_channel('localhost:%d' % port), *client_interceptors)
@property
def unary_unary_multi_callable(self):
return self.channel.unary_unary(_UNARY_UNARY)
@property
def unary_stream_multi_callable(self):
return self.channel.unary_stream(
_UNARY_STREAM,
request_serializer=_SERIALIZE_REQUEST,
response_deserializer=_DESERIALIZE_RESPONSE)
@property
def stream_unary_multi_callable(self):
return self.channel.stream_unary(
_STREAM_UNARY,
request_serializer=_SERIALIZE_REQUEST,
response_deserializer=_DESERIALIZE_RESPONSE)
@property
def stream_stream_multi_callable(self):
return self.channel.stream_stream(
_STREAM_STREAM,
request_serializer=_SERIALIZE_REQUEST,
response_deserializer=_DESERIALIZE_RESPONSE)

View File

@@ -0,0 +1,83 @@
from collections import defaultdict
import enum
import opentracing
@enum.unique
class SpanRelationship(enum.Enum):
NONE = 0
FOLLOWS_FROM = 1
CHILD_OF = 2
class _SpanContext(opentracing.SpanContext):
def __init__(self, identity):
self.identity = identity
class _Span(opentracing.Span):
def __init__(self, tracer, identity, tags=None):
super(_Span, self).__init__(tracer, _SpanContext(identity))
self._identity = identity
if tags is None:
tags = {}
self._tags = tags
def set_tag(self, key, value):
self._tags[key] = value
def get_tag(self, key):
return self._tags.get(key, None)
class Tracer(opentracing.Tracer):
def __init__(self):
super(Tracer, self).__init__()
self._counter = 0
self._spans = {}
self._relationships = defaultdict(lambda: None)
def start_span(self,
operation_name=None,
child_of=None,
references=None,
tags=None,
start_time=None):
identity = self._counter
self._counter += 1
if child_of is not None:
self._relationships[(child_of.identity,
identity)] = opentracing.ReferenceType.CHILD_OF
if references is not None:
assert child_of is None and len(
references) == 1, 'Only a single reference is supported'
reference_type, span_context = references[0]
self._relationships[(span_context.identity,
identity)] = reference_type
span = _Span(self, identity, tags)
self._spans[identity] = span
return span
def inject(self, span_context, format, carrier):
if format != opentracing.Format.HTTP_HEADERS and isinstance(carrier,
dict):
raise opentracing.UnsupportedFormatException(format)
carrier['span-identity'] = str(span_context.identity)
def extract(self, format, carrier):
if format != opentracing.Format.HTTP_HEADERS and isinstance(carrier,
dict):
raise opentracing.UnsupportedFormatException(format)
if 'span-identity' not in carrier:
raise opentracing.SpanContextCorruptedException
return _SpanContext(int(carrier['span-identity']))
def get_relationship(self, identity1, identity2):
return self._relationships[(identity1, identity2)]
def get_span(self, identity):
return self._spans.get(identity, None)

View File

@@ -0,0 +1,168 @@
import unittest
import grpc
from grpc_opentracing import grpcext
from _service import Service
class ClientInterceptor(grpcext.UnaryClientInterceptor,
grpcext.StreamClientInterceptor):
def __init__(self):
self.intercepted = False
def intercept_unary(self, request, metadata, client_info, invoker):
self.intercepted = True
return invoker(request, metadata)
def intercept_stream(self, request_or_iterator, metadata, client_info,
invoker):
self.intercepted = True
return invoker(request_or_iterator, metadata)
class ServerInterceptor(grpcext.UnaryServerInterceptor,
grpcext.StreamServerInterceptor):
def __init__(self):
self.intercepted = False
def intercept_unary(self, request, servicer_context, server_info, handler):
self.intercepted = True
return handler(request, servicer_context)
def intercept_stream(self, request_or_iterator, servicer_context,
server_info, handler):
self.intercepted = True
return handler(request_or_iterator, servicer_context)
class InterceptorTest(unittest.TestCase):
"""Test that RPC calls are intercepted."""
def setUp(self):
self._client_interceptor = ClientInterceptor()
self._server_interceptor = ServerInterceptor()
self._service = Service([self._client_interceptor],
[self._server_interceptor])
def testUnaryUnaryInterception(self):
multi_callable = self._service.unary_unary_multi_callable
request = b'\x01'
expected_response = self._service.handler.handle_unary_unary(request,
None)
response = multi_callable(request)
self.assertEqual(response, expected_response)
self.assertTrue(self._client_interceptor.intercepted)
self.assertTrue(self._server_interceptor.intercepted)
def testUnaryUnaryInterceptionWithCall(self):
multi_callable = self._service.unary_unary_multi_callable
request = b'\x01'
expected_response = self._service.handler.handle_unary_unary(request,
None)
response, call = multi_callable.with_call(request)
self.assertEqual(response, expected_response)
self.assertIs(grpc.StatusCode.OK, call.code())
self.assertTrue(self._client_interceptor.intercepted)
self.assertTrue(self._server_interceptor.intercepted)
def testUnaryUnaryInterceptionFuture(self):
multi_callable = self._service.unary_unary_multi_callable
request = b'\x01'
expected_response = self._service.handler.handle_unary_unary(request,
None)
response = multi_callable.future(request).result()
self.assertEqual(response, expected_response)
self.assertTrue(self._client_interceptor.intercepted)
self.assertTrue(self._server_interceptor.intercepted)
def testUnaryStreamInterception(self):
multi_callable = self._service.unary_stream_multi_callable
request = b'\x01'
expected_response = self._service.handler.handle_unary_stream(request,
None)
response = multi_callable(request)
self.assertEqual(list(response), list(expected_response))
self.assertTrue(self._client_interceptor.intercepted)
self.assertTrue(self._server_interceptor.intercepted)
def testStreamUnaryInterception(self):
multi_callable = self._service.stream_unary_multi_callable
requests = [b'\x01', b'\x02']
expected_response = self._service.handler.handle_stream_unary(
iter(requests), None)
response = multi_callable(iter(requests))
self.assertEqual(response, expected_response)
self.assertTrue(self._client_interceptor.intercepted)
self.assertTrue(self._server_interceptor.intercepted)
def testStreamUnaryInterceptionWithCall(self):
multi_callable = self._service.stream_unary_multi_callable
requests = [b'\x01', b'\x02']
expected_response = self._service.handler.handle_stream_unary(
iter(requests), None)
response, call = multi_callable.with_call(iter(requests))
self.assertEqual(response, expected_response)
self.assertIs(grpc.StatusCode.OK, call.code())
self.assertTrue(self._client_interceptor.intercepted)
self.assertTrue(self._server_interceptor.intercepted)
def testStreamUnaryInterceptionFuture(self):
multi_callable = self._service.stream_unary_multi_callable
requests = [b'\x01', b'\x02']
expected_response = self._service.handler.handle_stream_unary(
iter(requests), None)
response = multi_callable.future(iter(requests)).result()
self.assertEqual(response, expected_response)
self.assertTrue(self._client_interceptor.intercepted)
self.assertTrue(self._server_interceptor.intercepted)
def testStreamStreamInterception(self):
multi_callable = self._service.stream_stream_multi_callable
requests = [b'\x01', b'\x02']
expected_response = self._service.handler.handle_stream_stream(
iter(requests), None)
response = multi_callable(iter(requests))
self.assertEqual(list(response), list(expected_response))
self.assertTrue(self._client_interceptor.intercepted)
self.assertTrue(self._server_interceptor.intercepted)
class MultiInterceptorTest(unittest.TestCase):
"""Test that you can chain multiple interceptors together."""
def setUp(self):
self._client_interceptors = [ClientInterceptor(), ClientInterceptor()]
self._server_interceptors = [ServerInterceptor(), ServerInterceptor()]
self._service = Service(self._client_interceptors,
self._server_interceptors)
def _clear(self):
for client_interceptor in self._client_interceptors:
client_interceptor.intercepted = False
for server_interceptor in self._server_interceptors:
server_interceptor.intercepted = False
def testUnaryUnaryMultiInterception(self):
multi_callable = self._service.unary_unary_multi_callable
request = b'\x01'
expected_response = self._service.handler.handle_unary_unary(request,
None)
response = multi_callable(request)
self.assertEqual(response, expected_response)
for client_interceptor in self._client_interceptors:
self.assertTrue(client_interceptor.intercepted)
for server_interceptor in self._server_interceptors:
self.assertTrue(server_interceptor.intercepted)

View File

@@ -0,0 +1,611 @@
import unittest
import grpc
from _service import Service, ErroringHandler, ExceptionErroringHandler
from _tracer import Tracer, SpanRelationship
from grpc_opentracing import open_tracing_client_interceptor, open_tracing_server_interceptor
import opentracing
class OpenTracingTest(unittest.TestCase):
"""Test that tracers create the correct spans when RPC calls are invoked."""
def setUp(self):
self._tracer = Tracer()
self._service = Service([open_tracing_client_interceptor(self._tracer)],
[open_tracing_server_interceptor(self._tracer)])
def testUnaryUnaryOpenTracing(self):
multi_callable = self._service.unary_unary_multi_callable
request = b'\x01'
expected_response = self._service.handler.handle_unary_unary(request,
None)
response = multi_callable(request)
self.assertEqual(response, expected_response)
span0 = self._tracer.get_span(0)
self.assertIsNotNone(span0)
self.assertEqual(span0.get_tag('span.kind'), 'client')
span1 = self._tracer.get_span(1)
self.assertIsNotNone(span1)
self.assertEqual(span1.get_tag('span.kind'), 'server')
self.assertEqual(
self._tracer.get_relationship(0, 1),
opentracing.ReferenceType.CHILD_OF)
def testUnaryUnaryOpenTracingFuture(self):
multi_callable = self._service.unary_unary_multi_callable
request = b'\x01'
expected_response = self._service.handler.handle_unary_unary(request,
None)
future = multi_callable.future(request)
response = future.result()
self.assertEqual(response, expected_response)
span0 = self._tracer.get_span(0)
self.assertIsNotNone(span0)
self.assertEqual(span0.get_tag('span.kind'), 'client')
span1 = self._tracer.get_span(1)
self.assertIsNotNone(span1)
self.assertEqual(span1.get_tag('span.kind'), 'server')
self.assertEqual(
self._tracer.get_relationship(0, 1),
opentracing.ReferenceType.CHILD_OF)
def testUnaryUnaryOpenTracingWithCall(self):
multi_callable = self._service.unary_unary_multi_callable
request = b'\x01'
expected_response = self._service.handler.handle_unary_unary(request,
None)
response, call = multi_callable.with_call(request)
self.assertEqual(response, expected_response)
self.assertIs(grpc.StatusCode.OK, call.code())
span0 = self._tracer.get_span(0)
self.assertIsNotNone(span0)
self.assertEqual(span0.get_tag('span.kind'), 'client')
span1 = self._tracer.get_span(1)
self.assertIsNotNone(span1)
self.assertEqual(span1.get_tag('span.kind'), 'server')
self.assertEqual(
self._tracer.get_relationship(0, 1),
opentracing.ReferenceType.CHILD_OF)
def testUnaryStreamOpenTracing(self):
multi_callable = self._service.unary_stream_multi_callable
request = b'\x01'
expected_response = self._service.handler.handle_unary_stream(request,
None)
response = multi_callable(request)
self.assertEqual(list(response), list(expected_response))
span0 = self._tracer.get_span(0)
self.assertIsNotNone(span0)
self.assertEqual(span0.get_tag('span.kind'), 'client')
span1 = self._tracer.get_span(1)
self.assertIsNotNone(span1)
self.assertEqual(span1.get_tag('span.kind'), 'server')
self.assertEqual(
self._tracer.get_relationship(0, 1),
opentracing.ReferenceType.CHILD_OF)
def testStreamUnaryOpenTracing(self):
multi_callable = self._service.stream_unary_multi_callable
requests = [b'\x01', b'\x02']
expected_response = self._service.handler.handle_stream_unary(
iter(requests), None)
response = multi_callable(iter(requests))
self.assertEqual(response, expected_response)
span0 = self._tracer.get_span(0)
self.assertIsNotNone(span0)
self.assertEqual(span0.get_tag('span.kind'), 'client')
span1 = self._tracer.get_span(1)
self.assertIsNotNone(span1)
self.assertEqual(span1.get_tag('span.kind'), 'server')
self.assertEqual(
self._tracer.get_relationship(0, 1),
opentracing.ReferenceType.CHILD_OF)
def testStreamUnaryOpenTracingWithCall(self):
multi_callable = self._service.stream_unary_multi_callable
requests = [b'\x01', b'\x02']
expected_response = self._service.handler.handle_stream_unary(
iter(requests), None)
response, call = multi_callable.with_call(iter(requests))
self.assertEqual(response, expected_response)
self.assertIs(grpc.StatusCode.OK, call.code())
span0 = self._tracer.get_span(0)
self.assertIsNotNone(span0)
self.assertEqual(span0.get_tag('span.kind'), 'client')
span1 = self._tracer.get_span(1)
self.assertIsNotNone(span1)
self.assertEqual(span1.get_tag('span.kind'), 'server')
self.assertEqual(
self._tracer.get_relationship(0, 1),
opentracing.ReferenceType.CHILD_OF)
def testStreamUnaryOpenTracingFuture(self):
multi_callable = self._service.stream_unary_multi_callable
requests = [b'\x01', b'\x02']
expected_response = self._service.handler.handle_stream_unary(
iter(requests), None)
result = multi_callable.future(iter(requests))
response = result.result()
self.assertEqual(response, expected_response)
span0 = self._tracer.get_span(0)
self.assertIsNotNone(span0)
self.assertEqual(span0.get_tag('span.kind'), 'client')
span1 = self._tracer.get_span(1)
self.assertIsNotNone(span1)
self.assertEqual(span1.get_tag('span.kind'), 'server')
self.assertEqual(
self._tracer.get_relationship(0, 1),
opentracing.ReferenceType.CHILD_OF)
def testStreamStreamOpenTracing(self):
multi_callable = self._service.stream_stream_multi_callable
requests = [b'\x01', b'\x02']
expected_response = self._service.handler.handle_stream_stream(
iter(requests), None)
response = multi_callable(iter(requests))
self.assertEqual(list(response), list(expected_response))
span0 = self._tracer.get_span(0)
self.assertIsNotNone(span0)
self.assertEqual(span0.get_tag('span.kind'), 'client')
span1 = self._tracer.get_span(1)
self.assertIsNotNone(span1)
self.assertEqual(span1.get_tag('span.kind'), 'server')
self.assertEqual(
self._tracer.get_relationship(0, 1),
opentracing.ReferenceType.CHILD_OF)
class OpenTracingInteroperabilityClientTest(unittest.TestCase):
"""Test that a traced client can interoperate with a non-trace server."""
def setUp(self):
self._tracer = Tracer()
self._service = Service([open_tracing_client_interceptor(self._tracer)],
[])
def testUnaryUnaryOpenTracing(self):
multi_callable = self._service.unary_unary_multi_callable
request = b'\x01'
expected_response = self._service.handler.handle_unary_unary(request,
None)
response = multi_callable(request)
self.assertEqual(response, expected_response)
span0 = self._tracer.get_span(0)
self.assertIsNotNone(span0)
self.assertEqual(span0.get_tag('span.kind'), 'client')
span1 = self._tracer.get_span(1)
self.assertIsNone(span1)
def testUnaryUnaryOpenTracingWithCall(self):
multi_callable = self._service.unary_unary_multi_callable
request = b'\x01'
expected_response = self._service.handler.handle_unary_unary(request,
None)
response, call = multi_callable.with_call(request)
self.assertEqual(response, expected_response)
self.assertIs(grpc.StatusCode.OK, call.code())
span0 = self._tracer.get_span(0)
self.assertIsNotNone(span0)
self.assertEqual(span0.get_tag('span.kind'), 'client')
span1 = self._tracer.get_span(1)
self.assertIsNone(span1)
def testUnaryStreamOpenTracing(self):
multi_callable = self._service.unary_stream_multi_callable
request = b'\x01'
expected_response = self._service.handler.handle_unary_stream(request,
None)
response = multi_callable(request)
self.assertEqual(list(response), list(expected_response))
span0 = self._tracer.get_span(0)
self.assertIsNotNone(span0)
self.assertEqual(span0.get_tag('span.kind'), 'client')
span1 = self._tracer.get_span(1)
self.assertIsNone(span1)
def testStreamUnaryOpenTracing(self):
multi_callable = self._service.stream_unary_multi_callable
requests = [b'\x01', b'\x02']
expected_response = self._service.handler.handle_stream_unary(
iter(requests), None)
response = multi_callable(iter(requests))
self.assertEqual(response, expected_response)
span0 = self._tracer.get_span(0)
self.assertIsNotNone(span0)
self.assertEqual(span0.get_tag('span.kind'), 'client')
span1 = self._tracer.get_span(1)
self.assertIsNone(span1)
def testStreamUnaryOpenTracingWithCall(self):
multi_callable = self._service.stream_unary_multi_callable
requests = [b'\x01', b'\x02']
expected_response = self._service.handler.handle_stream_unary(
iter(requests), None)
response, call = multi_callable.with_call(iter(requests))
self.assertEqual(response, expected_response)
self.assertIs(grpc.StatusCode.OK, call.code())
span0 = self._tracer.get_span(0)
self.assertIsNotNone(span0)
self.assertEqual(span0.get_tag('span.kind'), 'client')
span1 = self._tracer.get_span(1)
self.assertIsNone(span1)
def testStreamStreamOpenTracing(self):
multi_callable = self._service.stream_stream_multi_callable
requests = [b'\x01', b'\x02']
expected_response = self._service.handler.handle_stream_stream(
iter(requests), None)
response = multi_callable(iter(requests))
self.assertEqual(list(response), list(expected_response))
span0 = self._tracer.get_span(0)
self.assertIsNotNone(span0)
self.assertEqual(span0.get_tag('span.kind'), 'client')
span1 = self._tracer.get_span(1)
self.assertIsNone(span1)
class OpenTracingMetadataTest(unittest.TestCase):
"""Test that open-tracing doesn't interfere with passing metadata through the
RPC.
"""
def setUp(self):
self._tracer = Tracer()
self._service = Service([open_tracing_client_interceptor(self._tracer)],
[open_tracing_server_interceptor(self._tracer)])
def testInvocationMetadata(self):
multi_callable = self._service.unary_unary_multi_callable
request = b'\x01'
multi_callable(request, None, (('abc', '123'),))
self.assertIn(('abc', '123'), self._service.handler.invocation_metadata)
def testTrailingMetadata(self):
self._service.handler.trailing_metadata = (('abc', '123'),)
multi_callable = self._service.unary_unary_multi_callable
request = b'\x01'
future = multi_callable.future(request, None, (('abc', '123'),))
self.assertIn(('abc', '123'), future.trailing_metadata())
class OpenTracingInteroperabilityServerTest(unittest.TestCase):
"""Test that a traced server can interoperate with a non-trace client."""
def setUp(self):
self._tracer = Tracer()
self._service = Service([],
[open_tracing_server_interceptor(self._tracer)])
def testUnaryUnaryOpenTracing(self):
multi_callable = self._service.unary_unary_multi_callable
request = b'\x01'
expected_response = self._service.handler.handle_unary_unary(request,
None)
response = multi_callable(request)
self.assertEqual(response, expected_response)
span0 = self._tracer.get_span(0)
self.assertIsNotNone(span0)
self.assertEqual(span0.get_tag('span.kind'), 'server')
span1 = self._tracer.get_span(1)
self.assertIsNone(span1)
def testUnaryUnaryOpenTracingWithCall(self):
multi_callable = self._service.unary_unary_multi_callable
request = b'\x01'
expected_response = self._service.handler.handle_unary_unary(request,
None)
response, call = multi_callable.with_call(request)
self.assertEqual(response, expected_response)
self.assertIs(grpc.StatusCode.OK, call.code())
span0 = self._tracer.get_span(0)
self.assertIsNotNone(span0)
self.assertEqual(span0.get_tag('span.kind'), 'server')
span1 = self._tracer.get_span(1)
self.assertIsNone(span1)
def testUnaryStreamOpenTracing(self):
multi_callable = self._service.unary_stream_multi_callable
request = b'\x01'
expected_response = self._service.handler.handle_unary_stream(request,
None)
response = multi_callable(request)
self.assertEqual(list(response), list(expected_response))
span0 = self._tracer.get_span(0)
self.assertIsNotNone(span0)
self.assertEqual(span0.get_tag('span.kind'), 'server')
span1 = self._tracer.get_span(1)
self.assertIsNone(span1)
def testStreamUnaryOpenTracing(self):
multi_callable = self._service.stream_unary_multi_callable
requests = [b'\x01', b'\x02']
expected_response = self._service.handler.handle_stream_unary(
iter(requests), None)
response = multi_callable(iter(requests))
self.assertEqual(response, expected_response)
span0 = self._tracer.get_span(0)
self.assertIsNotNone(span0)
self.assertEqual(span0.get_tag('span.kind'), 'server')
span1 = self._tracer.get_span(1)
self.assertIsNone(span1)
def testStreamUnaryOpenTracingWithCall(self):
multi_callable = self._service.stream_unary_multi_callable
requests = [b'\x01', b'\x02']
expected_response = self._service.handler.handle_stream_unary(
iter(requests), None)
response, call = multi_callable.with_call(iter(requests))
self.assertEqual(response, expected_response)
self.assertIs(grpc.StatusCode.OK, call.code())
span0 = self._tracer.get_span(0)
self.assertIsNotNone(span0)
self.assertEqual(span0.get_tag('span.kind'), 'server')
span1 = self._tracer.get_span(1)
self.assertIsNone(span1)
def testStreamStreamOpenTracing(self):
multi_callable = self._service.stream_stream_multi_callable
requests = [b'\x01', b'\x02']
expected_response = self._service.handler.handle_stream_stream(
iter(requests), None)
response = multi_callable(iter(requests))
self.assertEqual(list(response), list(expected_response))
span0 = self._tracer.get_span(0)
self.assertIsNotNone(span0)
self.assertEqual(span0.get_tag('span.kind'), 'server')
span1 = self._tracer.get_span(1)
self.assertIsNone(span1)
class OpenTracingErroringTest(unittest.TestCase):
"""Test that tracer spans set the error tag when erroring RPC are invoked."""
def setUp(self):
self._tracer = Tracer()
self._service = Service([open_tracing_client_interceptor(self._tracer)],
[open_tracing_server_interceptor(self._tracer)],
ErroringHandler())
def testUnaryUnaryOpenTracing(self):
multi_callable = self._service.unary_unary_multi_callable
request = b'\x01'
self.assertRaises(grpc.RpcError, multi_callable, request)
span0 = self._tracer.get_span(0)
self.assertIsNotNone(span0)
self.assertTrue(span0.get_tag('error'))
span1 = self._tracer.get_span(1)
self.assertIsNotNone(span1)
self.assertTrue(span1.get_tag('error'))
def testUnaryUnaryOpenTracingWithCall(self):
multi_callable = self._service.unary_unary_multi_callable
request = b'\x01'
self.assertRaises(grpc.RpcError, multi_callable.with_call, request)
span0 = self._tracer.get_span(0)
self.assertIsNotNone(span0)
self.assertTrue(span0.get_tag('error'))
span1 = self._tracer.get_span(1)
self.assertIsNotNone(span1)
self.assertTrue(span1.get_tag('error'))
def testUnaryStreamOpenTracing(self):
multi_callable = self._service.unary_stream_multi_callable
request = b'\x01'
response = multi_callable(request)
self.assertRaises(grpc.RpcError, list, response)
span0 = self._tracer.get_span(0)
self.assertIsNotNone(span0)
self.assertTrue(span0.get_tag('error'))
span1 = self._tracer.get_span(1)
self.assertIsNotNone(span1)
self.assertTrue(span1.get_tag('error'))
def testStreamUnaryOpenTracing(self):
multi_callable = self._service.stream_unary_multi_callable
requests = [b'\x01', b'\x02']
self.assertRaises(grpc.RpcError, multi_callable, iter(requests))
span0 = self._tracer.get_span(0)
self.assertIsNotNone(span0)
self.assertTrue(span0.get_tag('error'))
span1 = self._tracer.get_span(1)
self.assertIsNotNone(span1)
self.assertTrue(span1.get_tag('error'))
def testStreamUnaryOpenTracingWithCall(self):
multi_callable = self._service.stream_unary_multi_callable
requests = [b'\x01', b'\x02']
self.assertRaises(grpc.RpcError, multi_callable.with_call,
iter(requests))
span0 = self._tracer.get_span(0)
self.assertIsNotNone(span0)
self.assertTrue(span0.get_tag('error'))
span1 = self._tracer.get_span(1)
self.assertIsNotNone(span1)
self.assertTrue(span1.get_tag('error'))
def testStreamStreamOpenTracing(self):
multi_callable = self._service.stream_stream_multi_callable
requests = [b'\x01', b'\x02']
response = multi_callable(iter(requests))
self.assertRaises(grpc.RpcError, list, response)
span0 = self._tracer.get_span(0)
self.assertIsNotNone(span0)
self.assertTrue(span0.get_tag('error'))
span1 = self._tracer.get_span(1)
self.assertIsNotNone(span1)
self.assertTrue(span1.get_tag('error'))
class OpenTracingExceptionErroringTest(unittest.TestCase):
"""Test that tracer spans set the error tag when exception erroring RPC are
invoked.
"""
def setUp(self):
self._tracer = Tracer()
self._service = Service([open_tracing_client_interceptor(self._tracer)],
[open_tracing_server_interceptor(self._tracer)],
ExceptionErroringHandler())
def testUnaryUnaryOpenTracing(self):
multi_callable = self._service.unary_unary_multi_callable
request = b'\x01'
self.assertRaises(grpc.RpcError, multi_callable, request)
span0 = self._tracer.get_span(0)
self.assertIsNotNone(span0)
self.assertTrue(span0.get_tag('error'))
span1 = self._tracer.get_span(1)
self.assertIsNotNone(span1)
self.assertTrue(span1.get_tag('error'))
def testUnaryUnaryOpenTracingWithCall(self):
multi_callable = self._service.unary_unary_multi_callable
request = b'\x01'
self.assertRaises(grpc.RpcError, multi_callable.with_call, request)
span0 = self._tracer.get_span(0)
self.assertIsNotNone(span0)
self.assertTrue(span0.get_tag('error'))
span1 = self._tracer.get_span(1)
self.assertIsNotNone(span1)
self.assertTrue(span1.get_tag('error'))
def testUnaryStreamOpenTracing(self):
multi_callable = self._service.unary_stream_multi_callable
request = b'\x01'
response = multi_callable(request)
self.assertRaises(grpc.RpcError, list, response)
span0 = self._tracer.get_span(0)
self.assertIsNotNone(span0)
self.assertTrue(span0.get_tag('error'))
span1 = self._tracer.get_span(1)
self.assertIsNotNone(span1)
self.assertTrue(span1.get_tag('error'))
def testStreamUnaryOpenTracing(self):
multi_callable = self._service.stream_unary_multi_callable
requests = [b'\x01', b'\x02']
self.assertRaises(grpc.RpcError, multi_callable, iter(requests))
span0 = self._tracer.get_span(0)
self.assertIsNotNone(span0)
self.assertTrue(span0.get_tag('error'))
span1 = self._tracer.get_span(1)
self.assertIsNotNone(span1)
self.assertTrue(span1.get_tag('error'))
def testStreamUnaryOpenTracingWithCall(self):
multi_callable = self._service.stream_unary_multi_callable
requests = [b'\x01', b'\x02']
self.assertRaises(grpc.RpcError, multi_callable.with_call,
iter(requests))
span0 = self._tracer.get_span(0)
self.assertIsNotNone(span0)
self.assertTrue(span0.get_tag('error'))
span1 = self._tracer.get_span(1)
self.assertIsNotNone(span1)
self.assertTrue(span1.get_tag('error'))
def testStreamStreamOpenTracing(self):
multi_callable = self._service.stream_stream_multi_callable
requests = [b'\x01', b'\x02']
response = multi_callable(iter(requests))
self.assertRaises(grpc.RpcError, list, response)
span0 = self._tracer.get_span(0)
self.assertIsNotNone(span0)
self.assertTrue(span0.get_tag('error'))
span1 = self._tracer.get_span(1)
self.assertIsNotNone(span1)
self.assertTrue(span1.get_tag('error'))