def test_span_lifetime(self): """Check that the span is active for the duration of the call.""" interceptor = server_interceptor() # To capture the current span at the time the handler is called active_span_in_handler = None def handler(request, context): nonlocal active_span_in_handler active_span_in_handler = trace.get_current_span() return b"" server = grpc.server( futures.ThreadPoolExecutor(max_workers=1), options=(("grpc.so_reuseport", 0), ), ) server = intercept_server(server, interceptor) server.add_generic_rpc_handlers((UnaryUnaryRpcHandler(handler), )) port = server.add_insecure_port("[::]:0") channel = grpc.insecure_channel("localhost:{:d}".format(port)) active_span_before_call = trace.get_current_span() try: server.start() channel.unary_unary("")(b"") finally: server.stop(None) active_span_after_call = trace.get_current_span() self.assertEqual(active_span_before_call, trace.INVALID_SPAN) self.assertEqual(active_span_after_call, trace.INVALID_SPAN) self.assertIsInstance(active_span_in_handler, trace_sdk.Span) self.assertIsNone(active_span_in_handler.parent)
def start(dummy_mode): # Create gRPC server channel to receive requests from checkout (client). server = grpc.server( futures.ThreadPoolExecutor(max_workers=10), interceptors=( oc_tracer_interceptor, )) # TODO: remove OpenCensus interceptor # OpenTelemetry interceptor receives trace contexts from clients. server = intercept_server(server, server_interceptor(trace.get_tracer_provider())) service = None if dummy_mode: service = DummyEmailService() else: raise Exception('non-dummy mode not implemented yet') demo_pb2_grpc.add_EmailServiceServicer_to_server(service, server) health_pb2_grpc.add_HealthServicer_to_server(service, server) port = os.environ.get('PORT', "8080") logger.info("listening on port: " + port) server.add_insecure_port('[::]:' + port) server.start() try: while True: time.sleep(3600) except KeyboardInterrupt: server.stop(0)
def test_create_span(self): """Check that the interceptor wraps calls with spans server-side.""" @contextmanager def mock_start_as_current_span(*args, **kwargs): yield mock.Mock(spec=trace.Span) # Intercept gRPC calls... tracer = mock.Mock(spec=trace.Tracer) tracer.start_as_current_span.side_effect = mock_start_as_current_span interceptor = server_interceptor(tracer) # No-op RPC handler def handler(request, context): return b"" server = grpc.server( futures.ThreadPoolExecutor(max_workers=1), options=(("grpc.so_reuseport", 0), ), ) # FIXME: grpcext interceptor doesn't apply to handlers passed to server # init, should use intercept_service API instead. server = intercept_server(server, interceptor) server.add_generic_rpc_handlers((UnaryUnaryRpcHandler(handler), )) port = server.add_insecure_port("[::]:0") channel = grpc.insecure_channel("localhost:{:d}".format(port)) try: server.start() channel.unary_unary("")(b"") finally: server.stop(None) tracer.start_as_current_span.assert_called_once_with( name="", kind=trace.SpanKind.SERVER)
def serve(): server = grpc.server(futures.ThreadPoolExecutor(max_workers=10)) server = intercept_server(server, server_interceptor(tracer)) route_guide_pb2_grpc.add_RouteGuideServicer_to_server( RouteGuideServicer(), server) server.add_insecure_port("[::]:50051") server.start() server.wait_for_termination()
def serve(): server = grpc.server(futures.ThreadPoolExecutor()) server = intercept_server(server, server_interceptor(tracer)) helloworld_pb2_grpc.add_GreeterServicer_to_server(Greeter(), server) server.add_insecure_port("[::]:50051") server.start() server.wait_for_termination()
def serve(): log = logging.getLogger() server = grpc.server(futures.ThreadPoolExecutor(max_workers=10)) # OpenTelemetry magic! server = intercept_server(server, server_interceptor(tracer)) field_pb2_grpc.add_FieldServicer_to_server(Field(), server) server.add_insecure_port('[::]:9091') server.start() log.info('Listening for gRPC connections on port 9091') server.wait_for_termination()
def test_concurrent_server_spans(self): """Check that concurrent RPC calls don't interfere with each other. This is the same check as test_sequential_server_spans except that the RPCs are concurrent. Two handlers are invoked at the same time on two separate threads. Each one should see a different active span and context. """ tracer_provider = trace_sdk.TracerProvider() tracer = tracer_provider.get_tracer(__name__) interceptor = server_interceptor(tracer) # Capture the currently active span in each thread active_spans_in_handler = [] latch = get_latch(2) def handler(request, context): latch() active_spans_in_handler.append(tracer.get_current_span()) return b"" server = grpc.server( futures.ThreadPoolExecutor(max_workers=2), options=(("grpc.so_reuseport", 0), ), ) server = intercept_server(server, interceptor) server.add_generic_rpc_handlers((UnaryUnaryRpcHandler(handler), )) port = server.add_insecure_port("[::]:0") channel = grpc.insecure_channel("localhost:{:d}".format(port)) try: server.start() # Interleave calls so spans are active on each thread at the same # time with futures.ThreadPoolExecutor(max_workers=2) as tpe: f1 = tpe.submit(channel.unary_unary(""), b"") f2 = tpe.submit(channel.unary_unary(""), b"") futures.wait((f1, f2)) finally: server.stop(None) self.assertEqual(len(active_spans_in_handler), 2) # pylint:disable=unbalanced-tuple-unpacking span1, span2 = active_spans_in_handler # Spans should belong to separate traces, and each should be a root # span self.assertNotEqual(span1.context.span_id, span2.context.span_id) self.assertNotEqual(span1.context.trace_id, span2.context.trace_id) self.assertIsNone(span1.parent) self.assertIsNone(span1.parent)
def create_grpc_server(is_prod: bool) -> grpc.Server: console_span_processor = SimpleExportSpanProcessor(ConsoleSpanExporter()) if is_prod: span_processor = MultiSpanProcessor() span_processor.add_span_processor(console_span_processor) span_processor.add_span_processor( BatchExportSpanProcessor(CloudTraceSpanExporter())) else: span_processor = console_span_processor # this should typecheck but the API interface doesn't have add_span_processor() trace.get_tracer_provider().add_span_processor( # type: ignore span_processor) server = grpc.server(ThreadPoolExecutor(max_workers=10)) server = intercept_server(server, server_interceptor()) return server
def test_sequential_server_spans(self): """Check that sequential RPCs get separate server spans.""" tracer_provider = trace_sdk.TracerProvider() tracer = tracer_provider.get_tracer(__name__) interceptor = server_interceptor(tracer) # Capture the currently active span in each thread active_spans_in_handler = [] def handler(request, context): active_spans_in_handler.append(tracer.get_current_span()) return b"" server = grpc.server( futures.ThreadPoolExecutor(max_workers=1), options=(("grpc.so_reuseport", 0), ), ) server = intercept_server(server, interceptor) server.add_generic_rpc_handlers((UnaryUnaryRpcHandler(handler), )) port = server.add_insecure_port("[::]:0") channel = grpc.insecure_channel("localhost:{:d}".format(port)) try: server.start() channel.unary_unary("")(b"") channel.unary_unary("")(b"") finally: server.stop(None) self.assertEqual(len(active_spans_in_handler), 2) # pylint:disable=unbalanced-tuple-unpacking span1, span2 = active_spans_in_handler # Spans should belong to separate traces, and each should be a root # span self.assertNotEqual(span1.context.span_id, span2.context.span_id) self.assertNotEqual(span1.context.trace_id, span2.context.trace_id) self.assertIsNone(span1.parent) self.assertIsNone(span1.parent)
def test_create_span(self): """Check that the interceptor wraps calls with spans server-side.""" # Intercept gRPC calls... interceptor = server_interceptor() # No-op RPC handler def handler(request, context): return b"" server = grpc.server( futures.ThreadPoolExecutor(max_workers=1), options=(("grpc.so_reuseport", 0), ), ) # FIXME: grpcext interceptor doesn't apply to handlers passed to server # init, should use intercept_service API instead. server = intercept_server(server, interceptor) server.add_generic_rpc_handlers((UnaryUnaryRpcHandler(handler), )) port = server.add_insecure_port("[::]:0") channel = grpc.insecure_channel("localhost:{:d}".format(port)) try: server.start() channel.unary_unary("")(b"") finally: server.stop(None) spans_list = self.memory_exporter.get_finished_spans() self.assertEqual(len(spans_list), 1) span = spans_list[0] self.assertEqual(span.name, "") self.assertIs(span.kind, trace.SpanKind.SERVER) # Check version and name in span's instrumentation info self.check_span_instrumentation_info(span, opentelemetry.ext.grpc)
if catalog_addr == "": raise Exception('PRODUCT_CATALOG_SERVICE_ADDR environment variable not set') logger.info("product catalog address: " + catalog_addr) # Create the gRPC client channel to ProductCatalog (server). channel = grpc.insecure_channel(catalog_addr) # OpenTelemetry client interceptor passes trace contexts to the server. channel = intercept_channel(channel, client_interceptor(trace.get_tracer_provider())) product_catalog_stub = demo_pb2_grpc.ProductCatalogServiceStub(channel) # Create the gRPC server for accepting ListRecommendations Requests from frontend (client). server = grpc.server(futures.ThreadPoolExecutor(max_workers=10)) # OpenTelemetry interceptor receives trace contexts from clients. server = intercept_server(server, server_interceptor(trace.get_tracer_provider())) # Add RecommendationService class to gRPC server. service = RecommendationService() demo_pb2_grpc.add_RecommendationServiceServicer_to_server(service, server) health_pb2_grpc.add_HealthServicer_to_server(service, server) # start server logger.info("listening on port: " + port) server.add_insecure_port('[::]:'+port) server.start() # keep alive try: while True: time.sleep(10000)
def wrapper_fn(self, original_func, instance, args, kwargs): server = original_func(*args, **kwargs) return intercept_server(server, server_interceptor())