diff --git a/sentry_sdk/integrations/grpc/client.py b/sentry_sdk/integrations/grpc/client.py index fe9954445e..55bfcff5a0 100644 --- a/sentry_sdk/integrations/grpc/client.py +++ b/sentry_sdk/integrations/grpc/client.py @@ -4,7 +4,6 @@ from sentry_sdk.consts import OP, SPANDATA from sentry_sdk.integrations import DidNotEnable from sentry_sdk.integrations.grpc.consts import SPAN_ORIGIN -from sentry_sdk.tracing_utils import has_span_streaming_enabled if TYPE_CHECKING: from typing import Any, Callable, Iterable, Iterator, Union @@ -31,54 +30,27 @@ def intercept_unary_unary( ) -> "_UnaryOutcome": method = client_call_details.method - span_streaming = has_span_streaming_enabled(sentry_sdk.get_client().options) - if span_streaming: - if sentry_sdk.traces.get_current_span() is None: - client_call_details = ( - self._update_client_call_details_metadata_from_scope( - client_call_details - ) - ) - return continuation(client_call_details, request) - with sentry_sdk.traces.start_span( - name="unary unary call to %s" % method, - attributes={ - "sentry.op": OP.GRPC_CLIENT, - "sentry.origin": SPAN_ORIGIN, - SPANDATA.RPC_METHOD: method, - }, - ) as span: - client_call_details = ( - self._update_client_call_details_metadata_from_scope( - client_call_details - ) - ) - - response = continuation(client_call_details, request) - span.set_attribute( - SPANDATA.RPC_RESPONSE_STATUS_CODE, response.code().name - ) - - return response - else: - with sentry_sdk.start_span( - op=OP.GRPC_CLIENT, - name="unary unary call to %s" % method, - origin=SPAN_ORIGIN, - ) as span: - span.set_data("type", "unary unary") - span.set_data("method", method) - - client_call_details = ( - self._update_client_call_details_metadata_from_scope( - client_call_details - ) - ) - - response = continuation(client_call_details, request) - span.set_data("code", response.code().name) - - return response + if sentry_sdk.traces.get_current_span() is None: + client_call_details = self._update_client_call_details_metadata_from_scope( + client_call_details + ) + return continuation(client_call_details, request) + with sentry_sdk.traces.start_span( + name="unary unary call to %s" % method, + attributes={ + "sentry.op": OP.GRPC_CLIENT, + "sentry.origin": SPAN_ORIGIN, + SPANDATA.RPC_METHOD: method, + }, + ) as span: + client_call_details = self._update_client_call_details_metadata_from_scope( + client_call_details + ) + + response = continuation(client_call_details, request) + span.set_attribute(SPANDATA.RPC_RESPONSE_STATUS_CODE, response.code().name) + + return response def intercept_unary_stream( self: "ClientInterceptor", @@ -88,55 +60,29 @@ def intercept_unary_stream( ) -> "Union[Iterator[Message], Call]": method = client_call_details.method - span_streaming = has_span_streaming_enabled(sentry_sdk.get_client().options) response: "UnaryStreamCall" - if span_streaming: - if sentry_sdk.traces.get_current_span() is None: - client_call_details = ( - self._update_client_call_details_metadata_from_scope( - client_call_details - ) - ) - return continuation(client_call_details, request) - with sentry_sdk.traces.start_span( - name="unary stream call to %s" % method, - attributes={ - "sentry.op": OP.GRPC_CLIENT, - "sentry.origin": SPAN_ORIGIN, - SPANDATA.RPC_METHOD: method, - }, - ) as span: - client_call_details = ( - self._update_client_call_details_metadata_from_scope( - client_call_details - ) - ) - - response = continuation(client_call_details, request) - # Setting code on unary-stream leads to execution getting stuck - # span.set_data("code", response.code().name) - - return response - else: - with sentry_sdk.start_span( - op=OP.GRPC_CLIENT, - name="unary stream call to %s" % method, - origin=SPAN_ORIGIN, - ) as span: - span.set_data("type", "unary stream") - span.set_data("method", method) - - client_call_details = ( - self._update_client_call_details_metadata_from_scope( - client_call_details - ) - ) - - response = continuation(client_call_details, request) - # Setting code on unary-stream leads to execution getting stuck - # span.set_data("code", response.code().name) - - return response + if sentry_sdk.traces.get_current_span() is None: + client_call_details = self._update_client_call_details_metadata_from_scope( + client_call_details + ) + return continuation(client_call_details, request) + with sentry_sdk.traces.start_span( + name="unary stream call to %s" % method, + attributes={ + "sentry.op": OP.GRPC_CLIENT, + "sentry.origin": SPAN_ORIGIN, + SPANDATA.RPC_METHOD: method, + }, + ): + client_call_details = self._update_client_call_details_metadata_from_scope( + client_call_details + ) + + response = continuation(client_call_details, request) + # Setting code on unary-stream leads to execution getting stuck + # span.set_data("code", response.code().name) + + return response @staticmethod def _update_client_call_details_metadata_from_scope( diff --git a/sentry_sdk/integrations/grpc/server.py b/sentry_sdk/integrations/grpc/server.py index 9b091c258d..a363652ad8 100644 --- a/sentry_sdk/integrations/grpc/server.py +++ b/sentry_sdk/integrations/grpc/server.py @@ -5,8 +5,6 @@ from sentry_sdk.integrations import DidNotEnable from sentry_sdk.integrations.grpc.consts import SPAN_ORIGIN from sentry_sdk.traces import SegmentNameSource -from sentry_sdk.tracing import TransactionSource -from sentry_sdk.tracing_utils import has_span_streaming_enabled if TYPE_CHECKING: from typing import Callable, Optional @@ -48,39 +46,22 @@ def behavior(request: "Message", context: "ServicerContext") -> "Message": if name: metadata = dict(context.invocation_metadata()) - span_streaming = has_span_streaming_enabled( - sentry_sdk.get_client().options - ) - if span_streaming: - sentry_sdk.traces.continue_trace(metadata) + sentry_sdk.traces.continue_trace(metadata) - with sentry_sdk.traces.start_span( - name=name, - attributes={ - "sentry.op": OP.GRPC_SERVER, - "sentry.segment.name.source": SegmentNameSource.CUSTOM.value, - "sentry.origin": SPAN_ORIGIN, - }, - parent_span=None, - ): - try: - return handler.unary_unary(request, context) - except BaseException as e: - raise e - else: - transaction = sentry_sdk.continue_trace( - metadata, - op=OP.GRPC_SERVER, - name=name, - source=TransactionSource.CUSTOM, - origin=SPAN_ORIGIN, - ) + with sentry_sdk.traces.start_span( + name=name, + attributes={ + "sentry.op": OP.GRPC_SERVER, + "sentry.segment.name.source": SegmentNameSource.CUSTOM.value, + "sentry.origin": SPAN_ORIGIN, + }, + parent_span=None, + ): + try: + return handler.unary_unary(request, context) + except BaseException as e: + raise e - with sentry_sdk.start_transaction(transaction=transaction): - try: - return handler.unary_unary(request, context) - except BaseException as e: - raise e else: return handler.unary_unary(request, context) diff --git a/tests/integrations/grpc/test_grpc.py b/tests/integrations/grpc/test_grpc.py index f50a2f62d1..15575b7344 100644 --- a/tests/integrations/grpc/test_grpc.py +++ b/tests/integrations/grpc/test_grpc.py @@ -7,11 +7,9 @@ import pytest import sentry_sdk -from sentry_sdk import start_span, start_transaction from sentry_sdk.consts import OP from sentry_sdk.integrations.grpc import GRPCIntegration from sentry_sdk.integrations.grpc.client import ClientInterceptor -from sentry_sdk.tracing_utils import has_span_streaming_enabled from tests.conftest import ApproxDict from tests.integrations.grpc.grpc_test_service_pb2 import gRPCTestMessage from tests.integrations.grpc.grpc_test_service_pb2_grpc import ( @@ -54,72 +52,47 @@ def _tear_down(server: grpc.Server): @pytest.mark.forked -@pytest.mark.parametrize("span_streaming", [True, False]) def test_grpc_server_starts_transaction( sentry_init, - capture_events_forksafe, capture_items_forksafe, - span_streaming, ): sentry_init( traces_sample_rate=1.0, integrations=[GRPCIntegration()], - trace_lifecycle="stream" if span_streaming else "static", + trace_lifecycle="stream", ) server, channel = _set_up() # Use the provided channel stub = gRPCTestServiceStub(channel) + items = capture_items_forksafe("span") - if span_streaming: - items = capture_items_forksafe("span") + stub.TestServe(gRPCTestMessage(text="test")) - stub.TestServe(gRPCTestMessage(text="test")) - - _tear_down(server=server) - - sentry_sdk.flush() - items.write_file.close() - items = items.read_event() - spans = [item["payload"] for item in items if item["type"] == "span"] - span = spans[0] - - assert spans[1]["attributes"]["sentry.segment.name.source"] == "custom" - assert spans[1]["attributes"]["sentry.op"] == OP.GRPC_SERVER - assert span["attributes"]["sentry.op"] == "test" - else: - events = capture_events_forksafe() - - stub.TestServe(gRPCTestMessage(text="test")) - - _tear_down(server=server) + _tear_down(server=server) - events.write_file.close() - event = events.read_event() - span = event["spans"][0] + sentry_sdk.flush() + items.write_file.close() + items = items.read_event() + spans = [item["payload"] for item in items if item["type"] == "span"] + span = spans[0] - assert event["type"] == "transaction" - assert event["transaction_info"] == { - "source": "custom", - } - assert event["contexts"]["trace"]["op"] == OP.GRPC_SERVER - assert span["op"] == "test" + assert spans[1]["attributes"]["sentry.segment.name.source"] == "custom" + assert spans[1]["attributes"]["sentry.op"] == OP.GRPC_SERVER + assert span["attributes"]["sentry.op"] == "test" @pytest.mark.forked -@pytest.mark.parametrize("span_streaming", [True, False]) def test_grpc_server_other_interceptors( sentry_init, - capture_events_forksafe, capture_items_forksafe, - span_streaming, ): """Ensure compatibility with additional server interceptors.""" sentry_init( traces_sample_rate=1.0, integrations=[GRPCIntegration()], - trace_lifecycle="stream" if span_streaming else "static", + trace_lifecycle="stream", ) mock_intercept = lambda continuation, handler_call_details: continuation( @@ -132,302 +105,180 @@ def test_grpc_server_other_interceptors( # Use the provided channel stub = gRPCTestServiceStub(channel) + items = capture_items_forksafe("span") - if span_streaming: - items = capture_items_forksafe("span") - - stub.TestServe(gRPCTestMessage(text="test")) - - _tear_down(server=server) - - mock_interceptor.intercept_service.assert_called_once() + stub.TestServe(gRPCTestMessage(text="test")) - sentry_sdk.flush() - items.write_file.close() - items = items.read_event() - spans = [item["payload"] for item in items if item["type"] == "span"] - span = spans[0] - - assert spans[1]["attributes"]["sentry.segment.name.source"] == "custom" - assert spans[1]["attributes"]["sentry.op"] == OP.GRPC_SERVER - assert span["attributes"]["sentry.op"] == "test" - else: - events = capture_events_forksafe() - - stub.TestServe(gRPCTestMessage(text="test")) - - _tear_down(server=server) + _tear_down(server=server) - mock_interceptor.intercept_service.assert_called_once() + mock_interceptor.intercept_service.assert_called_once() - events.write_file.close() - event = events.read_event() - span = event["spans"][0] + sentry_sdk.flush() + items.write_file.close() + items = items.read_event() + spans = [item["payload"] for item in items if item["type"] == "span"] + span = spans[0] - assert event["type"] == "transaction" - assert event["transaction_info"] == { - "source": "custom", - } - assert event["contexts"]["trace"]["op"] == OP.GRPC_SERVER - assert span["op"] == "test" + assert spans[1]["attributes"]["sentry.segment.name.source"] == "custom" + assert spans[1]["attributes"]["sentry.op"] == OP.GRPC_SERVER + assert span["attributes"]["sentry.op"] == "test" @pytest.mark.forked -@pytest.mark.parametrize("span_streaming", [True, False]) def test_grpc_server_continues_transaction( sentry_init, - capture_events_forksafe, capture_items_forksafe, - span_streaming, ): sentry_init( traces_sample_rate=1.0, integrations=[GRPCIntegration()], - trace_lifecycle="stream" if span_streaming else "static", + trace_lifecycle="stream", ) server, channel = _set_up() # Use the provided channel stub = gRPCTestServiceStub(channel) - - if span_streaming: - items = capture_items_forksafe("span") - - with sentry_sdk.traces.start_span(name="custom parent") as segment_span: - metadata = ( - ( - "baggage", - "sentry-trace_id={trace_id},sentry-environment=test," - "sentry-transaction=test-transaction,sentry-sample_rate=1.0".format( - trace_id=segment_span.trace_id - ), - ), - ( - "sentry-trace", - "{trace_id}-{parent_span_id}-{sampled}".format( - trace_id=segment_span.trace_id, - parent_span_id=segment_span.span_id, - sampled=1, - ), - ), - ) - - stub.TestServe(gRPCTestMessage(text="test"), metadata=metadata) - - _tear_down(server=server) - - sentry_sdk.flush() - items.write_file.close() - items = items.read_event() - spans = [item["payload"] for item in items if item["type"] == "span"] - span = spans[0] - - assert spans[1]["attributes"]["sentry.segment.name.source"] == "custom" - assert spans[1]["attributes"]["sentry.op"] == OP.GRPC_SERVER - assert spans[1]["trace_id"] == segment_span.trace_id - assert span["attributes"]["sentry.op"] == "test" - else: - events = capture_events_forksafe() - - with start_transaction() as transaction: - metadata = ( - ( - "baggage", - "sentry-trace_id={trace_id},sentry-environment=test," - "sentry-transaction=test-transaction,sentry-sample_rate=1.0".format( - trace_id=transaction.trace_id - ), + items = capture_items_forksafe("span") + + with sentry_sdk.traces.start_span(name="custom parent") as segment_span: + metadata = ( + ( + "baggage", + "sentry-trace_id={trace_id},sentry-environment=test," + "sentry-transaction=test-transaction,sentry-sample_rate=1.0".format( + trace_id=segment_span.trace_id ), - ( - "sentry-trace", - "{trace_id}-{parent_span_id}-{sampled}".format( - trace_id=transaction.trace_id, - parent_span_id=transaction.span_id, - sampled=1, - ), + ), + ( + "sentry-trace", + "{trace_id}-{parent_span_id}-{sampled}".format( + trace_id=segment_span.trace_id, + parent_span_id=segment_span.span_id, + sampled=1, ), - ) + ), + ) - stub.TestServe(gRPCTestMessage(text="test"), metadata=metadata) + stub.TestServe(gRPCTestMessage(text="test"), metadata=metadata) - _tear_down(server=server) + _tear_down(server=server) - events.write_file.close() - event = events.read_event() - span = event["spans"][0] + sentry_sdk.flush() + items.write_file.close() + items = items.read_event() + spans = [item["payload"] for item in items if item["type"] == "span"] + span = spans[0] - assert event["type"] == "transaction" - assert event["transaction_info"] == { - "source": "custom", - } - assert event["contexts"]["trace"]["op"] == OP.GRPC_SERVER - assert event["contexts"]["trace"]["trace_id"] == transaction.trace_id - assert span["op"] == "test" + assert spans[1]["attributes"]["sentry.segment.name.source"] == "custom" + assert spans[1]["attributes"]["sentry.op"] == OP.GRPC_SERVER + assert spans[1]["trace_id"] == segment_span.trace_id + assert span["attributes"]["sentry.op"] == "test" @pytest.mark.forked -@pytest.mark.parametrize("span_streaming", [True, False]) def test_grpc_client_starts_span( sentry_init, - capture_events_forksafe, capture_items_forksafe, - span_streaming, ): sentry_init( traces_sample_rate=1.0, integrations=[GRPCIntegration()], - trace_lifecycle="stream" if span_streaming else "static", + trace_lifecycle="stream", ) server, channel = _set_up() # Use the provided channel stub = gRPCTestServiceStub(channel) + items = capture_items_forksafe("span") - if span_streaming: - items = capture_items_forksafe("span") - - with sentry_sdk.traces.start_span(name="custom parent"): - stub.TestServe(gRPCTestMessage(text="test")) - - _tear_down(server=server) - - sentry_sdk.flush() - items.write_file.close() - items = items.read_event() - spans = [item["payload"] for item in items if item["type"] == "span"] - span = spans[2] - - assert len(spans) == 4 - assert span["attributes"]["sentry.op"] == OP.GRPC_CLIENT - assert ( - span["name"] - == "unary unary call to /grpc_test_server.gRPCTestService/TestServe" - ) - assert span["attributes"] == ApproxDict( - { - "rpc.method": "/grpc_test_server.gRPCTestService/TestServe", - "sentry.environment": mock.ANY, - "sentry.op": "grpc.client", - "sentry.origin": "auto.grpc.grpc", - "sentry.release": mock.ANY, - "sentry.sdk.name": "sentry.python", - "sentry.sdk.version": mock.ANY, - "sentry.segment.id": mock.ANY, - "sentry.segment.name": "custom parent", - "server.address": mock.ANY, - "thread.id": mock.ANY, - "thread.name": mock.ANY, - "rpc.response.status_code": "OK", - } - ) - else: - events = capture_events_forksafe() - - with start_transaction(): - stub.TestServe(gRPCTestMessage(text="test")) - - _tear_down(server=server) + with sentry_sdk.traces.start_span(name="custom parent"): + stub.TestServe(gRPCTestMessage(text="test")) - events.write_file.close() - events.read_event() - local_transaction = events.read_event() - span = local_transaction["spans"][0] + _tear_down(server=server) - assert len(local_transaction["spans"]) == 1 - assert span["op"] == OP.GRPC_CLIENT - assert ( - span["description"] - == "unary unary call to /grpc_test_server.gRPCTestService/TestServe" - ) - assert span["data"] == ApproxDict( - { - "type": "unary unary", - "method": "/grpc_test_server.gRPCTestService/TestServe", - "code": "OK", - } - ) + sentry_sdk.flush() + items.write_file.close() + items = items.read_event() + spans = [item["payload"] for item in items if item["type"] == "span"] + span = spans[2] + + assert len(spans) == 4 + assert span["attributes"]["sentry.op"] == OP.GRPC_CLIENT + assert ( + span["name"] + == "unary unary call to /grpc_test_server.gRPCTestService/TestServe" + ) + assert span["attributes"] == ApproxDict( + { + "rpc.method": "/grpc_test_server.gRPCTestService/TestServe", + "sentry.environment": mock.ANY, + "sentry.op": "grpc.client", + "sentry.origin": "auto.grpc.grpc", + "sentry.release": mock.ANY, + "sentry.sdk.name": "sentry.python", + "sentry.sdk.version": mock.ANY, + "sentry.segment.id": mock.ANY, + "sentry.segment.name": "custom parent", + "server.address": mock.ANY, + "thread.id": mock.ANY, + "thread.name": mock.ANY, + "rpc.response.status_code": "OK", + } + ) @pytest.mark.forked -@pytest.mark.parametrize("span_streaming", [True, False]) def test_grpc_client_unary_stream_starts_span( sentry_init, - capture_events_forksafe, capture_items_forksafe, - span_streaming, ): sentry_init( traces_sample_rate=1.0, integrations=[GRPCIntegration()], - trace_lifecycle="stream" if span_streaming else "static", + trace_lifecycle="stream", ) server, channel = _set_up() # Use the provided channel stub = gRPCTestServiceStub(channel) + items = capture_items_forksafe("span") - if span_streaming: - items = capture_items_forksafe("span") + with sentry_sdk.traces.start_span(name="custom parent"): + [el for el in stub.TestUnaryStream(gRPCTestMessage(text="test"))] - with sentry_sdk.traces.start_span(name="custom parent"): - [el for el in stub.TestUnaryStream(gRPCTestMessage(text="test"))] - - _tear_down(server=server) - - sentry_sdk.flush() - items.write_file.close() - items = items.read_event() - spans = [item["payload"] for item in items if item["type"] == "span"] - span = spans[0] + _tear_down(server=server) - assert len(spans) == 2 - assert span["attributes"]["sentry.op"] == OP.GRPC_CLIENT - assert ( - span["name"] - == "unary stream call to /grpc_test_server.gRPCTestService/TestUnaryStream" - ) - assert span["attributes"] == ApproxDict( - { - "rpc.method": "/grpc_test_server.gRPCTestService/TestUnaryStream", - "sentry.environment": mock.ANY, - "sentry.op": "grpc.client", - "sentry.origin": "auto.grpc.grpc", - "sentry.release": mock.ANY, - "sentry.sdk.name": "sentry.python", - "sentry.sdk.version": mock.ANY, - "sentry.segment.id": mock.ANY, - "sentry.segment.name": "custom parent", - "server.address": mock.ANY, - "thread.id": mock.ANY, - "thread.name": mock.ANY, - } - ) - else: - events = capture_events_forksafe() - with start_transaction(): - [el for el in stub.TestUnaryStream(gRPCTestMessage(text="test"))] - - _tear_down(server=server) - - events.write_file.close() - local_transaction = events.read_event() - span = local_transaction["spans"][0] - - assert len(local_transaction["spans"]) == 1 - assert span["op"] == OP.GRPC_CLIENT - assert ( - span["description"] - == "unary stream call to /grpc_test_server.gRPCTestService/TestUnaryStream" - ) - assert span["data"] == ApproxDict( - { - "type": "unary stream", - "method": "/grpc_test_server.gRPCTestService/TestUnaryStream", - } - ) + sentry_sdk.flush() + items.write_file.close() + items = items.read_event() + spans = [item["payload"] for item in items if item["type"] == "span"] + span = spans[0] + + assert len(spans) == 2 + assert span["attributes"]["sentry.op"] == OP.GRPC_CLIENT + assert ( + span["name"] + == "unary stream call to /grpc_test_server.gRPCTestService/TestUnaryStream" + ) + assert span["attributes"] == ApproxDict( + { + "rpc.method": "/grpc_test_server.gRPCTestService/TestUnaryStream", + "sentry.environment": mock.ANY, + "sentry.op": "grpc.client", + "sentry.origin": "auto.grpc.grpc", + "sentry.release": mock.ANY, + "sentry.sdk.name": "sentry.python", + "sentry.sdk.version": mock.ANY, + "sentry.segment.id": mock.ANY, + "sentry.segment.name": "custom parent", + "server.address": mock.ANY, + "thread.id": mock.ANY, + "thread.name": mock.ANY, + } + ) # using unittest.mock.Mock not possible because grpc verifies @@ -441,18 +292,15 @@ def intercept_unary_unary(self, continuation, client_call_details, request): @pytest.mark.forked -@pytest.mark.parametrize("span_streaming", [True, False]) def test_grpc_client_other_interceptor( sentry_init, - capture_events_forksafe, capture_items_forksafe, - span_streaming, ): """Ensure compatibility with additional client interceptors.""" sentry_init( traces_sample_rate=1.0, integrations=[GRPCIntegration()], - trace_lifecycle="stream" if span_streaming else "static", + trace_lifecycle="stream", ) server, channel = _set_up() @@ -460,88 +308,55 @@ def test_grpc_client_other_interceptor( # Intercept the channel channel = grpc.intercept_channel(channel, MockClientInterceptor()) stub = gRPCTestServiceStub(channel) + items = capture_items_forksafe("span") - if span_streaming: - items = capture_items_forksafe("span") - - with sentry_sdk.traces.start_span(name="custom parent"): - stub.TestServe(gRPCTestMessage(text="test")) - - _tear_down(server=server) - - assert MockClientInterceptor.call_counter == 1 - - sentry_sdk.flush() - items.write_file.close() - items = items.read_event() - spans = [item["payload"] for item in items if item["type"] == "span"] - span = spans[2] - - assert len(spans) == 4 - assert span["attributes"]["sentry.op"] == OP.GRPC_CLIENT - assert ( - span["name"] - == "unary unary call to /grpc_test_server.gRPCTestService/TestServe" - ) - assert span["attributes"] == ApproxDict( - { - "rpc.method": "/grpc_test_server.gRPCTestService/TestServe", - "sentry.environment": mock.ANY, - "sentry.op": "grpc.client", - "sentry.origin": "auto.grpc.grpc", - "sentry.release": mock.ANY, - "sentry.sdk.name": "sentry.python", - "sentry.sdk.version": mock.ANY, - "sentry.segment.id": mock.ANY, - "sentry.segment.name": "custom parent", - "server.address": mock.ANY, - "thread.id": mock.ANY, - "thread.name": mock.ANY, - "rpc.response.status_code": "OK", - } - ) - else: - events = capture_events_forksafe() - - with start_transaction(): - stub.TestServe(gRPCTestMessage(text="test")) + with sentry_sdk.traces.start_span(name="custom parent"): + stub.TestServe(gRPCTestMessage(text="test")) - _tear_down(server=server) + _tear_down(server=server) - assert MockClientInterceptor.call_counter == 1 + assert MockClientInterceptor.call_counter == 1 - events.write_file.close() - events.read_event() - local_transaction = events.read_event() - span = local_transaction["spans"][0] + sentry_sdk.flush() + items.write_file.close() + items = items.read_event() + spans = [item["payload"] for item in items if item["type"] == "span"] + span = spans[2] - assert len(local_transaction["spans"]) == 1 - assert span["op"] == OP.GRPC_CLIENT - assert ( - span["description"] - == "unary unary call to /grpc_test_server.gRPCTestService/TestServe" - ) - assert span["data"] == ApproxDict( - { - "type": "unary unary", - "method": "/grpc_test_server.gRPCTestService/TestServe", - "code": "OK", - } - ) + assert len(spans) == 4 + assert span["attributes"]["sentry.op"] == OP.GRPC_CLIENT + assert ( + span["name"] + == "unary unary call to /grpc_test_server.gRPCTestService/TestServe" + ) + assert span["attributes"] == ApproxDict( + { + "rpc.method": "/grpc_test_server.gRPCTestService/TestServe", + "sentry.environment": mock.ANY, + "sentry.op": "grpc.client", + "sentry.origin": "auto.grpc.grpc", + "sentry.release": mock.ANY, + "sentry.sdk.name": "sentry.python", + "sentry.sdk.version": mock.ANY, + "sentry.segment.id": mock.ANY, + "sentry.segment.name": "custom parent", + "server.address": mock.ANY, + "thread.id": mock.ANY, + "thread.name": mock.ANY, + "rpc.response.status_code": "OK", + } + ) @pytest.mark.forked -@pytest.mark.parametrize("span_streaming", [True, False]) def test_prevent_dual_client_interceptor( sentry_init, - capture_events_forksafe, capture_items_forksafe, - span_streaming, ): sentry_init( traces_sample_rate=1.0, integrations=[GRPCIntegration()], - trace_lifecycle="stream" if span_streaming else "static", + trace_lifecycle="stream", ) server, channel = _set_up() @@ -549,113 +364,64 @@ def test_prevent_dual_client_interceptor( # Intercept the channel channel = grpc.intercept_channel(channel, ClientInterceptor()) stub = gRPCTestServiceStub(channel) + items = capture_items_forksafe("span") - if span_streaming: - items = capture_items_forksafe("span") - - with sentry_sdk.traces.start_span(name="custom parent"): - stub.TestServe(gRPCTestMessage(text="test")) - - _tear_down(server=server) - - sentry_sdk.flush() - items.write_file.close() - items = items.read_event() - spans = [item["payload"] for item in items if item["type"] == "span"] - span = spans[2] - - assert len(spans) == 4 - assert span["attributes"]["sentry.op"] == OP.GRPC_CLIENT - assert ( - span["name"] - == "unary unary call to /grpc_test_server.gRPCTestService/TestServe" - ) - assert span["attributes"] == ApproxDict( - { - "rpc.method": "/grpc_test_server.gRPCTestService/TestServe", - "rpc.response.status_code": "OK", - } - ) - else: - events = capture_events_forksafe() - - with start_transaction(): - stub.TestServe(gRPCTestMessage(text="test")) - - _tear_down(server=server) + with sentry_sdk.traces.start_span(name="custom parent"): + stub.TestServe(gRPCTestMessage(text="test")) - events.write_file.close() - events.read_event() - local_transaction = events.read_event() - span = local_transaction["spans"][0] + _tear_down(server=server) - assert len(local_transaction["spans"]) == 1 - assert span["op"] == OP.GRPC_CLIENT - assert ( - span["description"] - == "unary unary call to /grpc_test_server.gRPCTestService/TestServe" - ) - assert span["data"] == ApproxDict( - { - "type": "unary unary", - "method": "/grpc_test_server.gRPCTestService/TestServe", - "code": "OK", - } - ) + sentry_sdk.flush() + items.write_file.close() + items = items.read_event() + spans = [item["payload"] for item in items if item["type"] == "span"] + span = spans[2] + + assert len(spans) == 4 + assert span["attributes"]["sentry.op"] == OP.GRPC_CLIENT + assert ( + span["name"] + == "unary unary call to /grpc_test_server.gRPCTestService/TestServe" + ) + assert span["attributes"] == ApproxDict( + { + "rpc.method": "/grpc_test_server.gRPCTestService/TestServe", + "rpc.response.status_code": "OK", + } + ) @pytest.mark.forked -@pytest.mark.parametrize("span_streaming", [True, False]) def test_grpc_client_and_servers_interceptors_integration( sentry_init, - capture_events_forksafe, capture_items_forksafe, - span_streaming, ): sentry_init( traces_sample_rate=1.0, integrations=[GRPCIntegration()], - trace_lifecycle="stream" if span_streaming else "static", + trace_lifecycle="stream", ) server, channel = _set_up() # Use the provided channel stub = gRPCTestServiceStub(channel) + items = capture_items_forksafe("span") - if span_streaming: - items = capture_items_forksafe("span") - - with sentry_sdk.traces.start_span(name="custom parent"): - stub.TestServe(gRPCTestMessage(text="test")) - - _tear_down(server=server) - - sentry_sdk.flush() - items.write_file.close() - items = items.read_event() - - spans = [item["payload"] for item in items if item["type"] == "span"] - - assert spans[1]["is_segment"] is True - assert spans[3]["is_segment"] is True - assert spans[1]["trace_id"] == spans[3]["trace_id"] - else: - events = capture_events_forksafe() + with sentry_sdk.traces.start_span(name="custom parent"): + stub.TestServe(gRPCTestMessage(text="test")) - with start_transaction(): - stub.TestServe(gRPCTestMessage(text="test")) + _tear_down(server=server) - _tear_down(server=server) + sentry_sdk.flush() + items.write_file.close() + items = items.read_event() - events.write_file.close() - server_transaction = events.read_event() - local_transaction = events.read_event() + spans = [item["payload"] for item in items if item["type"] == "span"] - assert ( - server_transaction["contexts"]["trace"]["trace_id"] - == local_transaction["contexts"]["trace"]["trace_id"] - ) + assert spans[1]["is_segment"] is True + assert spans[3]["is_segment"] is True + assert spans[1]["trace_id"] == spans[3]["trace_id"] @pytest.mark.forked @@ -690,69 +456,40 @@ def test_stream_unary(sentry_init): @pytest.mark.forked -@pytest.mark.parametrize("span_streaming", [True, False]) def test_span_origin( sentry_init, - capture_events_forksafe, capture_items_forksafe, - span_streaming, ): sentry_init( traces_sample_rate=1.0, integrations=[GRPCIntegration()], - trace_lifecycle="stream" if span_streaming else "static", + trace_lifecycle="stream", ) server, channel = _set_up() # Use the provided channel stub = gRPCTestServiceStub(channel) + items = capture_items_forksafe("span") - if span_streaming: - items = capture_items_forksafe("span") - - with sentry_sdk.traces.start_span(name="custom parent"): - stub.TestServe(gRPCTestMessage(text="test")) - - _tear_down(server=server) - - sentry_sdk.flush() - items.write_file.close() - items = items.read_event() - - spans = [item["payload"] for item in items if item["type"] == "span"] - - assert spans[1]["attributes"]["sentry.origin"] == "auto.grpc.grpc" - assert ( - spans[0]["attributes"]["sentry.origin"] == "auto.grpc.grpc.TestService" - ) # manually created in TestService, not the instrumentation - - assert spans[3]["attributes"]["sentry.origin"] == "manual" - assert spans[2]["attributes"]["sentry.origin"] == "auto.grpc.grpc" - else: - events = capture_events_forksafe() - - with start_transaction(name="custom_transaction"): - stub.TestServe(gRPCTestMessage(text="test")) + with sentry_sdk.traces.start_span(name="custom parent"): + stub.TestServe(gRPCTestMessage(text="test")) - _tear_down(server=server) + _tear_down(server=server) - events.write_file.close() + sentry_sdk.flush() + items.write_file.close() + items = items.read_event() - transaction_from_integration = events.read_event() - custom_transaction = events.read_event() + spans = [item["payload"] for item in items if item["type"] == "span"] - assert ( - transaction_from_integration["contexts"]["trace"]["origin"] - == "auto.grpc.grpc" - ) - assert ( - transaction_from_integration["spans"][0]["origin"] - == "auto.grpc.grpc.TestService" - ) # manually created in TestService, not the instrumentation + assert spans[1]["attributes"]["sentry.origin"] == "auto.grpc.grpc" + assert ( + spans[0]["attributes"]["sentry.origin"] == "auto.grpc.grpc.TestService" + ) # manually created in TestService, not the instrumentation - assert custom_transaction["contexts"]["trace"]["origin"] == "manual" - assert custom_transaction["spans"][0]["origin"] == "auto.grpc.grpc" + assert spans[3]["attributes"]["sentry.origin"] == "manual" + assert spans[2]["attributes"]["sentry.origin"] == "auto.grpc.grpc" class TestService(gRPCTestServiceServicer): @@ -760,25 +497,14 @@ class TestService(gRPCTestServiceServicer): @staticmethod def TestServe(request, context): # noqa: N802 - client = sentry_sdk.get_client() - span_streaming = has_span_streaming_enabled(client.options) - - if span_streaming: - with sentry_sdk.traces.start_span( - name="test", - attributes={ - "sentry.op": "test", - "sentry.origin": "auto.grpc.grpc.TestService", - }, - ): - pass - else: - with start_span( - op="test", - name="test", - origin="auto.grpc.grpc.TestService", - ): - pass + with sentry_sdk.traces.start_span( + name="test", + attributes={ + "sentry.op": "test", + "sentry.origin": "auto.grpc.grpc.TestService", + }, + ): + pass return gRPCTestMessage(text=request.text) diff --git a/tests/integrations/grpc/test_grpc_aio.py b/tests/integrations/grpc/test_grpc_aio.py index 217dc110d2..1170ad81b9 100644 --- a/tests/integrations/grpc/test_grpc_aio.py +++ b/tests/integrations/grpc/test_grpc_aio.py @@ -7,10 +7,8 @@ import pytest_asyncio import sentry_sdk -from sentry_sdk import start_span, start_transaction from sentry_sdk.consts import OP from sentry_sdk.integrations.grpc import GRPCIntegration -from sentry_sdk.tracing_utils import has_span_streaming_enabled from tests.conftest import ApproxDict from tests.integrations.grpc.grpc_test_service_pb2 import gRPCTestMessage from tests.integrations.grpc.grpc_test_service_pb2_grpc import ( @@ -29,13 +27,13 @@ async def grpc_server_and_channel(sentry_init): channel: "Optional[grpc.aio.Channel]" = None server: "Optional[grpc.aio.Server]" = None - async def inner(span_streaming: bool): + async def inner(): nonlocal server, channel sentry_init( traces_sample_rate=1.0, integrations=[GRPCIntegration()], - trace_lifecycle="stream" if span_streaming else "static", + trace_lifecycle="stream", ) # Create server @@ -66,213 +64,120 @@ async def inner(span_streaming: bool): @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_noop_for_unimplemented_method( sentry_init, - capture_events, capture_items, - span_streaming, ): sentry_init( traces_sample_rate=1.0, integrations=[GRPCIntegration()], - trace_lifecycle="stream" if span_streaming else "static", + trace_lifecycle="stream", ) # Create empty server with no services server = grpc.aio.server() port = server.add_insecure_port("[::]:0") # Let gRPC choose a free port await asyncio.create_task(server.start()) + items = capture_items("span") - if span_streaming: - items = capture_items("span") - - try: - async with grpc.aio.insecure_channel( - f"localhost:{port}" # noqa: E231 - ) as channel: - stub = gRPCTestServiceStub(channel) - with pytest.raises(grpc.RpcError) as exc: - await stub.TestServe(gRPCTestMessage(text="test")) - assert exc.value.details() == "Method not found!" - finally: - await server.stop(None) - - sentry_sdk.flush() - spans = [item.payload for item in items] - assert len(spans) == 0 # No client span created without an active span. - else: - events = capture_events() - - try: - async with grpc.aio.insecure_channel( - f"localhost:{port}" # noqa: E231 - ) as channel: - stub = gRPCTestServiceStub(channel) - with pytest.raises(grpc.RpcError) as exc: - await stub.TestServe(gRPCTestMessage(text="test")) - assert exc.value.details() == "Method not found!" - finally: - await server.stop(None) + try: + async with grpc.aio.insecure_channel( + f"localhost:{port}" # noqa: E231 + ) as channel: + stub = gRPCTestServiceStub(channel) + with pytest.raises(grpc.RpcError) as exc: + await stub.TestServe(gRPCTestMessage(text="test")) + assert exc.value.details() == "Method not found!" + finally: + await server.stop(None) - assert not events + sentry_sdk.flush() + spans = [item.payload for item in items] + assert len(spans) == 0 # No client span created without an active span. @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_grpc_server_starts_transaction( grpc_server_and_channel, - capture_events, capture_items, - span_streaming, ): - _, channel = await grpc_server_and_channel(span_streaming) + _, channel = await grpc_server_and_channel() # Use the provided channel stub = gRPCTestServiceStub(channel) + items = capture_items("span") - if span_streaming: - items = capture_items("span") - - await stub.TestServe(gRPCTestMessage(text="test")) - - sentry_sdk.flush() - spans = [item.payload for item in items] - span = spans[0] - - assert spans[1]["attributes"]["sentry.segment.name.source"] == "custom" - assert spans[1]["attributes"]["sentry.op"] == OP.GRPC_SERVER - assert span["attributes"]["sentry.op"] == "test" - else: - events = capture_events() + await stub.TestServe(gRPCTestMessage(text="test")) - await stub.TestServe(gRPCTestMessage(text="test")) + sentry_sdk.flush() + spans = [item.payload for item in items] + span = spans[0] - (event,) = events - span = event["spans"][0] - - assert event["type"] == "transaction" - assert event["transaction_info"] == { - "source": "custom", - } - assert event["contexts"]["trace"]["op"] == OP.GRPC_SERVER - assert span["op"] == "test" + assert spans[1]["attributes"]["sentry.segment.name.source"] == "custom" + assert spans[1]["attributes"]["sentry.op"] == OP.GRPC_SERVER + assert span["attributes"]["sentry.op"] == "test" @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_grpc_server_continues_transaction( grpc_server_and_channel, - capture_events, capture_items, - span_streaming, ): - _, channel = await grpc_server_and_channel(span_streaming) + _, channel = await grpc_server_and_channel() # Use the provided channel stub = gRPCTestServiceStub(channel) - - if span_streaming: - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="custom parent") as segment_span: - metadata = ( - ( - "baggage", - "sentry-trace_id={trace_id},sentry-environment=test," - "sentry-transaction=test-transaction,sentry-sample_rate=1.0".format( - trace_id=segment_span.trace_id - ), - ), - ( - "sentry-trace", - "{trace_id}-{parent_span_id}-{sampled}".format( - trace_id=segment_span.trace_id, - parent_span_id=segment_span.span_id, - sampled=1, - ), + items = capture_items("span") + + with sentry_sdk.traces.start_span(name="custom parent") as segment_span: + metadata = ( + ( + "baggage", + "sentry-trace_id={trace_id},sentry-environment=test," + "sentry-transaction=test-transaction,sentry-sample_rate=1.0".format( + trace_id=segment_span.trace_id ), - ) - - await stub.TestServe(gRPCTestMessage(text="test"), metadata=metadata) - - sentry_sdk.flush() - spans = [item.payload for item in items] - span = spans[0] - - assert spans[1]["attributes"]["sentry.segment.name.source"] == "custom" - assert spans[1]["attributes"]["sentry.op"] == OP.GRPC_SERVER - assert spans[1]["trace_id"] == segment_span.trace_id - assert span["attributes"]["sentry.op"] == "test" - else: - events = capture_events() - - with sentry_sdk.start_transaction() as transaction: - metadata = ( - ( - "baggage", - "sentry-trace_id={trace_id},sentry-environment=test," - "sentry-transaction=test-transaction,sentry-sample_rate=1.0".format( - trace_id=transaction.trace_id - ), + ), + ( + "sentry-trace", + "{trace_id}-{parent_span_id}-{sampled}".format( + trace_id=segment_span.trace_id, + parent_span_id=segment_span.span_id, + sampled=1, ), - ( - "sentry-trace", - "{trace_id}-{parent_span_id}-{sampled}".format( - trace_id=transaction.trace_id, - parent_span_id=transaction.span_id, - sampled=1, - ), - ), - ) + ), + ) - await stub.TestServe(gRPCTestMessage(text="test"), metadata=metadata) + await stub.TestServe(gRPCTestMessage(text="test"), metadata=metadata) - (event, _) = events - span = event["spans"][0] + sentry_sdk.flush() + spans = [item.payload for item in items] + span = spans[0] - assert event["type"] == "transaction" - assert event["transaction_info"] == { - "source": "custom", - } - assert event["contexts"]["trace"]["op"] == OP.GRPC_SERVER - assert event["contexts"]["trace"]["trace_id"] == transaction.trace_id - assert span["op"] == "test" + assert spans[1]["attributes"]["sentry.segment.name.source"] == "custom" + assert spans[1]["attributes"]["sentry.op"] == OP.GRPC_SERVER + assert spans[1]["trace_id"] == segment_span.trace_id + assert span["attributes"]["sentry.op"] == "test" @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_grpc_server_exception( grpc_server_and_channel, - capture_events, capture_items, - span_streaming, ): - _, channel = await grpc_server_and_channel(span_streaming) + _, channel = await grpc_server_and_channel() # Use the provided channel stub = gRPCTestServiceStub(channel) + items = capture_items("event") - if span_streaming: - items = capture_items("event") - - try: - await stub.TestServe(gRPCTestMessage(text="exception")) - raise AssertionError() - except Exception: - pass - - (event,) = (item.payload for item in items) - else: - events = capture_events() - - try: - await stub.TestServe(gRPCTestMessage(text="exception")) - raise AssertionError() - except Exception: - pass + try: + await stub.TestServe(gRPCTestMessage(text="exception")) + raise AssertionError() + except Exception: + pass - (event, _) = events + (event,) = (item.payload for item in items) assert event["exception"]["values"][0]["type"] == "TestService.TestException" assert event["exception"]["values"][0]["value"] == "test" @@ -281,9 +186,9 @@ async def test_grpc_server_exception( @pytest.mark.asyncio -async def test_grpc_server_abort(grpc_server_and_channel, capture_events): - _, channel = await grpc_server_and_channel(False) - events = capture_events() +async def test_grpc_server_abort(grpc_server_and_channel, capture_items): + _, channel = await grpc_server_and_channel() + items = capture_items("span") # Use the provided channel stub = gRPCTestServiceStub(channel) @@ -296,154 +201,97 @@ async def test_grpc_server_abort(grpc_server_and_channel, capture_events): # Add a small delay to allow events to be collected await asyncio.sleep(0.1) - assert len(events) == 1 + assert len(items) >= 1 @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_grpc_client_starts_span( grpc_server_and_channel, - capture_events_forksafe, capture_items_forksafe, - span_streaming, ): - _, channel = await grpc_server_and_channel(span_streaming) + _, channel = await grpc_server_and_channel() # Use the provided channel stub = gRPCTestServiceStub(channel) + items = capture_items_forksafe("span") - if span_streaming: - items = capture_items_forksafe("span") - - with sentry_sdk.traces.start_span(name="custom parent") as span: - await stub.TestServe(gRPCTestMessage(text="test")) - - sentry_sdk.flush() - items.write_file.close() - items = items.read_event() - spans = [item["payload"] for item in items if item["type"] == "span"] - span = spans[2] + with sentry_sdk.traces.start_span(name="custom parent") as span: + await stub.TestServe(gRPCTestMessage(text="test")) - assert len(spans) == 4 - assert span["attributes"]["sentry.op"] == OP.GRPC_CLIENT - assert ( - span["name"] - == "unary unary call to /grpc_test_server.gRPCTestService/TestServe" - ) - assert span["attributes"] == ApproxDict( - { - "rpc.method": "/grpc_test_server.gRPCTestService/TestServe", - "sentry.environment": mock.ANY, - "sentry.op": "grpc.client", - "sentry.origin": "auto.grpc.grpc", - "sentry.release": mock.ANY, - "sentry.sdk.name": "sentry.python", - "sentry.sdk.version": mock.ANY, - "sentry.segment.id": mock.ANY, - "sentry.segment.name": "custom parent", - "server.address": mock.ANY, - "thread.id": mock.ANY, - "thread.name": mock.ANY, - "rpc.response.status_code": "OK", - } - ) - else: - events = capture_events_forksafe() - - with start_transaction(): - await stub.TestServe(gRPCTestMessage(text="test")) - - events.write_file.close() - events.read_event() - local_transaction = events.read_event() - span = local_transaction["spans"][0] - - assert len(local_transaction["spans"]) == 1 - assert span["op"] == OP.GRPC_CLIENT - assert ( - span["description"] - == "unary unary call to /grpc_test_server.gRPCTestService/TestServe" - ) - assert span["data"] == ApproxDict( - { - "type": "unary unary", - "method": "/grpc_test_server.gRPCTestService/TestServe", - "code": "OK", - } - ) + sentry_sdk.flush() + items.write_file.close() + items = items.read_event() + spans = [item["payload"] for item in items if item["type"] == "span"] + span = spans[2] + + assert len(spans) == 4 + assert span["attributes"]["sentry.op"] == OP.GRPC_CLIENT + assert ( + span["name"] + == "unary unary call to /grpc_test_server.gRPCTestService/TestServe" + ) + assert span["attributes"] == ApproxDict( + { + "rpc.method": "/grpc_test_server.gRPCTestService/TestServe", + "sentry.environment": mock.ANY, + "sentry.op": "grpc.client", + "sentry.origin": "auto.grpc.grpc", + "sentry.release": mock.ANY, + "sentry.sdk.name": "sentry.python", + "sentry.sdk.version": mock.ANY, + "sentry.segment.id": mock.ANY, + "sentry.segment.name": "custom parent", + "server.address": mock.ANY, + "thread.id": mock.ANY, + "thread.name": mock.ANY, + "rpc.response.status_code": "OK", + } + ) @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_grpc_client_unary_stream_starts_span( grpc_server_and_channel, - capture_events_forksafe, capture_items_forksafe, - span_streaming, ): - _, channel = await grpc_server_and_channel(span_streaming) + _, channel = await grpc_server_and_channel() # Use the provided channel stub = gRPCTestServiceStub(channel) - - if span_streaming: - items = capture_items_forksafe("span") - - with sentry_sdk.traces.start_span(name="custom parent"): - response = stub.TestUnaryStream(gRPCTestMessage(text="test")) - [_ async for _ in response] - - sentry_sdk.flush() - items.write_file.close() - items = items.read_event() - spans = [item["payload"] for item in items if item["type"] == "span"] - span = spans[0] - - assert len(spans) == 2 - assert span["attributes"]["sentry.op"] == OP.GRPC_CLIENT - assert ( - span["name"] - == "unary stream call to /grpc_test_server.gRPCTestService/TestUnaryStream" - ) - assert span["attributes"] == ApproxDict( - { - "rpc.method": "/grpc_test_server.gRPCTestService/TestUnaryStream", - "sentry.environment": mock.ANY, - "sentry.op": "grpc.client", - "sentry.origin": "auto.grpc.grpc", - "sentry.release": mock.ANY, - "sentry.sdk.name": "sentry.python", - "sentry.sdk.version": mock.ANY, - "sentry.segment.id": mock.ANY, - "sentry.segment.name": "custom parent", - "server.address": mock.ANY, - "thread.id": mock.ANY, - "thread.name": mock.ANY, - } - ) - else: - events = capture_events_forksafe() - - with start_transaction(): - response = stub.TestUnaryStream(gRPCTestMessage(text="test")) - [_ async for _ in response] - - events.write_file.close() - local_transaction = events.read_event() - span = local_transaction["spans"][0] - - assert len(local_transaction["spans"]) == 1 - assert span["op"] == OP.GRPC_CLIENT - assert ( - span["description"] - == "unary stream call to /grpc_test_server.gRPCTestService/TestUnaryStream" - ) - assert span["data"] == ApproxDict( - { - "type": "unary stream", - "method": "/grpc_test_server.gRPCTestService/TestUnaryStream", - } - ) + items = capture_items_forksafe("span") + + with sentry_sdk.traces.start_span(name="custom parent"): + response = stub.TestUnaryStream(gRPCTestMessage(text="test")) + [_ async for _ in response] + + sentry_sdk.flush() + items.write_file.close() + items = items.read_event() + spans = [item["payload"] for item in items if item["type"] == "span"] + span = spans[0] + + assert len(spans) == 2 + assert span["attributes"]["sentry.op"] == OP.GRPC_CLIENT + assert ( + span["name"] + == "unary stream call to /grpc_test_server.gRPCTestService/TestUnaryStream" + ) + assert span["attributes"] == ApproxDict( + { + "rpc.method": "/grpc_test_server.gRPCTestService/TestUnaryStream", + "sentry.environment": mock.ANY, + "sentry.op": "grpc.client", + "sentry.origin": "auto.grpc.grpc", + "sentry.release": mock.ANY, + "sentry.sdk.name": "sentry.python", + "sentry.sdk.version": mock.ANY, + "sentry.segment.id": mock.ANY, + "sentry.segment.name": "custom parent", + "server.address": mock.ANY, + "thread.id": mock.ANY, + "thread.name": mock.ANY, + } + ) @pytest.mark.asyncio @@ -452,7 +300,7 @@ async def test_stream_stream(grpc_server_and_channel): Test to verify stream-stream works. Tracing not supported for it yet. """ - _, channel = await grpc_server_and_channel(False) + _, channel = await grpc_server_and_channel() # Use the provided channel stub = gRPCTestServiceStub(channel) @@ -467,7 +315,7 @@ async def test_stream_unary(grpc_server_and_channel): Test to verify stream-stream works. Tracing not supported for it yet. """ - _, channel = await grpc_server_and_channel(False) + _, channel = await grpc_server_and_channel() # Use the provided channel stub = gRPCTestServiceStub(channel) @@ -476,59 +324,32 @@ async def test_stream_unary(grpc_server_and_channel): @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_span_origin( grpc_server_and_channel, - capture_events_forksafe, capture_items_forksafe, - span_streaming, ): - _, channel = await grpc_server_and_channel(span_streaming) + _, channel = await grpc_server_and_channel() # Use the provided channel stub = gRPCTestServiceStub(channel) + items = capture_items_forksafe("span") - if span_streaming: - items = capture_items_forksafe("span") - - with sentry_sdk.traces.start_span(name="custom parent"): - await stub.TestServe(gRPCTestMessage(text="test")) - - sentry_sdk.flush() - items.write_file.close() - items = items.read_event() - - spans = [item["payload"] for item in items if item["type"] == "span"] - - assert spans[1]["attributes"]["sentry.origin"] == "auto.grpc.grpc" - assert ( - spans[0]["attributes"]["sentry.origin"] == "auto.grpc.grpc.TestService.aio" - ) # manually created in TestService, not the instrumentation - - assert spans[3]["attributes"]["sentry.origin"] == "manual" - assert spans[2]["attributes"]["sentry.origin"] == "auto.grpc.grpc" - else: - events = capture_events_forksafe() - - with start_transaction(name="custom_transaction"): - await stub.TestServe(gRPCTestMessage(text="test")) + with sentry_sdk.traces.start_span(name="custom parent"): + await stub.TestServe(gRPCTestMessage(text="test")) - events.write_file.close() + sentry_sdk.flush() + items.write_file.close() + items = items.read_event() - transaction_from_integration = events.read_event() - custom_transaction = events.read_event() + spans = [item["payload"] for item in items if item["type"] == "span"] - assert ( - transaction_from_integration["contexts"]["trace"]["origin"] - == "auto.grpc.grpc" - ) - assert ( - transaction_from_integration["spans"][0]["origin"] - == "auto.grpc.grpc.TestService.aio" - ) # manually created in TestService, not the instrumentation + assert spans[1]["attributes"]["sentry.origin"] == "auto.grpc.grpc" + assert ( + spans[0]["attributes"]["sentry.origin"] == "auto.grpc.grpc.TestService.aio" + ) # manually created in TestService, not the instrumentation - assert custom_transaction["contexts"]["trace"]["origin"] == "manual" - assert custom_transaction["spans"][0]["origin"] == "auto.grpc.grpc" + assert spans[3]["attributes"]["sentry.origin"] == "manual" + assert spans[2]["attributes"]["sentry.origin"] == "auto.grpc.grpc" class TestService(gRPCTestServiceServicer): @@ -540,25 +361,14 @@ def __init__(self): @classmethod async def TestServe(cls, request, context): # noqa: N802 - client = sentry_sdk.get_client() - span_streaming = has_span_streaming_enabled(client.options) - - if span_streaming: - with sentry_sdk.traces.start_span( - name="test", - attributes={ - "sentry.op": "test", - "sentry.origin": "auto.grpc.grpc.TestService.aio", - }, - ): - pass - else: - with start_span( - op="test", - name="test", - origin="auto.grpc.grpc.TestService.aio", - ): - pass + with sentry_sdk.traces.start_span( + name="test", + attributes={ + "sentry.op": "test", + "sentry.origin": "auto.grpc.grpc.TestService.aio", + }, + ): + pass if request.text == "exception": raise cls.TestException()