From cb107fd2515a26dd4ef421c30d2d057f22574276 Mon Sep 17 00:00:00 2001 From: hossein raeisi Date: Sat, 18 Feb 2023 16:37:52 +0330 Subject: [PATCH 01/34] feat(integrations) Implement an integration for tracing socket module Implement SocketIntegration; patches socket's getaddrinfo and create_connection and adds spans to them --- sentry_sdk/consts.py | 2 + sentry_sdk/integrations/socket.py | 68 ++++++++++++++++++++++++ tests/integrations/socket/__init__.py | 3 ++ tests/integrations/socket/test_socket.py | 51 ++++++++++++++++++ tox.ini | 11 ++-- 5 files changed, 130 insertions(+), 5 deletions(-) create mode 100644 sentry_sdk/integrations/socket.py create mode 100644 tests/integrations/socket/__init__.py create mode 100644 tests/integrations/socket/test_socket.py diff --git a/sentry_sdk/consts.py b/sentry_sdk/consts.py index 2d2b28b9ee..466b8ee817 100644 --- a/sentry_sdk/consts.py +++ b/sentry_sdk/consts.py @@ -77,6 +77,8 @@ class OP: VIEW_RENDER = "view.render" VIEW_RESPONSE_RENDER = "view.response.render" WEBSOCKET_SERVER = "websocket.server" + SOCKET_CONNECTION = "socket.connection" + SOCKET_DNS = "socket.dns" # This type exists to trick mypy and PyCharm into thinking `init` and `Client` diff --git a/sentry_sdk/integrations/socket.py b/sentry_sdk/integrations/socket.py new file mode 100644 index 0000000000..a0d90790d2 --- /dev/null +++ b/sentry_sdk/integrations/socket.py @@ -0,0 +1,68 @@ +import socket + +from sentry_sdk import Hub +from sentry_sdk.consts import OP +from sentry_sdk.integrations import Integration + +__all__ = ["SocketIntegration"] + + +class SocketIntegration(Integration): + identifier = "socket" + + @staticmethod + def setup_once(): + # type: () -> None + """ + patches two of the most used functions of socket: create_connection and getaddrinfo(dns resolver) + """ + _patch_create_connection() + _patch_getaddrinfo() + + +def _patch_create_connection(): + # type: () -> None + real_create_connection = socket.create_connection + + def create_connection( + address, timeout=socket._GLOBAL_DEFAULT_TIMEOUT, source_address=None + ): + # type: (tuple[str, None | int], float | None, tuple[bytearray | bytes | str, int] | None) -> socket + hub = Hub.current + if hub.get_integration(SocketIntegration) is None: + return real_create_connection( + address=address, timeout=timeout, source_address=source_address + ) + + with hub.start_span( + op=OP.SOCKET_CONNECTION, description="%s:%s" % (address[0], address[1]) + ) as span: + span.set_data("address", address) + span.set_data("timeout", timeout) + span.set_data("source_address", source_address) + + return real_create_connection( + address=address, timeout=timeout, source_address=source_address + ) + + socket.create_connection = create_connection + + +def _patch_getaddrinfo(): + # type: () -> None + real_getaddrinfo = socket.getaddrinfo + + def getaddrinfo(host, port, *args, **kwargs): + hub = Hub.current + if hub.get_integration(SocketIntegration) is None: + return real_getaddrinfo(host, port, *args, **kwargs) + + with hub.start_span( + op=OP.SOCKET_DNS, description="%s:%s" % (host, port) + ) as span: + span.set_data("host", host) + span.set_data("port", port) + + return real_getaddrinfo(host, port, *args, **kwargs) + + socket.getaddrinfo = getaddrinfo diff --git a/tests/integrations/socket/__init__.py b/tests/integrations/socket/__init__.py new file mode 100644 index 0000000000..893069b21b --- /dev/null +++ b/tests/integrations/socket/__init__.py @@ -0,0 +1,3 @@ +import pytest + +pytest.importorskip("socket") diff --git a/tests/integrations/socket/test_socket.py b/tests/integrations/socket/test_socket.py new file mode 100644 index 0000000000..914ba0bf84 --- /dev/null +++ b/tests/integrations/socket/test_socket.py @@ -0,0 +1,51 @@ +import socket + +from sentry_sdk import start_transaction +from sentry_sdk.integrations.socket import SocketIntegration + + +def test_getaddrinfo_trace(sentry_init, capture_events): + sentry_init(integrations=[SocketIntegration()], traces_sample_rate=1.0) + events = capture_events() + + with start_transaction(): + socket.getaddrinfo("example.com", 443) + + (event,) = events + (span,) = event["spans"] + + assert span["op"] == "socket.dns" + assert span["description"] == "example.com:443" + assert span["data"] == { + "host": "example.com", + "port": 443, + } + + +def test_create_connection_trace(sentry_init, capture_events): + timeout = 10 + + sentry_init(integrations=[SocketIntegration()], traces_sample_rate=1.0) + events = capture_events() + + with start_transaction(): + socket.create_connection(("example.com", 443), timeout, None) + + (event,) = events + (connect_span, dns_span) = event["spans"] + # as getaddrinfo gets called in create_connection it should also contain a dns span + + assert connect_span["op"] == "socket.connection" + assert connect_span["description"] == "example.com:443" + assert connect_span["data"] == { + "address": ["example.com", 443], + "timeout": timeout, + "source_address": None, + } + + assert dns_span["op"] == "socket.dns" + assert dns_span["description"] == "example.com:443" + assert dns_span["data"] == { + "host": "example.com", + "port": 443, + } diff --git a/tox.ini b/tox.ini index d1b058dc71..12b84e8694 100644 --- a/tox.ini +++ b/tox.ini @@ -66,7 +66,7 @@ envlist = {py2.7,py3.5,py3.6,py3.7}-falcon-v{1.4} {py2.7,py3.5,py3.6,py3.7}-falcon-v{2.0} {py3.5,py3.6,py3.7,py3.8,py3.9}-falcon-v{3.0} - + # FastAPI {py3.7,py3.8,py3.9,py3.10,py3.11}-fastapi @@ -80,9 +80,9 @@ envlist = # HTTPX {py3.6,py3.7,py3.8,py3.9,py3.10,py3.11}-httpx-v{0.16,0.17} - + # Huey - {py2.7,py3.5,py3.6,py3.7,py3.8,py3.9,py3.10,py3.11}-huey-2 + {py2.7,py3.5,py3.6,py3.7,py3.8,py3.9,py3.10,py3.11}-huey-2 # OpenTelemetry (OTel) {py3.7,py3.8,py3.9,py3.10,py3.11}-opentelemetry @@ -266,10 +266,10 @@ deps = # HTTPX httpx-v0.16: httpx>=0.16,<0.17 httpx-v0.17: httpx>=0.17,<0.18 - + # Huey huey-2: huey>=2.0 - + # OpenTelemetry (OTel) opentelemetry: opentelemetry-distro @@ -407,6 +407,7 @@ setenv = sqlalchemy: TESTPATH=tests/integrations/sqlalchemy tornado: TESTPATH=tests/integrations/tornado trytond: TESTPATH=tests/integrations/trytond + socket: TESTPATH=tests/integrations/socket COVERAGE_FILE=.coverage-{envname} passenv = From 41631e48e307e90d3adc872844d33cda4bb9fbd9 Mon Sep 17 00:00:00 2001 From: hossein raeisi Date: Sun, 19 Feb 2023 18:07:30 +0330 Subject: [PATCH 02/34] feat(tracing) Implement an interceptor for grpc server Implement gRPC ServerInterceptor; starts(or continues) a transaction for each grpc request --- sentry_sdk/consts.py | 1 + sentry_sdk/integrations/grpc/__init__.py | 1 + sentry_sdk/integrations/grpc/server.py | 59 +++++++++ setup.py | 1 + test-requirements.txt | 4 + tests/conftest.py | 11 +- tests/integrations/grpc/__init__.py | 3 + tests/integrations/grpc/test_server.py | 121 ++++++++++++++++++ tests/integrations/grpc/test_service.proto | 11 ++ tests/integrations/grpc/test_service_pb2.py | 28 ++++ tests/integrations/grpc/test_service_pb2.pyi | 32 +++++ .../grpc/test_service_pb2_grpc.py | 79 ++++++++++++ tox.ini | 5 + 13 files changed, 351 insertions(+), 5 deletions(-) create mode 100644 sentry_sdk/integrations/grpc/__init__.py create mode 100644 sentry_sdk/integrations/grpc/server.py create mode 100644 tests/integrations/grpc/__init__.py create mode 100644 tests/integrations/grpc/test_server.py create mode 100644 tests/integrations/grpc/test_service.proto create mode 100644 tests/integrations/grpc/test_service_pb2.py create mode 100644 tests/integrations/grpc/test_service_pb2.pyi create mode 100644 tests/integrations/grpc/test_service_pb2_grpc.py diff --git a/sentry_sdk/consts.py b/sentry_sdk/consts.py index 466b8ee817..6591a9b1fd 100644 --- a/sentry_sdk/consts.py +++ b/sentry_sdk/consts.py @@ -79,6 +79,7 @@ class OP: WEBSOCKET_SERVER = "websocket.server" SOCKET_CONNECTION = "socket.connection" SOCKET_DNS = "socket.dns" + GRPC_SERVER = "grpc.server" # This type exists to trick mypy and PyCharm into thinking `init` and `Client` diff --git a/sentry_sdk/integrations/grpc/__init__.py b/sentry_sdk/integrations/grpc/__init__.py new file mode 100644 index 0000000000..d611d4dacb --- /dev/null +++ b/sentry_sdk/integrations/grpc/__init__.py @@ -0,0 +1 @@ +from .server import ServerInterceptor diff --git a/sentry_sdk/integrations/grpc/server.py b/sentry_sdk/integrations/grpc/server.py new file mode 100644 index 0000000000..a63fd98032 --- /dev/null +++ b/sentry_sdk/integrations/grpc/server.py @@ -0,0 +1,59 @@ +from sentry_sdk import Hub +from sentry_sdk._types import MYPY +from sentry_sdk.consts import OP +from sentry_sdk.integrations import DidNotEnable +from sentry_sdk.tracing import Transaction, TRANSACTION_SOURCE_CUSTOM + +if MYPY: + from typing import Callable + +try: + import grpc +except ImportError: + raise DidNotEnable("grpcio is not installed") + + +class ServerInterceptor(grpc.ServerInterceptor): + def __init__(self, find_name=None): + # type: (ServerInterceptor, Callable | None) -> ServerInterceptor + if find_name: + self._find_method_name = find_name + super(ServerInterceptor, self).__init__() + + def intercept_service(self, continuation, handler_call_details): + handler = continuation(handler_call_details) + if not handler or not handler.unary_unary: + return handler + + def behavior(request, context): + hub = Hub(Hub.current) + + name = self._find_method_name(context) + + if name: + meta_data = dict(context.invocation_metadata()) + + transaction = Transaction.continue_from_headers( + meta_data, + op=OP.GRPC_SERVER, + name=name, + source=TRANSACTION_SOURCE_CUSTOM, + ) + + with hub.start_transaction(transaction=transaction): + try: + return handler.unary_unary(request, context) + except BaseException as e: + raise e + else: + return handler.unary_unary(request, context) + + return grpc.unary_unary_rpc_method_handler( + behavior, + request_deserializer=handler.request_deserializer, + response_serializer=handler.response_serializer, + ) + + @staticmethod + def _find_name(context): + return context._rpc_event.call_details.method.decode() diff --git a/setup.py b/setup.py index 07756acabc..7d0c42abf4 100644 --- a/setup.py +++ b/setup.py @@ -66,6 +66,7 @@ def get_file_text(file_name): "fastapi": ["fastapi>=0.79.0"], "pymongo": ["pymongo>=3.1"], "opentelemetry": ["opentelemetry-distro>=0.35b0"], + "grpcio": ["grpcio>=1.21.1"] }, classifiers=[ "Development Status :: 5 - Production/Stable", diff --git a/test-requirements.txt b/test-requirements.txt index 5d449df716..94fd5b8463 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -13,3 +13,7 @@ executing asttokens responses ipdb +grpcio-tools +protobuf +mypy-protobuf +types-protobuf diff --git a/tests/conftest.py b/tests/conftest.py index cb1fedb4c6..d779c99e8d 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -298,20 +298,21 @@ def flush(timeout=None, callback=None): monkeypatch.setattr(test_client.transport, "capture_event", append) monkeypatch.setattr(test_client, "flush", flush) - return EventStreamReader(events_r) + return EventStreamReader(events_r, events_w) return inner class EventStreamReader(object): - def __init__(self, file): - self.file = file + def __init__(self, read_file, write_file): + self.read_file = read_file + self.write_file = write_file def read_event(self): - return json.loads(self.file.readline().decode("utf-8")) + return json.loads(self.read_file.readline().decode("utf-8")) def read_flush(self): - assert self.file.readline() == b"flush\n" + assert self.read_file.readline() == b"flush\n" # scope=session ensures that fixture is run earlier diff --git a/tests/integrations/grpc/__init__.py b/tests/integrations/grpc/__init__.py new file mode 100644 index 0000000000..88a0a201e4 --- /dev/null +++ b/tests/integrations/grpc/__init__.py @@ -0,0 +1,3 @@ +import pytest + +pytest.importorskip("grpc") diff --git a/tests/integrations/grpc/test_server.py b/tests/integrations/grpc/test_server.py new file mode 100644 index 0000000000..94dd1b28d4 --- /dev/null +++ b/tests/integrations/grpc/test_server.py @@ -0,0 +1,121 @@ +from __future__ import absolute_import + +from concurrent import futures + +import grpc +import pytest + +from sentry_sdk import Hub, start_transaction +from sentry_sdk.consts import OP +from sentry_sdk.integrations.grpc.server import ServerInterceptor +from tests.integrations.grpc.test_service_pb2 import TestMessage +from tests.integrations.grpc.test_service_pb2_grpc import ( + TestServiceServicer, + add_TestServiceServicer_to_server, + TestServiceStub, +) + +PORT = 50051 + + +@pytest.mark.forked +def test_grpc_server_starts_transaction(sentry_init, capture_events_forksafe): + sentry_init(traces_sample_rate=1.0) + events = capture_events_forksafe() + + server = _set_up() + + with grpc.insecure_channel(f"localhost:{PORT}") as channel: + stub = TestServiceStub(channel) + stub.TestServe(TestMessage(text="test")) + + _tear_down(server=server) + + events.write_file.close() + event = events.read_event() + 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" + + +@pytest.mark.forked +def test_grpc_server_continues_transaction(sentry_init, capture_events_forksafe): + sentry_init(traces_sample_rate=1.0) + events = capture_events_forksafe() + + server = _set_up() + + with grpc.insecure_channel(f"localhost:{PORT}") as channel: + stub = TestServiceStub(channel) + + 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 + ), + ), + ( + "sentry-trace", + "{trace_id}-{parent_span_id}-{sampled}".format( + trace_id=transaction.trace_id, + parent_span_id=transaction.span_id, + sampled=1, + ) + ) + ) + stub.TestServe(TestMessage(text="test"), metadata=metadata) + + _tear_down(server=server) + + events.write_file.close() + event = events.read_event() + span = event["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" + + +def _set_up(): + server = grpc.server( + futures.ThreadPoolExecutor(max_workers=2), + interceptors=[ServerInterceptor(find_name=_find_name)], + ) + + add_TestServiceServicer_to_server(TestService, server) + server.add_insecure_port(f"[::]:{PORT}") + server.start() + + return server + + +def _tear_down(server: grpc.Server): + server.stop(None) + + +def _find_name(request): + return request.__class__ + + +class TestService(TestServiceServicer): + events = [] + + @staticmethod + def TestServe(request, context): + hub = Hub.current + with hub.start_span(op="test", description="test"): + pass + + return TestMessage(text=request.text) diff --git a/tests/integrations/grpc/test_service.proto b/tests/integrations/grpc/test_service.proto new file mode 100644 index 0000000000..1818389754 --- /dev/null +++ b/tests/integrations/grpc/test_service.proto @@ -0,0 +1,11 @@ +syntax = "proto3"; + +package test_grpc_server; + +service TestService{ + rpc TestServe(TestMessage) returns (TestMessage); +} + +message TestMessage { + string text = 1; +} diff --git a/tests/integrations/grpc/test_service_pb2.py b/tests/integrations/grpc/test_service_pb2.py new file mode 100644 index 0000000000..fe29fad34e --- /dev/null +++ b/tests/integrations/grpc/test_service_pb2.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: test_service.proto +"""Generated protocol buffer code.""" +from google.protobuf.internal import builder as _builder +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import symbol_database as _symbol_database + +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile( + b'\n\x12test_service.proto\x12\x10test_grpc_server"\x1b\n\x0bTestMessage\x12\x0c\n\x04text\x18\x01 \x01(\t2X\n\x0bTestService\x12I\n\tTestServe\x12\x1d.test_grpc_server.TestMessage\x1a\x1d.test_grpc_server.TestMessageb\x06proto3' +) + +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "test_service_pb2", globals()) +if _descriptor._USE_C_DESCRIPTORS == False: + + DESCRIPTOR._options = None + _TESTMESSAGE._serialized_start = 40 + _TESTMESSAGE._serialized_end = 67 + _TESTSERVICE._serialized_start = 69 + _TESTSERVICE._serialized_end = 157 +# @@protoc_insertion_point(module_scope) diff --git a/tests/integrations/grpc/test_service_pb2.pyi b/tests/integrations/grpc/test_service_pb2.pyi new file mode 100644 index 0000000000..d37eefb5de --- /dev/null +++ b/tests/integrations/grpc/test_service_pb2.pyi @@ -0,0 +1,32 @@ +""" +@generated by mypy-protobuf. Do not edit manually! +isort:skip_file +""" +import builtins +import google.protobuf.descriptor +import google.protobuf.message +import sys + +if sys.version_info >= (3, 8): + import typing as typing_extensions +else: + import typing_extensions + +DESCRIPTOR: google.protobuf.descriptor.FileDescriptor + +@typing_extensions.final +class TestMessage(google.protobuf.message.Message): + DESCRIPTOR: google.protobuf.descriptor.Descriptor + + TEXT_FIELD_NUMBER: builtins.int + text: builtins.str + def __init__( + self, + *, + text: builtins.str = ..., + ) -> None: ... + def ClearField( + self, field_name: typing_extensions.Literal["text", b"text"] + ) -> None: ... + +global___TestMessage = TestMessage diff --git a/tests/integrations/grpc/test_service_pb2_grpc.py b/tests/integrations/grpc/test_service_pb2_grpc.py new file mode 100644 index 0000000000..52a2e873a7 --- /dev/null +++ b/tests/integrations/grpc/test_service_pb2_grpc.py @@ -0,0 +1,79 @@ +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! +"""Client and server classes corresponding to protobuf-defined services.""" +import grpc + +import tests.integrations.grpc.test_service_pb2 as test__service__pb2 + + +class TestServiceStub(object): + """Missing associated documentation comment in .proto file.""" + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.TestServe = channel.unary_unary( + "/test_grpc_server.TestService/TestServe", + request_serializer=test__service__pb2.TestMessage.SerializeToString, + response_deserializer=test__service__pb2.TestMessage.FromString, + ) + + +class TestServiceServicer(object): + """Missing associated documentation comment in .proto file.""" + + def TestServe(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!") + + +def add_TestServiceServicer_to_server(servicer, server): + rpc_method_handlers = { + "TestServe": grpc.unary_unary_rpc_method_handler( + servicer.TestServe, + request_deserializer=test__service__pb2.TestMessage.FromString, + response_serializer=test__service__pb2.TestMessage.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + "test_grpc_server.TestService", rpc_method_handlers + ) + server.add_generic_rpc_handlers((generic_handler,)) + + +# This class is part of an EXPERIMENTAL API. +class TestService(object): + """Missing associated documentation comment in .proto file.""" + + @staticmethod + def TestServe( + request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None, + ): + return grpc.experimental.unary_unary( + request, + target, + "/test_grpc_server.TestService/TestServe", + test__service__pb2.TestMessage.SerializeToString, + test__service__pb2.TestMessage.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + ) diff --git a/tox.ini b/tox.ini index 12b84e8694..45f6cd1121 100644 --- a/tox.ini +++ b/tox.ini @@ -140,6 +140,10 @@ envlist = {py3.5,py3.6,py3.7,py3.8,py3.9}-trytond-v{4.6,5.0,5.2} {py3.6,py3.7,py3.8,py3.9,py3.10,py3.11}-trytond-v{5.4} + # Grpc + {py3.7,py3.8,py3.9,py3.10,py3.11}-grpcio-v{1.51.1} + {py3.6,py3.7,py3.8,py3.9,py3.10,py3.11}-grpcio-v{1.41.1,1.43.0,1.44.0,1.46.1,1.48.1} + {py3.5,py3.6,py3.7,py3.8,py3.9,py3.10,py3.11}-grpcio-v{1.21.1,1.22.1,1.23.1,1.24.1,1.25.0,1.26.0,1.27.1,1.28.1,1.29.0,1.30.0,1.31.0,1.32.0,1.33.1,1.34.0,1.36.0,1.37.0,1.38.0,1.39.0,1.40.0} [testenv] deps = @@ -408,6 +412,7 @@ setenv = tornado: TESTPATH=tests/integrations/tornado trytond: TESTPATH=tests/integrations/trytond socket: TESTPATH=tests/integrations/socket + grpc: TESTPATH=tests/integrations/grpc COVERAGE_FILE=.coverage-{envname} passenv = From 5c2db86df48022b86bb83ee5d65b64e1e2d5dda6 Mon Sep 17 00:00:00 2001 From: hossein raeisi Date: Mon, 20 Feb 2023 21:21:22 +0330 Subject: [PATCH 03/34] feat(tracing) Implement unary-unary and unary-stream interceptors for grpc stub Implement gRPC UnaryUnaryClientInterceptor and grpc.UnaryStreamClientInterceptor; starts a span for grpc call and sends propagation headers in metadata --- sentry_sdk/consts.py | 1 + sentry_sdk/integrations/grpc/__init__.py | 1 + sentry_sdk/integrations/grpc/client.py | 73 +++++++++++++++++++ .../grpc/{test_server.py => test_grpc.py} | 69 +++++++++++++++++- 4 files changed, 142 insertions(+), 2 deletions(-) create mode 100644 sentry_sdk/integrations/grpc/client.py rename tests/integrations/grpc/{test_server.py => test_grpc.py} (62%) diff --git a/sentry_sdk/consts.py b/sentry_sdk/consts.py index 6591a9b1fd..117db6382b 100644 --- a/sentry_sdk/consts.py +++ b/sentry_sdk/consts.py @@ -80,6 +80,7 @@ class OP: SOCKET_CONNECTION = "socket.connection" SOCKET_DNS = "socket.dns" GRPC_SERVER = "grpc.server" + GRPC_CLIENT = "grpc.client" # This type exists to trick mypy and PyCharm into thinking `init` and `Client` diff --git a/sentry_sdk/integrations/grpc/__init__.py b/sentry_sdk/integrations/grpc/__init__.py index d611d4dacb..2e35bf8cdd 100644 --- a/sentry_sdk/integrations/grpc/__init__.py +++ b/sentry_sdk/integrations/grpc/__init__.py @@ -1 +1,2 @@ from .server import ServerInterceptor +from .client import ClientInterceptor diff --git a/sentry_sdk/integrations/grpc/client.py b/sentry_sdk/integrations/grpc/client.py new file mode 100644 index 0000000000..06a05d89c2 --- /dev/null +++ b/sentry_sdk/integrations/grpc/client.py @@ -0,0 +1,73 @@ +from sentry_sdk import Hub +from sentry_sdk._types import MYPY +from sentry_sdk.consts import OP +from sentry_sdk.integrations import DidNotEnable + +if MYPY: + pass + +try: + import grpc +except ImportError: + raise DidNotEnable("grpcio is not installed") + + +class ClientInterceptor( + grpc.UnaryUnaryClientInterceptor, grpc.UnaryStreamClientInterceptor +): + def intercept_unary_unary(self, continuation, client_call_details, request): + hub = Hub.current + method = client_call_details.method + + with hub.start_span( + op=OP.GRPC_CLIENT, description="unary unary call to %s" % method + ) as span: + span.set_data("type", "unary unary") + span.set_data("method", method) + + client_call_details = self._update_client_call_details_metadata_from_hub( + client_call_details, hub + ) + + response = continuation(client_call_details, request) + span.set_data("code", response.code().name) + + return response + + def intercept_unary_stream(self, continuation, client_call_details, request): + hub = Hub.current + method = client_call_details.method + + with hub.start_span( + op=OP.GRPC_CLIENT, description="unary stream call to %s" % method + ) as span: + span.set_data("type", "unary stream") + span.set_data("method", method) + + client_call_details = self._update_client_call_details_metadata_from_hub( + client_call_details, hub + ) + + response = continuation(client_call_details, request) + span.set_data("code", response.code().name) + + return response + + @staticmethod + def _update_client_call_details_metadata_from_hub(client_call_details, hub): + metadata = ( + list(client_call_details.metadata) if client_call_details.metadata else [] + ) + for key, value in hub.iter_trace_propagation_headers(): + metadata.append((key, value)) + + client_call_details = grpc._interceptor._ClientCallDetails( + method=client_call_details.method, + timeout=client_call_details.timeout, + metadata=metadata, + credentials=client_call_details.credentials, + wait_for_ready=client_call_details.wait_for_ready, + compression=client_call_details.compression, + ) + + return client_call_details diff --git a/tests/integrations/grpc/test_server.py b/tests/integrations/grpc/test_grpc.py similarity index 62% rename from tests/integrations/grpc/test_server.py rename to tests/integrations/grpc/test_grpc.py index 94dd1b28d4..842f7bb8ef 100644 --- a/tests/integrations/grpc/test_server.py +++ b/tests/integrations/grpc/test_grpc.py @@ -7,6 +7,7 @@ from sentry_sdk import Hub, start_transaction from sentry_sdk.consts import OP +from sentry_sdk.integrations.grpc.client import ClientInterceptor from sentry_sdk.integrations.grpc.server import ServerInterceptor from tests.integrations.grpc.test_service_pb2 import TestMessage from tests.integrations.grpc.test_service_pb2_grpc import ( @@ -68,8 +69,8 @@ def test_grpc_server_continues_transaction(sentry_init, capture_events_forksafe) trace_id=transaction.trace_id, parent_span_id=transaction.span_id, sampled=1, - ) - ) + ), + ), ) stub.TestServe(TestMessage(text="test"), metadata=metadata) @@ -88,6 +89,70 @@ def test_grpc_server_continues_transaction(sentry_init, capture_events_forksafe) assert span["op"] == "test" +@pytest.mark.forked +def test_grpc_client_starts_span(sentry_init, capture_events_forksafe): + sentry_init(traces_sample_rate=1.0) + events = capture_events_forksafe() + interceptors = [ClientInterceptor()] + + server = _set_up() + + with grpc.insecure_channel(f"localhost:{PORT}") as channel: + channel = grpc.intercept_channel(channel, *interceptors) + stub = TestServiceStub(channel) + + with start_transaction(): + stub.TestServe(TestMessage(text="test")) + + _tear_down(server=server) + + 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 /test_grpc_server.TestService/TestServe" + ) + assert span["data"] == { + "type": "unary unary", + "method": "/test_grpc_server.TestService/TestServe", + "code": "OK", + } + + +@pytest.mark.forked +def test_grpc_client_and_servers_interceptors_integration( + sentry_init, capture_events_forksafe +): + sentry_init(traces_sample_rate=1.0) + events = capture_events_forksafe() + interceptors = [ClientInterceptor()] + + server = _set_up() + + with grpc.insecure_channel(f"localhost:{PORT}") as channel: + channel = grpc.intercept_channel(channel, *interceptors) + stub = TestServiceStub(channel) + + with start_transaction(): + stub.TestServe(TestMessage(text="test")) + + _tear_down(server=server) + + events.write_file.close() + server_transaction = events.read_event() + local_transaction = events.read_event() + + assert ( + server_transaction["contexts"]["trace"]["trace_id"] + == local_transaction["contexts"]["trace"]["trace_id"] + ) + + def _set_up(): server = grpc.server( futures.ThreadPoolExecutor(max_workers=2), From 3e35b1648284e9908e2e9d095cf935ccfc3416fe Mon Sep 17 00:00:00 2001 From: Anton Pirker Date: Fri, 3 Mar 2023 09:22:42 +0100 Subject: [PATCH 04/34] Fixed httpx mess up --- tox.ini | 1 - 1 file changed, 1 deletion(-) diff --git a/tox.ini b/tox.ini index b657bd586d..b228f9a681 100644 --- a/tox.ini +++ b/tox.ini @@ -88,7 +88,6 @@ envlist = {py3.7}-gcp # HTTPX - {py3.6,py3.7,py3.8,py3.9,py3.10,py3.11}-httpx-v{0.16,0.17} {py3.6,py3.7,py3.8,py3.9}-httpx-v{0.16,0.17,0.18} {py3.6,py3.7,py3.8,py3.9,py3.10}-httpx-v{0.19,0.20,0.21,0.22} {py3.7,py3.8,py3.9,py3.10,py3.11}-httpx-v{0.23} From e3194ca534becd1a171b14bd25fbe48c8044e6ed Mon Sep 17 00:00:00 2001 From: Anton Pirker Date: Fri, 3 Mar 2023 09:27:16 +0100 Subject: [PATCH 05/34] Updated test config --- .github/workflows/test-integration-grpcio.yml | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 .github/workflows/test-integration-grpcio.yml diff --git a/.github/workflows/test-integration-grpcio.yml b/.github/workflows/test-integration-grpcio.yml new file mode 100644 index 0000000000..03743bec25 --- /dev/null +++ b/.github/workflows/test-integration-grpcio.yml @@ -0,0 +1,73 @@ +name: Test grpcio + +on: + push: + branches: + - master + - release/** + + pull_request: + +# Cancel in progress workflows on pull_requests. +# https://docs.github.com/en/actions/using-jobs/using-concurrency#example-using-a-fallback-value +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +permissions: + contents: read + +env: + BUILD_CACHE_KEY: ${{ github.sha }} + CACHED_BUILD_PATHS: | + ${{ github.workspace }}/dist-serverless + +jobs: + test: + name: grpcio, python ${{ matrix.python-version }}, ${{ matrix.os }} + runs-on: ${{ matrix.os }} + timeout-minutes: 45 + + strategy: + fail-fast: false + matrix: + python-version: ["3.7","3.8","3.9","3.10","3.11","3.6","3.5"] + # python3.6 reached EOL and is no longer being supported on + # new versions of hosted runners on Github Actions + # ubuntu-20.04 is the last version that supported python3.6 + # see https://github.com/actions/setup-python/issues/544#issuecomment-1332535877 + os: [ubuntu-20.04] + + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + + - name: Setup Test Env + run: | + pip install codecov "tox>=3,<4" + + - name: Test grpcio + timeout-minutes: 45 + shell: bash + run: | + set -x # print commands that are executed + coverage erase + + ./scripts/runtox.sh "${{ matrix.python-version }}-grpcio" --cov=tests --cov=sentry_sdk --cov-report= --cov-branch + coverage combine .coverage* + coverage xml -i + codecov --file coverage.xml + + check_required_tests: + name: All grpcio tests passed or skipped + needs: test + # Always run this, even if a dependent job failed + if: always() + runs-on: ubuntu-20.04 + steps: + - name: Check for failures + if: contains(needs.test.result, 'failure') + run: | + echo "One of the dependent jobs have failed. You may need to re-run it." && exit 1 From 84d5b778451b7c76fe861a5a10d9ef02d58bc181 Mon Sep 17 00:00:00 2001 From: Anton Pirker Date: Fri, 3 Mar 2023 09:37:03 +0100 Subject: [PATCH 06/34] small nitpicking and fixes --- sentry_sdk/consts.py | 4 ++-- sentry_sdk/integrations/grpc/__init__.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sentry_sdk/consts.py b/sentry_sdk/consts.py index 01bcfa9f17..142c7ca1da 100644 --- a/sentry_sdk/consts.py +++ b/sentry_sdk/consts.py @@ -57,6 +57,8 @@ class OP: FUNCTION = "function" FUNCTION_AWS = "function.aws" FUNCTION_GCP = "function.gcp" + GRPC_CLIENT = "grpc.client" + GRPC_SERVER = "grpc.server" HTTP_CLIENT = "http.client" HTTP_CLIENT_STREAM = "http.client.stream" HTTP_SERVER = "http.server" @@ -83,8 +85,6 @@ class OP: WEBSOCKET_SERVER = "websocket.server" SOCKET_CONNECTION = "socket.connection" SOCKET_DNS = "socket.dns" - GRPC_SERVER = "grpc.server" - GRPC_CLIENT = "grpc.client" # This type exists to trick mypy and PyCharm into thinking `init` and `Client` diff --git a/sentry_sdk/integrations/grpc/__init__.py b/sentry_sdk/integrations/grpc/__init__.py index 2e35bf8cdd..59bfd502e5 100644 --- a/sentry_sdk/integrations/grpc/__init__.py +++ b/sentry_sdk/integrations/grpc/__init__.py @@ -1,2 +1,2 @@ -from .server import ServerInterceptor -from .client import ClientInterceptor +from .server import ServerInterceptor # noqa: F401 +from .client import ClientInterceptor # noqa: F401 From 4a09bf9526d3ffa8def7f4a4efe1185a618d3350 Mon Sep 17 00:00:00 2001 From: Anton Pirker Date: Fri, 3 Mar 2023 09:46:05 +0100 Subject: [PATCH 07/34] Fixed flake8 errors --- .flake8 | 4 ++++ tests/integrations/grpc/test_grpc.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.flake8 b/.flake8 index 37f5883f00..9bf2bed06c 100644 --- a/.flake8 +++ b/.flake8 @@ -15,3 +15,7 @@ extend-ignore = # is a worse version of and conflicts with B902 (first argument of a classmethod should be named cls) N804, extend-exclude=checkouts,lol* +exclude = + # gRCP generated files + test_service_pb2.py + test_service_pb2_grpc.py \ No newline at end of file diff --git a/tests/integrations/grpc/test_grpc.py b/tests/integrations/grpc/test_grpc.py index 842f7bb8ef..45cc6507b2 100644 --- a/tests/integrations/grpc/test_grpc.py +++ b/tests/integrations/grpc/test_grpc.py @@ -178,7 +178,7 @@ class TestService(TestServiceServicer): events = [] @staticmethod - def TestServe(request, context): + def TestServe(request, context): # noqa: N802 hub = Hub.current with hub.start_span(op="test", description="test"): pass From 01a51d3cf23908d6cd70c6b9a59632b25332460c Mon Sep 17 00:00:00 2001 From: hossein raeisi Date: Sun, 5 Mar 2023 00:06:08 +0330 Subject: [PATCH 08/34] feat(tracing) Add type hints for grpc and socket integrations --- mypy.ini | 2 ++ sentry_sdk/integrations/grpc/client.py | 12 +++++++++--- sentry_sdk/integrations/grpc/server.py | 9 +++++++-- sentry_sdk/integrations/socket.py | 20 +++++++++++++------- 4 files changed, 31 insertions(+), 12 deletions(-) diff --git a/mypy.ini b/mypy.ini index 0d12e43280..e25c2f1eac 100644 --- a/mypy.ini +++ b/mypy.ini @@ -67,3 +67,5 @@ ignore_missing_imports = True ignore_missing_imports = True [mypy-arq.*] ignore_missing_imports = True +[mypy-grpc.*] +ignore_missing_imports = True diff --git a/sentry_sdk/integrations/grpc/client.py b/sentry_sdk/integrations/grpc/client.py index 06a05d89c2..2548df9687 100644 --- a/sentry_sdk/integrations/grpc/client.py +++ b/sentry_sdk/integrations/grpc/client.py @@ -4,10 +4,13 @@ from sentry_sdk.integrations import DidNotEnable if MYPY: - pass + from typing import Callable, Iterator, Union try: import grpc + from grpc import ClientCallDetails, Call + from grpc._interceptor import _UnaryOutcome + from google.protobuf.message import Message except ImportError: raise DidNotEnable("grpcio is not installed") @@ -16,11 +19,12 @@ class ClientInterceptor( grpc.UnaryUnaryClientInterceptor, grpc.UnaryStreamClientInterceptor ): def intercept_unary_unary(self, continuation, client_call_details, request): + # type: (ClientInterceptor, Callable[[ClientCallDetails, Message], _UnaryOutcome], ClientCallDetails, Message) -> _UnaryOutcome hub = Hub.current method = client_call_details.method with hub.start_span( - op=OP.GRPC_CLIENT, description="unary unary call to %s" % method + op=OP.GRPC_CLIENT, description="unary unary call to %s" % method ) as span: span.set_data("type", "unary unary") span.set_data("method", method) @@ -35,11 +39,12 @@ def intercept_unary_unary(self, continuation, client_call_details, request): return response def intercept_unary_stream(self, continuation, client_call_details, request): + # type: (ClientInterceptor, Callable[[ClientCallDetails, Message], Iterator], ClientCallDetails, Message) -> Union[Iterator[Message], Call] hub = Hub.current method = client_call_details.method with hub.start_span( - op=OP.GRPC_CLIENT, description="unary stream call to %s" % method + op=OP.GRPC_CLIENT, description="unary stream call to %s" % method ) as span: span.set_data("type", "unary stream") span.set_data("method", method) @@ -55,6 +60,7 @@ def intercept_unary_stream(self, continuation, client_call_details, request): @staticmethod def _update_client_call_details_metadata_from_hub(client_call_details, hub): + # type: (ClientCallDetails, Hub) -> ClientCallDetails metadata = ( list(client_call_details.metadata) if client_call_details.metadata else [] ) diff --git a/sentry_sdk/integrations/grpc/server.py b/sentry_sdk/integrations/grpc/server.py index a63fd98032..8a56cd1709 100644 --- a/sentry_sdk/integrations/grpc/server.py +++ b/sentry_sdk/integrations/grpc/server.py @@ -5,27 +5,31 @@ from sentry_sdk.tracing import Transaction, TRANSACTION_SOURCE_CUSTOM if MYPY: - from typing import Callable + from typing import Callable, Optional + from google.protobuf.message import Message try: import grpc + from grpc import ServicerContext, HandlerCallDetails, RpcMethodHandler except ImportError: raise DidNotEnable("grpcio is not installed") class ServerInterceptor(grpc.ServerInterceptor): def __init__(self, find_name=None): - # type: (ServerInterceptor, Callable | None) -> ServerInterceptor + # type: (ServerInterceptor, Optional[Callable[[ServicerContext], str]]) -> None if find_name: self._find_method_name = find_name super(ServerInterceptor, self).__init__() def intercept_service(self, continuation, handler_call_details): + # type: (ServerInterceptor, Callable[[HandlerCallDetails], RpcMethodHandler], HandlerCallDetails) -> RpcMethodHandler handler = continuation(handler_call_details) if not handler or not handler.unary_unary: return handler def behavior(request, context): + # type: (Message, ServicerContext) -> Message hub = Hub(Hub.current) name = self._find_method_name(context) @@ -56,4 +60,5 @@ def behavior(request, context): @staticmethod def _find_name(context): + # type: (ServicerContext) -> str return context._rpc_event.call_details.method.decode() diff --git a/sentry_sdk/integrations/socket.py b/sentry_sdk/integrations/socket.py index a0d90790d2..68df79b723 100644 --- a/sentry_sdk/integrations/socket.py +++ b/sentry_sdk/integrations/socket.py @@ -1,9 +1,14 @@ import socket from sentry_sdk import Hub +from sentry_sdk._types import MYPY from sentry_sdk.consts import OP from sentry_sdk.integrations import Integration +if MYPY: + from socket import AddressFamily, SocketKind + from typing import Tuple, Optional, Union, List + __all__ = ["SocketIntegration"] @@ -25,9 +30,9 @@ def _patch_create_connection(): real_create_connection = socket.create_connection def create_connection( - address, timeout=socket._GLOBAL_DEFAULT_TIMEOUT, source_address=None + address, timeout=socket._GLOBAL_DEFAULT_TIMEOUT, source_address=None ): - # type: (tuple[str, None | int], float | None, tuple[bytearray | bytes | str, int] | None) -> socket + # type: (Tuple[Optional[str], int], Optional[float], Optional[Tuple[Union[bytearray, bytes, str], int]])-> socket.socket hub = Hub.current if hub.get_integration(SocketIntegration) is None: return real_create_connection( @@ -35,7 +40,7 @@ def create_connection( ) with hub.start_span( - op=OP.SOCKET_CONNECTION, description="%s:%s" % (address[0], address[1]) + op=OP.SOCKET_CONNECTION, description="%s:%s" % (address[0], address[1]) ) as span: span.set_data("address", address) span.set_data("timeout", timeout) @@ -52,17 +57,18 @@ def _patch_getaddrinfo(): # type: () -> None real_getaddrinfo = socket.getaddrinfo - def getaddrinfo(host, port, *args, **kwargs): + def getaddrinfo(host, port, family=0, type=0, proto=0, flags=0): + # type: (Union[bytes, str, None], Union[str, int, None], int, int, int, int) -> List[Tuple[AddressFamily, SocketKind, int, str, Union[Tuple[str, int], Tuple[str, int, int, int]]]] hub = Hub.current if hub.get_integration(SocketIntegration) is None: - return real_getaddrinfo(host, port, *args, **kwargs) + return real_getaddrinfo(host, port, family, type, proto, flags) with hub.start_span( - op=OP.SOCKET_DNS, description="%s:%s" % (host, port) + op=OP.SOCKET_DNS, description="%s:%s" % (host, port) ) as span: span.set_data("host", host) span.set_data("port", port) - return real_getaddrinfo(host, port, *args, **kwargs) + return real_getaddrinfo(host, port, family, type, proto, flags) socket.getaddrinfo = getaddrinfo From 8a8786facd9feb4f27d60232513b402fe039cdbd Mon Sep 17 00:00:00 2001 From: Anton Pirker Date: Tue, 28 Mar 2023 17:09:07 +0200 Subject: [PATCH 09/34] Some smaller fixes --- sentry_sdk/integrations/grpc/client.py | 4 ++-- sentry_sdk/integrations/grpc/server.py | 8 ++++---- sentry_sdk/integrations/socket.py | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/sentry_sdk/integrations/grpc/client.py b/sentry_sdk/integrations/grpc/client.py index 2548df9687..ba675b4722 100644 --- a/sentry_sdk/integrations/grpc/client.py +++ b/sentry_sdk/integrations/grpc/client.py @@ -24,7 +24,7 @@ def intercept_unary_unary(self, continuation, client_call_details, request): method = client_call_details.method with hub.start_span( - op=OP.GRPC_CLIENT, description="unary unary call to %s" % method + op=OP.GRPC_CLIENT, description="unary unary call to %s" % method ) as span: span.set_data("type", "unary unary") span.set_data("method", method) @@ -44,7 +44,7 @@ def intercept_unary_stream(self, continuation, client_call_details, request): method = client_call_details.method with hub.start_span( - op=OP.GRPC_CLIENT, description="unary stream call to %s" % method + op=OP.GRPC_CLIENT, description="unary stream call to %s" % method ) as span: span.set_data("type", "unary stream") span.set_data("method", method) diff --git a/sentry_sdk/integrations/grpc/server.py b/sentry_sdk/integrations/grpc/server.py index 8a56cd1709..c97df5fc5d 100644 --- a/sentry_sdk/integrations/grpc/server.py +++ b/sentry_sdk/integrations/grpc/server.py @@ -18,8 +18,8 @@ class ServerInterceptor(grpc.ServerInterceptor): def __init__(self, find_name=None): # type: (ServerInterceptor, Optional[Callable[[ServicerContext], str]]) -> None - if find_name: - self._find_method_name = find_name + self._find_method_name = find_name or ServerInterceptor._find_name + super(ServerInterceptor, self).__init__() def intercept_service(self, continuation, handler_call_details): @@ -35,10 +35,10 @@ def behavior(request, context): name = self._find_method_name(context) if name: - meta_data = dict(context.invocation_metadata()) + metadata = dict(context.invocation_metadata()) transaction = Transaction.continue_from_headers( - meta_data, + metadata, op=OP.GRPC_SERVER, name=name, source=TRANSACTION_SOURCE_CUSTOM, diff --git a/sentry_sdk/integrations/socket.py b/sentry_sdk/integrations/socket.py index 68df79b723..3c69c58dad 100644 --- a/sentry_sdk/integrations/socket.py +++ b/sentry_sdk/integrations/socket.py @@ -30,7 +30,7 @@ def _patch_create_connection(): real_create_connection = socket.create_connection def create_connection( - address, timeout=socket._GLOBAL_DEFAULT_TIMEOUT, source_address=None + address, timeout=socket._GLOBAL_DEFAULT_TIMEOUT, source_address=None ): # type: (Tuple[Optional[str], int], Optional[float], Optional[Tuple[Union[bytearray, bytes, str], int]])-> socket.socket hub = Hub.current @@ -40,7 +40,7 @@ def create_connection( ) with hub.start_span( - op=OP.SOCKET_CONNECTION, description="%s:%s" % (address[0], address[1]) + op=OP.SOCKET_CONNECTION, description="%s:%s" % (address[0], address[1]) ) as span: span.set_data("address", address) span.set_data("timeout", timeout) @@ -64,7 +64,7 @@ def getaddrinfo(host, port, family=0, type=0, proto=0, flags=0): return real_getaddrinfo(host, port, family, type, proto, flags) with hub.start_span( - op=OP.SOCKET_DNS, description="%s:%s" % (host, port) + op=OP.SOCKET_DNS, description="%s:%s" % (host, port) ) as span: span.set_data("host", host) span.set_data("port", port) From 288aaf6c58c95ba9f0e632530ce065478646b3a3 Mon Sep 17 00:00:00 2001 From: Anton Pirker Date: Tue, 28 Mar 2023 17:13:23 +0200 Subject: [PATCH 10/34] Updated test setup --- .github/workflows/test-integration-grpcio.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-integration-grpcio.yml b/.github/workflows/test-integration-grpcio.yml index 03743bec25..a010b4d3cd 100644 --- a/.github/workflows/test-integration-grpcio.yml +++ b/.github/workflows/test-integration-grpcio.yml @@ -55,7 +55,7 @@ jobs: set -x # print commands that are executed coverage erase - ./scripts/runtox.sh "${{ matrix.python-version }}-grpcio" --cov=tests --cov=sentry_sdk --cov-report= --cov-branch + ./scripts/runtox.sh "py${{ matrix.python-version }}-grpcio" --cov=tests --cov=sentry_sdk --cov-report= --cov-branch coverage combine .coverage* coverage xml -i codecov --file coverage.xml From 6f5386081c4644b5dce2fccdb0e8a5c744a224cd Mon Sep 17 00:00:00 2001 From: Anton Pirker Date: Wed, 29 Mar 2023 11:11:22 +0200 Subject: [PATCH 11/34] Fixed typoing --- sentry_sdk/integrations/grpc/client.py | 13 ++++++++----- sentry_sdk/integrations/grpc/server.py | 4 ++-- sentry_sdk/integrations/socket.py | 7 ++++--- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/sentry_sdk/integrations/grpc/client.py b/sentry_sdk/integrations/grpc/client.py index ba675b4722..1eb3621b0b 100644 --- a/sentry_sdk/integrations/grpc/client.py +++ b/sentry_sdk/integrations/grpc/client.py @@ -4,19 +4,20 @@ from sentry_sdk.integrations import DidNotEnable if MYPY: - from typing import Callable, Iterator, Union + from typing import Any, Callable, Iterator, Iterable, Union try: import grpc from grpc import ClientCallDetails, Call from grpc._interceptor import _UnaryOutcome - from google.protobuf.message import Message + from grpc.aio._interceptor import UnaryStreamCall + from google.protobuf.message import Message # type: ignore except ImportError: raise DidNotEnable("grpcio is not installed") class ClientInterceptor( - grpc.UnaryUnaryClientInterceptor, grpc.UnaryStreamClientInterceptor + grpc.UnaryUnaryClientInterceptor, grpc.UnaryStreamClientInterceptor # type: ignore ): def intercept_unary_unary(self, continuation, client_call_details, request): # type: (ClientInterceptor, Callable[[ClientCallDetails, Message], _UnaryOutcome], ClientCallDetails, Message) -> _UnaryOutcome @@ -39,7 +40,7 @@ def intercept_unary_unary(self, continuation, client_call_details, request): return response def intercept_unary_stream(self, continuation, client_call_details, request): - # type: (ClientInterceptor, Callable[[ClientCallDetails, Message], Iterator], ClientCallDetails, Message) -> Union[Iterator[Message], Call] + # type: (ClientInterceptor, Callable[[ClientCallDetails, Message], Union[Iterable[Any], UnaryStreamCall]], ClientCallDetails, Message) -> Union[Iterator[Message], Call] hub = Hub.current method = client_call_details.method @@ -53,7 +54,9 @@ def intercept_unary_stream(self, continuation, client_call_details, request): client_call_details, hub ) - response = continuation(client_call_details, request) + response = continuation( + client_call_details, request + ) # type: UnaryStreamCall span.set_data("code", response.code().name) return response diff --git a/sentry_sdk/integrations/grpc/server.py b/sentry_sdk/integrations/grpc/server.py index c97df5fc5d..cdeea4a2fa 100644 --- a/sentry_sdk/integrations/grpc/server.py +++ b/sentry_sdk/integrations/grpc/server.py @@ -6,7 +6,7 @@ if MYPY: from typing import Callable, Optional - from google.protobuf.message import Message + from google.protobuf.message import Message # type: ignore try: import grpc @@ -15,7 +15,7 @@ raise DidNotEnable("grpcio is not installed") -class ServerInterceptor(grpc.ServerInterceptor): +class ServerInterceptor(grpc.ServerInterceptor): # type: ignore def __init__(self, find_name=None): # type: (ServerInterceptor, Optional[Callable[[ServicerContext], str]]) -> None self._find_method_name = find_name or ServerInterceptor._find_name diff --git a/sentry_sdk/integrations/socket.py b/sentry_sdk/integrations/socket.py index 3c69c58dad..f70d13f6a3 100644 --- a/sentry_sdk/integrations/socket.py +++ b/sentry_sdk/integrations/socket.py @@ -1,5 +1,4 @@ import socket - from sentry_sdk import Hub from sentry_sdk._types import MYPY from sentry_sdk.consts import OP @@ -30,7 +29,9 @@ def _patch_create_connection(): real_create_connection = socket.create_connection def create_connection( - address, timeout=socket._GLOBAL_DEFAULT_TIMEOUT, source_address=None + address, + timeout=socket._GLOBAL_DEFAULT_TIMEOUT, # type: ignore + source_address=None, ): # type: (Tuple[Optional[str], int], Optional[float], Optional[Tuple[Union[bytearray, bytes, str], int]])-> socket.socket hub = Hub.current @@ -64,7 +65,7 @@ def getaddrinfo(host, port, family=0, type=0, proto=0, flags=0): return real_getaddrinfo(host, port, family, type, proto, flags) with hub.start_span( - op=OP.SOCKET_DNS, description="%s:%s" % (host, port) + op=OP.SOCKET_DNS, description="%r:%r" % (host, port) ) as span: span.set_data("host", host) span.set_data("port", port) From 64d13cf74fd9fa29e123e56f101627fad511d4f4 Mon Sep 17 00:00:00 2001 From: Anton Pirker Date: Wed, 29 Mar 2023 11:38:45 +0200 Subject: [PATCH 12/34] Fixed some tests --- sentry_sdk/integrations/socket.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sentry_sdk/integrations/socket.py b/sentry_sdk/integrations/socket.py index f70d13f6a3..4338220668 100644 --- a/sentry_sdk/integrations/socket.py +++ b/sentry_sdk/integrations/socket.py @@ -41,7 +41,7 @@ def create_connection( ) with hub.start_span( - op=OP.SOCKET_CONNECTION, description="%s:%s" % (address[0], address[1]) + op=OP.SOCKET_CONNECTION, description="%s:%s" % address, ) as span: span.set_data("address", address) span.set_data("timeout", timeout) @@ -65,7 +65,7 @@ def getaddrinfo(host, port, family=0, type=0, proto=0, flags=0): return real_getaddrinfo(host, port, family, type, proto, flags) with hub.start_span( - op=OP.SOCKET_DNS, description="%r:%r" % (host, port) + op=OP.SOCKET_DNS, description="%s:%s" % (host, port) ) as span: span.set_data("host", host) span.set_data("port", port) From 4d112f569913d4b314e6a5f0d1d1b3c41c8f02a0 Mon Sep 17 00:00:00 2001 From: Anton Pirker Date: Wed, 29 Mar 2023 11:39:16 +0200 Subject: [PATCH 13/34] The old way is better --- sentry_sdk/integrations/socket.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sentry_sdk/integrations/socket.py b/sentry_sdk/integrations/socket.py index 4338220668..7c4ea8c961 100644 --- a/sentry_sdk/integrations/socket.py +++ b/sentry_sdk/integrations/socket.py @@ -41,7 +41,7 @@ def create_connection( ) with hub.start_span( - op=OP.SOCKET_CONNECTION, description="%s:%s" % address, + op=OP.SOCKET_CONNECTION, description="%s:%s" % (address[0], address[1]), ) as span: span.set_data("address", address) span.set_data("timeout", timeout) From f94a6f137c3556db3436a5e781fd1dd47c3ccf2f Mon Sep 17 00:00:00 2001 From: Anton Pirker Date: Wed, 29 Mar 2023 11:41:30 +0200 Subject: [PATCH 14/34] formatting --- sentry_sdk/integrations/socket.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sentry_sdk/integrations/socket.py b/sentry_sdk/integrations/socket.py index 7c4ea8c961..d02d8e86d8 100644 --- a/sentry_sdk/integrations/socket.py +++ b/sentry_sdk/integrations/socket.py @@ -41,7 +41,8 @@ def create_connection( ) with hub.start_span( - op=OP.SOCKET_CONNECTION, description="%s:%s" % (address[0], address[1]), + op=OP.SOCKET_CONNECTION, + description="%s:%s" % (address[0], address[1]), ) as span: span.set_data("address", address) span.set_data("timeout", timeout) From ed2a66efefbdfa995c0d16f1a2436319cd6684c2 Mon Sep 17 00:00:00 2001 From: Anton Pirker Date: Wed, 29 Mar 2023 11:51:22 +0200 Subject: [PATCH 15/34] Fixed some tests --- sentry_sdk/integrations/socket.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/sentry_sdk/integrations/socket.py b/sentry_sdk/integrations/socket.py index d02d8e86d8..8bec8b0496 100644 --- a/sentry_sdk/integrations/socket.py +++ b/sentry_sdk/integrations/socket.py @@ -24,6 +24,17 @@ def setup_once(): _patch_getaddrinfo() +def _get_span_description(host, port): + # type: (Union[bytes, str, None], Union[str, int, None]) -> str + + try: + host = host.decode() + except (UnicodeDecodeError, AttributeError): + pass + + return "%s:%s" % (host, port) + + def _patch_create_connection(): # type: () -> None real_create_connection = socket.create_connection @@ -42,7 +53,7 @@ def create_connection( with hub.start_span( op=OP.SOCKET_CONNECTION, - description="%s:%s" % (address[0], address[1]), + description=_get_span_description(address[0], address[1]), ) as span: span.set_data("address", address) span.set_data("timeout", timeout) @@ -66,7 +77,7 @@ def getaddrinfo(host, port, family=0, type=0, proto=0, flags=0): return real_getaddrinfo(host, port, family, type, proto, flags) with hub.start_span( - op=OP.SOCKET_DNS, description="%s:%s" % (host, port) + op=OP.SOCKET_DNS, description=_get_span_description(host, port) ) as span: span.set_data("host", host) span.set_data("port", port) From 82d06d8868e2de569b480d166a90b30a5bf3bfdc Mon Sep 17 00:00:00 2001 From: Anton Pirker Date: Wed, 29 Mar 2023 11:57:39 +0200 Subject: [PATCH 16/34] Fixed some tests --- sentry_sdk/integrations/socket.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sentry_sdk/integrations/socket.py b/sentry_sdk/integrations/socket.py index 8bec8b0496..086c5081c3 100644 --- a/sentry_sdk/integrations/socket.py +++ b/sentry_sdk/integrations/socket.py @@ -28,11 +28,16 @@ def _get_span_description(host, port): # type: (Union[bytes, str, None], Union[str, int, None]) -> str try: - host = host.decode() + host = host.decode() # type: ignore except (UnicodeDecodeError, AttributeError): pass - return "%s:%s" % (host, port) + description = "%s:%s" % ( + host, # type: str + port, + ) + + return description def _patch_create_connection(): From c31339dc94ca2d16bf3283f235945867e2aedfed Mon Sep 17 00:00:00 2001 From: Anton Pirker Date: Wed, 29 Mar 2023 12:12:26 +0200 Subject: [PATCH 17/34] Some polishing --- .github/workflows/test-integration-grpcio.yml | 73 ------------------- tests/integrations/grpc/test_grpc.py | 3 + tox.ini | 6 +- 3 files changed, 6 insertions(+), 76 deletions(-) delete mode 100644 .github/workflows/test-integration-grpcio.yml diff --git a/.github/workflows/test-integration-grpcio.yml b/.github/workflows/test-integration-grpcio.yml deleted file mode 100644 index a010b4d3cd..0000000000 --- a/.github/workflows/test-integration-grpcio.yml +++ /dev/null @@ -1,73 +0,0 @@ -name: Test grpcio - -on: - push: - branches: - - master - - release/** - - pull_request: - -# Cancel in progress workflows on pull_requests. -# https://docs.github.com/en/actions/using-jobs/using-concurrency#example-using-a-fallback-value -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} - cancel-in-progress: true - -permissions: - contents: read - -env: - BUILD_CACHE_KEY: ${{ github.sha }} - CACHED_BUILD_PATHS: | - ${{ github.workspace }}/dist-serverless - -jobs: - test: - name: grpcio, python ${{ matrix.python-version }}, ${{ matrix.os }} - runs-on: ${{ matrix.os }} - timeout-minutes: 45 - - strategy: - fail-fast: false - matrix: - python-version: ["3.7","3.8","3.9","3.10","3.11","3.6","3.5"] - # python3.6 reached EOL and is no longer being supported on - # new versions of hosted runners on Github Actions - # ubuntu-20.04 is the last version that supported python3.6 - # see https://github.com/actions/setup-python/issues/544#issuecomment-1332535877 - os: [ubuntu-20.04] - - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-python@v4 - with: - python-version: ${{ matrix.python-version }} - - - name: Setup Test Env - run: | - pip install codecov "tox>=3,<4" - - - name: Test grpcio - timeout-minutes: 45 - shell: bash - run: | - set -x # print commands that are executed - coverage erase - - ./scripts/runtox.sh "py${{ matrix.python-version }}-grpcio" --cov=tests --cov=sentry_sdk --cov-report= --cov-branch - coverage combine .coverage* - coverage xml -i - codecov --file coverage.xml - - check_required_tests: - name: All grpcio tests passed or skipped - needs: test - # Always run this, even if a dependent job failed - if: always() - runs-on: ubuntu-20.04 - steps: - - name: Check for failures - if: contains(needs.test.result, 'failure') - run: | - echo "One of the dependent jobs have failed. You may need to re-run it." && exit 1 diff --git a/tests/integrations/grpc/test_grpc.py b/tests/integrations/grpc/test_grpc.py index 45cc6507b2..bf88dce6c3 100644 --- a/tests/integrations/grpc/test_grpc.py +++ b/tests/integrations/grpc/test_grpc.py @@ -1,5 +1,7 @@ from __future__ import absolute_import +import os + from concurrent import futures import grpc @@ -17,6 +19,7 @@ ) PORT = 50051 +PORT += os.getpid() % 100 # avoid port conflicts when running tests in parallel @pytest.mark.forked diff --git a/tox.ini b/tox.ini index 41577441fc..5b67b6387c 100644 --- a/tox.ini +++ b/tox.ini @@ -152,9 +152,9 @@ envlist = {py3.6,py3.7,py3.8,py3.9,py3.10,py3.11}-trytond-v{5.4} # Grpc - {py3.7,py3.8,py3.9,py3.10,py3.11}-grpcio-v{1.51.1} - {py3.6,py3.7,py3.8,py3.9,py3.10,py3.11}-grpcio-v{1.41.1,1.43.0,1.44.0,1.46.1,1.48.1} - {py3.5,py3.6,py3.7,py3.8,py3.9,py3.10,py3.11}-grpcio-v{1.21.1,1.22.1,1.23.1,1.24.1,1.25.0,1.26.0,1.27.1,1.28.1,1.29.0,1.30.0,1.31.0,1.32.0,1.33.1,1.34.0,1.36.0,1.37.0,1.38.0,1.39.0,1.40.0} + {py3.7,py3.8,py3.9,py3.10,py3.11}-grpc-v{1.51.1} + {py3.6,py3.7,py3.8,py3.9,py3.10,py3.11}-grpc-v{1.41.1,1.43.0,1.44.0,1.46.1,1.48.1} + {py3.5,py3.6,py3.7,py3.8,py3.9,py3.10,py3.11}-grpc-v{1.21.1,1.22.1,1.23.1,1.24.1,1.25.0,1.26.0,1.27.1,1.28.1,1.29.0,1.30.0,1.31.0,1.32.0,1.33.1,1.34.0,1.36.0,1.37.0,1.38.0,1.39.0,1.40.0} [testenv] deps = From ec855c1c34b78ca7d842122da8d85bff018dc6e1 Mon Sep 17 00:00:00 2001 From: Anton Pirker Date: Wed, 29 Mar 2023 12:14:33 +0200 Subject: [PATCH 18/34] Added missing file --- .github/workflows/test-integration-grpc.yml | 73 +++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 .github/workflows/test-integration-grpc.yml diff --git a/.github/workflows/test-integration-grpc.yml b/.github/workflows/test-integration-grpc.yml new file mode 100644 index 0000000000..7f217c2331 --- /dev/null +++ b/.github/workflows/test-integration-grpc.yml @@ -0,0 +1,73 @@ +name: Test grpc + +on: + push: + branches: + - master + - release/** + + pull_request: + +# Cancel in progress workflows on pull_requests. +# https://docs.github.com/en/actions/using-jobs/using-concurrency#example-using-a-fallback-value +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +permissions: + contents: read + +env: + BUILD_CACHE_KEY: ${{ github.sha }} + CACHED_BUILD_PATHS: | + ${{ github.workspace }}/dist-serverless + +jobs: + test: + name: grpc, python ${{ matrix.python-version }}, ${{ matrix.os }} + runs-on: ${{ matrix.os }} + timeout-minutes: 45 + + strategy: + fail-fast: false + matrix: + python-version: ["3.7","3.8","3.9","3.10","3.11","3.6","3.5"] + # python3.6 reached EOL and is no longer being supported on + # new versions of hosted runners on Github Actions + # ubuntu-20.04 is the last version that supported python3.6 + # see https://github.com/actions/setup-python/issues/544#issuecomment-1332535877 + os: [ubuntu-20.04] + + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + + - name: Setup Test Env + run: | + pip install codecov "tox>=3,<4" + + - name: Test grpc + timeout-minutes: 45 + shell: bash + run: | + set -x # print commands that are executed + coverage erase + + ./scripts/runtox.sh "py${{ matrix.python-version }}-grpc" --cov=tests --cov=sentry_sdk --cov-report= --cov-branch + coverage combine .coverage* + coverage xml -i + codecov --file coverage.xml + + check_required_tests: + name: All grpc tests passed or skipped + needs: test + # Always run this, even if a dependent job failed + if: always() + runs-on: ubuntu-20.04 + steps: + - name: Check for failures + if: contains(needs.test.result, 'failure') + run: | + echo "One of the dependent jobs have failed. You may need to re-run it." && exit 1 From f2bfa086b772ef8a48d88b0a9ea3abe6fc4c0a3e Mon Sep 17 00:00:00 2001 From: Anton Pirker Date: Wed, 29 Mar 2023 12:21:14 +0200 Subject: [PATCH 19/34] Fixed linting again --- sentry_sdk/integrations/socket.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/sentry_sdk/integrations/socket.py b/sentry_sdk/integrations/socket.py index 086c5081c3..ebb51354b1 100644 --- a/sentry_sdk/integrations/socket.py +++ b/sentry_sdk/integrations/socket.py @@ -32,10 +32,7 @@ def _get_span_description(host, port): except (UnicodeDecodeError, AttributeError): pass - description = "%s:%s" % ( - host, # type: str - port, - ) + description = "%s:%s" % (host, port) # type: ignore return description From 8bea90b3743bb7e8e46f00b91ec3035c3b3a916c Mon Sep 17 00:00:00 2001 From: Anton Pirker Date: Wed, 29 Mar 2023 12:32:44 +0200 Subject: [PATCH 20/34] Moved test requirements into tox.ini --- test-requirements.txt | 4 ---- tox.ini | 16 +++++++++++----- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/test-requirements.txt b/test-requirements.txt index 94fd5b8463..5d449df716 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -13,7 +13,3 @@ executing asttokens responses ipdb -grpcio-tools -protobuf -mypy-protobuf -types-protobuf diff --git a/tox.ini b/tox.ini index 5b67b6387c..04fcf2fde2 100644 --- a/tox.ini +++ b/tox.ini @@ -87,6 +87,11 @@ envlist = # GCP {py3.7}-gcp + # Grpc + {py3.7,py3.8,py3.9,py3.10,py3.11}-grpc-v{1.51.1} + {py3.6,py3.7,py3.8,py3.9,py3.10,py3.11}-grpc-v{1.41.1,1.43.0,1.44.0,1.46.1,1.48.1} + {py3.5,py3.6,py3.7,py3.8,py3.9,py3.10,py3.11}-grpc-v{1.21.1,1.22.1,1.23.1,1.24.1,1.25.0,1.26.0,1.27.1,1.28.1,1.29.0,1.30.0,1.31.0,1.32.0,1.33.1,1.34.0,1.36.0,1.37.0,1.38.0,1.39.0,1.40.0} + # HTTPX {py3.6,py3.7,py3.8,py3.9}-httpx-v{0.16,0.17,0.18} {py3.6,py3.7,py3.8,py3.9,py3.10}-httpx-v{0.19,0.20,0.21,0.22} @@ -151,11 +156,6 @@ envlist = {py3.5,py3.6,py3.7,py3.8,py3.9}-trytond-v{4.6,5.0,5.2} {py3.6,py3.7,py3.8,py3.9,py3.10,py3.11}-trytond-v{5.4} - # Grpc - {py3.7,py3.8,py3.9,py3.10,py3.11}-grpc-v{1.51.1} - {py3.6,py3.7,py3.8,py3.9,py3.10,py3.11}-grpc-v{1.41.1,1.43.0,1.44.0,1.46.1,1.48.1} - {py3.5,py3.6,py3.7,py3.8,py3.9,py3.10,py3.11}-grpc-v{1.21.1,1.22.1,1.23.1,1.24.1,1.25.0,1.26.0,1.27.1,1.28.1,1.29.0,1.30.0,1.31.0,1.32.0,1.33.1,1.34.0,1.36.0,1.37.0,1.38.0,1.39.0,1.40.0} - [testenv] deps = # if you change test-requirements.txt and your change is not being reflected @@ -296,6 +296,12 @@ deps = py3.5-gevent: greenlet==0.4.17 {py2.7,py3.6,py3.7,py3.8,py3.9,py3.10,py3.11}-gevent: gevent>=22.10.0, <22.11.0 + # Grpc + grpc: grpcio-tools + grpc: protobuf + grpc: mypy-protobuf + grpc: types-protobuf + # HTTPX httpx: pytest-httpx httpx-v0.16: httpx>=0.16,<0.17 From 5eed85250c8743c4624003149c54ade93d3fe353 Mon Sep 17 00:00:00 2001 From: Anton Pirker Date: Wed, 29 Mar 2023 12:45:42 +0200 Subject: [PATCH 21/34] Test Grpc only in Python 3.7+ --- tox.ini | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tox.ini b/tox.ini index 04fcf2fde2..24d1cd3b40 100644 --- a/tox.ini +++ b/tox.ini @@ -88,9 +88,7 @@ envlist = {py3.7}-gcp # Grpc - {py3.7,py3.8,py3.9,py3.10,py3.11}-grpc-v{1.51.1} - {py3.6,py3.7,py3.8,py3.9,py3.10,py3.11}-grpc-v{1.41.1,1.43.0,1.44.0,1.46.1,1.48.1} - {py3.5,py3.6,py3.7,py3.8,py3.9,py3.10,py3.11}-grpc-v{1.21.1,1.22.1,1.23.1,1.24.1,1.25.0,1.26.0,1.27.1,1.28.1,1.29.0,1.30.0,1.31.0,1.32.0,1.33.1,1.34.0,1.36.0,1.37.0,1.38.0,1.39.0,1.40.0} + {py3.7,py3.8,py3.9,py3.10,py3.11}-grpc-v{1.21.1,1.22.1,1.23.1,1.24.1,1.25.0,1.26.0,1.27.1,1.28.1,1.29.0,1.30.0,1.31.0,1.32.0,1.33.1,1.34.0,1.36.0,1.37.0,1.38.0,1.39.0,1.40.0,1.41.1,1.43.0,1.44.0,1.46.1,1.48.1,1.51.3,1.53.0} # HTTPX {py3.6,py3.7,py3.8,py3.9}-httpx-v{0.16,0.17,0.18} From 939b184596a251c36abaf5e179ef417a03de0e3d Mon Sep 17 00:00:00 2001 From: Anton Pirker Date: Wed, 29 Mar 2023 12:48:05 +0200 Subject: [PATCH 22/34] Updated test setup --- .github/workflows/test-integration-grpc.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-integration-grpc.yml b/.github/workflows/test-integration-grpc.yml index 7f217c2331..15cfcca552 100644 --- a/.github/workflows/test-integration-grpc.yml +++ b/.github/workflows/test-integration-grpc.yml @@ -31,7 +31,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.7","3.8","3.9","3.10","3.11","3.6","3.5"] + python-version: ["3.7","3.8","3.9","3.10","3.11"] # python3.6 reached EOL and is no longer being supported on # new versions of hosted runners on Github Actions # ubuntu-20.04 is the last version that supported python3.6 From e1bef2696c50ba56cb0547df3aa24d1a619a5069 Mon Sep 17 00:00:00 2001 From: Anton Pirker Date: Wed, 29 Mar 2023 13:00:33 +0200 Subject: [PATCH 23/34] Trigger ci (because of codecov) From d81fe6c3cb5450d3a9851933755d61a3b19d13c6 Mon Sep 17 00:00:00 2001 From: hossein raeisi Date: Wed, 29 Mar 2023 20:13:29 +0330 Subject: [PATCH 24/34] refactor(tracing) Rename grpc's test proto content --- .../integrations/grpc/grpc_test_service.proto | 11 +++ .../grpc/grpc_test_service_pb2.py | 27 +++++++ ...vice_pb2.pyi => grpc_test_service_pb2.pyi} | 8 +- .../grpc/grpc_test_service_pb2_grpc.py | 66 ++++++++++++++++ tests/integrations/grpc/test_grpc.py | 36 ++++----- tests/integrations/grpc/test_service.proto | 11 --- tests/integrations/grpc/test_service_pb2.py | 28 ------- .../grpc/test_service_pb2_grpc.py | 79 ------------------- 8 files changed, 125 insertions(+), 141 deletions(-) create mode 100644 tests/integrations/grpc/grpc_test_service.proto create mode 100644 tests/integrations/grpc/grpc_test_service_pb2.py rename tests/integrations/grpc/{test_service_pb2.pyi => grpc_test_service_pb2.pyi} (74%) create mode 100644 tests/integrations/grpc/grpc_test_service_pb2_grpc.py delete mode 100644 tests/integrations/grpc/test_service.proto delete mode 100644 tests/integrations/grpc/test_service_pb2.py delete mode 100644 tests/integrations/grpc/test_service_pb2_grpc.py diff --git a/tests/integrations/grpc/grpc_test_service.proto b/tests/integrations/grpc/grpc_test_service.proto new file mode 100644 index 0000000000..43497c7129 --- /dev/null +++ b/tests/integrations/grpc/grpc_test_service.proto @@ -0,0 +1,11 @@ +syntax = "proto3"; + +package grpc_test_server; + +service gRPCTestService{ + rpc TestServe(gRPCTestMessage) returns (gRPCTestMessage); +} + +message gRPCTestMessage { + string text = 1; +} diff --git a/tests/integrations/grpc/grpc_test_service_pb2.py b/tests/integrations/grpc/grpc_test_service_pb2.py new file mode 100644 index 0000000000..4290ae603d --- /dev/null +++ b/tests/integrations/grpc/grpc_test_service_pb2.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: grpc_test_service.proto +"""Generated protocol buffer code.""" +from google.protobuf.internal import builder as _builder +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import symbol_database as _symbol_database +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x17grpc_test_service.proto\x12\x10grpc_test_server\"\x1f\n\x0fgRPCTestMessage\x12\x0c\n\x04text\x18\x01 \x01(\t2d\n\x0fgRPCTestService\x12Q\n\tTestServe\x12!.grpc_test_server.gRPCTestMessage\x1a!.grpc_test_server.gRPCTestMessageb\x06proto3') + +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'grpc_test_service_pb2', globals()) +if _descriptor._USE_C_DESCRIPTORS == False: + + DESCRIPTOR._options = None + _GRPCTESTMESSAGE._serialized_start=45 + _GRPCTESTMESSAGE._serialized_end=76 + _GRPCTESTSERVICE._serialized_start=78 + _GRPCTESTSERVICE._serialized_end=178 +# @@protoc_insertion_point(module_scope) diff --git a/tests/integrations/grpc/test_service_pb2.pyi b/tests/integrations/grpc/grpc_test_service_pb2.pyi similarity index 74% rename from tests/integrations/grpc/test_service_pb2.pyi rename to tests/integrations/grpc/grpc_test_service_pb2.pyi index d37eefb5de..e5c53dbd4a 100644 --- a/tests/integrations/grpc/test_service_pb2.pyi +++ b/tests/integrations/grpc/grpc_test_service_pb2.pyi @@ -15,7 +15,7 @@ else: DESCRIPTOR: google.protobuf.descriptor.FileDescriptor @typing_extensions.final -class TestMessage(google.protobuf.message.Message): +class gRPCTestMessage(google.protobuf.message.Message): DESCRIPTOR: google.protobuf.descriptor.Descriptor TEXT_FIELD_NUMBER: builtins.int @@ -25,8 +25,6 @@ class TestMessage(google.protobuf.message.Message): *, text: builtins.str = ..., ) -> None: ... - def ClearField( - self, field_name: typing_extensions.Literal["text", b"text"] - ) -> None: ... + def ClearField(self, field_name: typing_extensions.Literal["text", b"text"]) -> None: ... -global___TestMessage = TestMessage +global___gRPCTestMessage = gRPCTestMessage diff --git a/tests/integrations/grpc/grpc_test_service_pb2_grpc.py b/tests/integrations/grpc/grpc_test_service_pb2_grpc.py new file mode 100644 index 0000000000..582835781f --- /dev/null +++ b/tests/integrations/grpc/grpc_test_service_pb2_grpc.py @@ -0,0 +1,66 @@ +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! +"""Client and server classes corresponding to protobuf-defined services.""" +import grpc + +import tests.integrations.grpc.grpc_test_service_pb2 as grpc__test__service__pb2 + + +class gRPCTestServiceStub(object): + """Missing associated documentation comment in .proto file.""" + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.TestServe = channel.unary_unary( + '/grpc_test_server.gRPCTestService/TestServe', + request_serializer=grpc__test__service__pb2.gRPCTestMessage.SerializeToString, + response_deserializer=grpc__test__service__pb2.gRPCTestMessage.FromString, + ) + + +class gRPCTestServiceServicer(object): + """Missing associated documentation comment in .proto file.""" + + def TestServe(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + +def add_gRPCTestServiceServicer_to_server(servicer, server): + rpc_method_handlers = { + 'TestServe': grpc.unary_unary_rpc_method_handler( + servicer.TestServe, + request_deserializer=grpc__test__service__pb2.gRPCTestMessage.FromString, + response_serializer=grpc__test__service__pb2.gRPCTestMessage.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + 'grpc_test_server.gRPCTestService', rpc_method_handlers) + server.add_generic_rpc_handlers((generic_handler,)) + + + # This class is part of an EXPERIMENTAL API. +class gRPCTestService(object): + """Missing associated documentation comment in .proto file.""" + + @staticmethod + def TestServe(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/grpc_test_server.gRPCTestService/TestServe', + grpc__test__service__pb2.gRPCTestMessage.SerializeToString, + grpc__test__service__pb2.gRPCTestMessage.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata) diff --git a/tests/integrations/grpc/test_grpc.py b/tests/integrations/grpc/test_grpc.py index bf88dce6c3..92883e9256 100644 --- a/tests/integrations/grpc/test_grpc.py +++ b/tests/integrations/grpc/test_grpc.py @@ -11,11 +11,11 @@ from sentry_sdk.consts import OP from sentry_sdk.integrations.grpc.client import ClientInterceptor from sentry_sdk.integrations.grpc.server import ServerInterceptor -from tests.integrations.grpc.test_service_pb2 import TestMessage -from tests.integrations.grpc.test_service_pb2_grpc import ( - TestServiceServicer, - add_TestServiceServicer_to_server, - TestServiceStub, +from tests.integrations.grpc.grpc_test_service_pb2 import gRPCTestMessage +from tests.integrations.grpc.grpc_test_service_pb2_grpc import ( + gRPCTestServiceServicer, + add_gRPCTestServiceServicer_to_server, + gRPCTestServiceStub, ) PORT = 50051 @@ -30,8 +30,8 @@ def test_grpc_server_starts_transaction(sentry_init, capture_events_forksafe): server = _set_up() with grpc.insecure_channel(f"localhost:{PORT}") as channel: - stub = TestServiceStub(channel) - stub.TestServe(TestMessage(text="test")) + stub = gRPCTestServiceStub(channel) + stub.TestServe(gRPCTestMessage(text="test")) _tear_down(server=server) @@ -55,7 +55,7 @@ def test_grpc_server_continues_transaction(sentry_init, capture_events_forksafe) server = _set_up() with grpc.insecure_channel(f"localhost:{PORT}") as channel: - stub = TestServiceStub(channel) + stub = gRPCTestServiceStub(channel) with start_transaction() as transaction: metadata = ( @@ -75,7 +75,7 @@ def test_grpc_server_continues_transaction(sentry_init, capture_events_forksafe) ), ), ) - stub.TestServe(TestMessage(text="test"), metadata=metadata) + stub.TestServe(gRPCTestMessage(text="test"), metadata=metadata) _tear_down(server=server) @@ -102,10 +102,10 @@ def test_grpc_client_starts_span(sentry_init, capture_events_forksafe): with grpc.insecure_channel(f"localhost:{PORT}") as channel: channel = grpc.intercept_channel(channel, *interceptors) - stub = TestServiceStub(channel) + stub = gRPCTestServiceStub(channel) with start_transaction(): - stub.TestServe(TestMessage(text="test")) + stub.TestServe(gRPCTestMessage(text="test")) _tear_down(server=server) @@ -118,11 +118,11 @@ def test_grpc_client_starts_span(sentry_init, capture_events_forksafe): assert span["op"] == OP.GRPC_CLIENT assert ( span["description"] - == "unary unary call to /test_grpc_server.TestService/TestServe" + == "unary unary call to /grpc_test_server.gRPCTestService/TestServe" ) assert span["data"] == { "type": "unary unary", - "method": "/test_grpc_server.TestService/TestServe", + "method": "/grpc_test_server.gRPCTestService/TestServe", "code": "OK", } @@ -139,10 +139,10 @@ def test_grpc_client_and_servers_interceptors_integration( with grpc.insecure_channel(f"localhost:{PORT}") as channel: channel = grpc.intercept_channel(channel, *interceptors) - stub = TestServiceStub(channel) + stub = gRPCTestServiceStub(channel) with start_transaction(): - stub.TestServe(TestMessage(text="test")) + stub.TestServe(gRPCTestMessage(text="test")) _tear_down(server=server) @@ -162,7 +162,7 @@ def _set_up(): interceptors=[ServerInterceptor(find_name=_find_name)], ) - add_TestServiceServicer_to_server(TestService, server) + add_gRPCTestServiceServicer_to_server(TestService, server) server.add_insecure_port(f"[::]:{PORT}") server.start() @@ -177,7 +177,7 @@ def _find_name(request): return request.__class__ -class TestService(TestServiceServicer): +class TestService(gRPCTestServiceServicer): events = [] @staticmethod @@ -186,4 +186,4 @@ def TestServe(request, context): # noqa: N802 with hub.start_span(op="test", description="test"): pass - return TestMessage(text=request.text) + return gRPCTestMessage(text=request.text) diff --git a/tests/integrations/grpc/test_service.proto b/tests/integrations/grpc/test_service.proto deleted file mode 100644 index 1818389754..0000000000 --- a/tests/integrations/grpc/test_service.proto +++ /dev/null @@ -1,11 +0,0 @@ -syntax = "proto3"; - -package test_grpc_server; - -service TestService{ - rpc TestServe(TestMessage) returns (TestMessage); -} - -message TestMessage { - string text = 1; -} diff --git a/tests/integrations/grpc/test_service_pb2.py b/tests/integrations/grpc/test_service_pb2.py deleted file mode 100644 index fe29fad34e..0000000000 --- a/tests/integrations/grpc/test_service_pb2.py +++ /dev/null @@ -1,28 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by the protocol buffer compiler. DO NOT EDIT! -# source: test_service.proto -"""Generated protocol buffer code.""" -from google.protobuf.internal import builder as _builder -from google.protobuf import descriptor as _descriptor -from google.protobuf import descriptor_pool as _descriptor_pool -from google.protobuf import symbol_database as _symbol_database - -# @@protoc_insertion_point(imports) - -_sym_db = _symbol_database.Default() - - -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile( - b'\n\x12test_service.proto\x12\x10test_grpc_server"\x1b\n\x0bTestMessage\x12\x0c\n\x04text\x18\x01 \x01(\t2X\n\x0bTestService\x12I\n\tTestServe\x12\x1d.test_grpc_server.TestMessage\x1a\x1d.test_grpc_server.TestMessageb\x06proto3' -) - -_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) -_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "test_service_pb2", globals()) -if _descriptor._USE_C_DESCRIPTORS == False: - - DESCRIPTOR._options = None - _TESTMESSAGE._serialized_start = 40 - _TESTMESSAGE._serialized_end = 67 - _TESTSERVICE._serialized_start = 69 - _TESTSERVICE._serialized_end = 157 -# @@protoc_insertion_point(module_scope) diff --git a/tests/integrations/grpc/test_service_pb2_grpc.py b/tests/integrations/grpc/test_service_pb2_grpc.py deleted file mode 100644 index 52a2e873a7..0000000000 --- a/tests/integrations/grpc/test_service_pb2_grpc.py +++ /dev/null @@ -1,79 +0,0 @@ -# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! -"""Client and server classes corresponding to protobuf-defined services.""" -import grpc - -import tests.integrations.grpc.test_service_pb2 as test__service__pb2 - - -class TestServiceStub(object): - """Missing associated documentation comment in .proto file.""" - - def __init__(self, channel): - """Constructor. - - Args: - channel: A grpc.Channel. - """ - self.TestServe = channel.unary_unary( - "/test_grpc_server.TestService/TestServe", - request_serializer=test__service__pb2.TestMessage.SerializeToString, - response_deserializer=test__service__pb2.TestMessage.FromString, - ) - - -class TestServiceServicer(object): - """Missing associated documentation comment in .proto file.""" - - def TestServe(self, request, context): - """Missing associated documentation comment in .proto file.""" - context.set_code(grpc.StatusCode.UNIMPLEMENTED) - context.set_details("Method not implemented!") - raise NotImplementedError("Method not implemented!") - - -def add_TestServiceServicer_to_server(servicer, server): - rpc_method_handlers = { - "TestServe": grpc.unary_unary_rpc_method_handler( - servicer.TestServe, - request_deserializer=test__service__pb2.TestMessage.FromString, - response_serializer=test__service__pb2.TestMessage.SerializeToString, - ), - } - generic_handler = grpc.method_handlers_generic_handler( - "test_grpc_server.TestService", rpc_method_handlers - ) - server.add_generic_rpc_handlers((generic_handler,)) - - -# This class is part of an EXPERIMENTAL API. -class TestService(object): - """Missing associated documentation comment in .proto file.""" - - @staticmethod - def TestServe( - request, - target, - options=(), - channel_credentials=None, - call_credentials=None, - insecure=False, - compression=None, - wait_for_ready=None, - timeout=None, - metadata=None, - ): - return grpc.experimental.unary_unary( - request, - target, - "/test_grpc_server.TestService/TestServe", - test__service__pb2.TestMessage.SerializeToString, - test__service__pb2.TestMessage.FromString, - options, - channel_credentials, - insecure, - call_credentials, - compression, - wait_for_ready, - timeout, - metadata, - ) From aadf76dfbee4d43790fa5e4cab02d27c8734bfdf Mon Sep 17 00:00:00 2001 From: Anton Pirker Date: Thu, 30 Mar 2023 08:44:07 +0200 Subject: [PATCH 25/34] Fixed linting --- .flake8 | 4 +- scripts/runtox.sh | 2 +- .../grpc/grpc_test_service_pb2.py | 19 +++--- .../grpc/grpc_test_service_pb2.pyi | 4 +- .../grpc/grpc_test_service_pb2_grpc.py | 63 +++++++++++-------- 5 files changed, 54 insertions(+), 38 deletions(-) diff --git a/.flake8 b/.flake8 index 9bf2bed06c..fb02f4fdef 100644 --- a/.flake8 +++ b/.flake8 @@ -17,5 +17,5 @@ extend-ignore = extend-exclude=checkouts,lol* exclude = # gRCP generated files - test_service_pb2.py - test_service_pb2_grpc.py \ No newline at end of file + grpc_test_service_pb2.py + grpc_test_service_pb2_grpc.py \ No newline at end of file diff --git a/scripts/runtox.sh b/scripts/runtox.sh index 07db62242b..e2d61db13d 100755 --- a/scripts/runtox.sh +++ b/scripts/runtox.sh @@ -16,4 +16,4 @@ fi searchstring="$1" export TOX_PARALLEL_NO_SPINNER=1 -exec $TOXPATH -vv -p auto -e "$($TOXPATH -l | grep "$searchstring" | tr $'\n' ',')" -- "${@:2}" +exec $TOXPATH -vv -e "$($TOXPATH -l | grep "$searchstring" | tr $'\n' ',')" -- "${@:2}" diff --git a/tests/integrations/grpc/grpc_test_service_pb2.py b/tests/integrations/grpc/grpc_test_service_pb2.py index 4290ae603d..c68f255b4a 100644 --- a/tests/integrations/grpc/grpc_test_service_pb2.py +++ b/tests/integrations/grpc/grpc_test_service_pb2.py @@ -6,22 +6,23 @@ from google.protobuf import descriptor as _descriptor from google.protobuf import descriptor_pool as _descriptor_pool from google.protobuf import symbol_database as _symbol_database + # @@protoc_insertion_point(imports) _sym_db = _symbol_database.Default() - - -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x17grpc_test_service.proto\x12\x10grpc_test_server\"\x1f\n\x0fgRPCTestMessage\x12\x0c\n\x04text\x18\x01 \x01(\t2d\n\x0fgRPCTestService\x12Q\n\tTestServe\x12!.grpc_test_server.gRPCTestMessage\x1a!.grpc_test_server.gRPCTestMessageb\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile( + b'\n\x17grpc_test_service.proto\x12\x10grpc_test_server"\x1f\n\x0fgRPCTestMessage\x12\x0c\n\x04text\x18\x01 \x01(\t2d\n\x0fgRPCTestService\x12Q\n\tTestServe\x12!.grpc_test_server.gRPCTestMessage\x1a!.grpc_test_server.gRPCTestMessageb\x06proto3' +) _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) -_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'grpc_test_service_pb2', globals()) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "grpc_test_service_pb2", globals()) if _descriptor._USE_C_DESCRIPTORS == False: - DESCRIPTOR._options = None - _GRPCTESTMESSAGE._serialized_start=45 - _GRPCTESTMESSAGE._serialized_end=76 - _GRPCTESTSERVICE._serialized_start=78 - _GRPCTESTSERVICE._serialized_end=178 + DESCRIPTOR._options = None + _GRPCTESTMESSAGE._serialized_start = 45 + _GRPCTESTMESSAGE._serialized_end = 76 + _GRPCTESTSERVICE._serialized_start = 78 + _GRPCTESTSERVICE._serialized_end = 178 # @@protoc_insertion_point(module_scope) diff --git a/tests/integrations/grpc/grpc_test_service_pb2.pyi b/tests/integrations/grpc/grpc_test_service_pb2.pyi index e5c53dbd4a..02a0b7045b 100644 --- a/tests/integrations/grpc/grpc_test_service_pb2.pyi +++ b/tests/integrations/grpc/grpc_test_service_pb2.pyi @@ -25,6 +25,8 @@ class gRPCTestMessage(google.protobuf.message.Message): *, text: builtins.str = ..., ) -> None: ... - def ClearField(self, field_name: typing_extensions.Literal["text", b"text"]) -> None: ... + def ClearField( + self, field_name: typing_extensions.Literal["text", b"text"] + ) -> None: ... global___gRPCTestMessage = gRPCTestMessage diff --git a/tests/integrations/grpc/grpc_test_service_pb2_grpc.py b/tests/integrations/grpc/grpc_test_service_pb2_grpc.py index 582835781f..73b7d94c16 100644 --- a/tests/integrations/grpc/grpc_test_service_pb2_grpc.py +++ b/tests/integrations/grpc/grpc_test_service_pb2_grpc.py @@ -15,10 +15,10 @@ def __init__(self, channel): channel: A grpc.Channel. """ self.TestServe = channel.unary_unary( - '/grpc_test_server.gRPCTestService/TestServe', - request_serializer=grpc__test__service__pb2.gRPCTestMessage.SerializeToString, - response_deserializer=grpc__test__service__pb2.gRPCTestMessage.FromString, - ) + "/grpc_test_server.gRPCTestService/TestServe", + request_serializer=grpc__test__service__pb2.gRPCTestMessage.SerializeToString, + response_deserializer=grpc__test__service__pb2.gRPCTestMessage.FromString, + ) class gRPCTestServiceServicer(object): @@ -27,40 +27,53 @@ class gRPCTestServiceServicer(object): def TestServe(self, request, context): """Missing associated documentation comment in .proto file.""" context.set_code(grpc.StatusCode.UNIMPLEMENTED) - context.set_details('Method not implemented!') - raise NotImplementedError('Method not implemented!') + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!") def add_gRPCTestServiceServicer_to_server(servicer, server): rpc_method_handlers = { - 'TestServe': grpc.unary_unary_rpc_method_handler( - servicer.TestServe, - request_deserializer=grpc__test__service__pb2.gRPCTestMessage.FromString, - response_serializer=grpc__test__service__pb2.gRPCTestMessage.SerializeToString, - ), + "TestServe": grpc.unary_unary_rpc_method_handler( + servicer.TestServe, + request_deserializer=grpc__test__service__pb2.gRPCTestMessage.FromString, + response_serializer=grpc__test__service__pb2.gRPCTestMessage.SerializeToString, + ), } generic_handler = grpc.method_handlers_generic_handler( - 'grpc_test_server.gRPCTestService', rpc_method_handlers) + "grpc_test_server.gRPCTestService", rpc_method_handlers + ) server.add_generic_rpc_handlers((generic_handler,)) - # This class is part of an EXPERIMENTAL API. +# This class is part of an EXPERIMENTAL API. class gRPCTestService(object): """Missing associated documentation comment in .proto file.""" @staticmethod - def TestServe(request, + def TestServe( + request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None, + ): + return grpc.experimental.unary_unary( + request, target, - options=(), - channel_credentials=None, - call_credentials=None, - insecure=False, - compression=None, - wait_for_ready=None, - timeout=None, - metadata=None): - return grpc.experimental.unary_unary(request, target, '/grpc_test_server.gRPCTestService/TestServe', + "/grpc_test_server.gRPCTestService/TestServe", grpc__test__service__pb2.gRPCTestMessage.SerializeToString, grpc__test__service__pb2.gRPCTestMessage.FromString, - options, channel_credentials, - insecure, call_credentials, compression, wait_for_ready, timeout, metadata) + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + ) From 6cefb698dc3473d1cc8277b4fcf9b8f1ee2dfc0e Mon Sep 17 00:00:00 2001 From: Anton Pirker Date: Thu, 30 Mar 2023 09:09:39 +0200 Subject: [PATCH 26/34] Trigger ci (because of codecov) From 7b0af47fa455f0f930e13d8471786562dd275931 Mon Sep 17 00:00:00 2001 From: Anton Pirker Date: Thu, 30 Mar 2023 09:48:31 +0200 Subject: [PATCH 27/34] Renamed integration to fix import clashes in python 2.7 --- sentry_sdk/integrations/{socket.py => socket_.py} | 2 ++ tests/integrations/{socket => socket_}/__init__.py | 0 tests/integrations/{socket => socket_}/test_socket.py | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) rename sentry_sdk/integrations/{socket.py => socket_.py} (98%) rename tests/integrations/{socket => socket_}/__init__.py (100%) rename tests/integrations/{socket => socket_}/test_socket.py (95%) diff --git a/sentry_sdk/integrations/socket.py b/sentry_sdk/integrations/socket_.py similarity index 98% rename from sentry_sdk/integrations/socket.py rename to sentry_sdk/integrations/socket_.py index ebb51354b1..58fb6de86a 100644 --- a/sentry_sdk/integrations/socket.py +++ b/sentry_sdk/integrations/socket_.py @@ -39,6 +39,8 @@ def _get_span_description(host, port): def _patch_create_connection(): # type: () -> None + import ipdb + ipdb.set_trace() real_create_connection = socket.create_connection def create_connection( diff --git a/tests/integrations/socket/__init__.py b/tests/integrations/socket_/__init__.py similarity index 100% rename from tests/integrations/socket/__init__.py rename to tests/integrations/socket_/__init__.py diff --git a/tests/integrations/socket/test_socket.py b/tests/integrations/socket_/test_socket.py similarity index 95% rename from tests/integrations/socket/test_socket.py rename to tests/integrations/socket_/test_socket.py index 914ba0bf84..dd7b7b50a1 100644 --- a/tests/integrations/socket/test_socket.py +++ b/tests/integrations/socket_/test_socket.py @@ -1,7 +1,7 @@ import socket from sentry_sdk import start_transaction -from sentry_sdk.integrations.socket import SocketIntegration +from sentry_sdk.integrations.socket_ import SocketIntegration def test_getaddrinfo_trace(sentry_init, capture_events): From 4cff7d92f48563f8c127fc9d9b91e43859ab9ab2 Mon Sep 17 00:00:00 2001 From: Anton Pirker Date: Thu, 30 Mar 2023 09:51:46 +0200 Subject: [PATCH 28/34] shame on me --- sentry_sdk/integrations/socket_.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/sentry_sdk/integrations/socket_.py b/sentry_sdk/integrations/socket_.py index 58fb6de86a..ebb51354b1 100644 --- a/sentry_sdk/integrations/socket_.py +++ b/sentry_sdk/integrations/socket_.py @@ -39,8 +39,6 @@ def _get_span_description(host, port): def _patch_create_connection(): # type: () -> None - import ipdb - ipdb.set_trace() real_create_connection = socket.create_connection def create_connection( From 5a176191bf4890794e165061a7ca5e42ed444cf6 Mon Sep 17 00:00:00 2001 From: Anton Pirker Date: Thu, 30 Mar 2023 11:18:28 +0200 Subject: [PATCH 29/34] Fixed unicode problem --- tests/utils/test_general.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/utils/test_general.py b/tests/utils/test_general.py index 570182ab0e..0a61f59318 100644 --- a/tests/utils/test_general.py +++ b/tests/utils/test_general.py @@ -587,5 +587,5 @@ def test_strip_string(): assert stripped_text.value.count("a") == 1021 # + '...' is 1024 # If text has unicode characters, it counts bytes and not number of characters. - text_with_unicode_character = "éê" - assert strip_string(text_with_unicode_character, max_length=2).value == "é..." + text_with_unicode_character = u"éê" + assert strip_string(text_with_unicode_character, max_length=2).value == u"é..." From e181206336c26e434ffe46407aff65f28cce7719 Mon Sep 17 00:00:00 2001 From: Anton Pirker Date: Thu, 30 Mar 2023 11:22:38 +0200 Subject: [PATCH 30/34] Prevent linter from breaking tests --- tests/utils/test_general.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/utils/test_general.py b/tests/utils/test_general.py index 0a61f59318..ea6beb2d62 100644 --- a/tests/utils/test_general.py +++ b/tests/utils/test_general.py @@ -571,7 +571,7 @@ def test_failed_base64_conversion(input): if type(input) not in string_types: assert to_base64(input) is None - +# fmt: off def test_strip_string(): # If value is None returns None. assert strip_string(None) is None @@ -589,3 +589,4 @@ def test_strip_string(): # If text has unicode characters, it counts bytes and not number of characters. text_with_unicode_character = u"éê" assert strip_string(text_with_unicode_character, max_length=2).value == u"é..." +# fmt: on \ No newline at end of file From fb5e0019206b7e910b04e7bc64a1e99df9c4be0f Mon Sep 17 00:00:00 2001 From: Anton Pirker Date: Thu, 30 Mar 2023 11:25:48 +0200 Subject: [PATCH 31/34] . --- tests/utils/test_general.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/utils/test_general.py b/tests/utils/test_general.py index ea6beb2d62..a475930dda 100644 --- a/tests/utils/test_general.py +++ b/tests/utils/test_general.py @@ -571,6 +571,7 @@ def test_failed_base64_conversion(input): if type(input) not in string_types: assert to_base64(input) is None + # fmt: off def test_strip_string(): # If value is None returns None. @@ -589,4 +590,4 @@ def test_strip_string(): # If text has unicode characters, it counts bytes and not number of characters. text_with_unicode_character = u"éê" assert strip_string(text_with_unicode_character, max_length=2).value == u"é..." -# fmt: on \ No newline at end of file +# fmt: on From 6e19ecc2f144232c8db5ac9ac8d45886d318706f Mon Sep 17 00:00:00 2001 From: Anton Pirker Date: Thu, 30 Mar 2023 11:59:38 +0200 Subject: [PATCH 32/34] Reverted accidental change --- scripts/runtox.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/runtox.sh b/scripts/runtox.sh index e2d61db13d..07db62242b 100755 --- a/scripts/runtox.sh +++ b/scripts/runtox.sh @@ -16,4 +16,4 @@ fi searchstring="$1" export TOX_PARALLEL_NO_SPINNER=1 -exec $TOXPATH -vv -e "$($TOXPATH -l | grep "$searchstring" | tr $'\n' ',')" -- "${@:2}" +exec $TOXPATH -vv -p auto -e "$($TOXPATH -l | grep "$searchstring" | tr $'\n' ',')" -- "${@:2}" From 815b7efdb680e888374e9c40c48705dadfa8941f Mon Sep 17 00:00:00 2001 From: Anton Pirker Date: Thu, 30 Mar 2023 12:09:07 +0200 Subject: [PATCH 33/34] This can not be the solution, something else is wrong. --- tests/utils/test_general.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/utils/test_general.py b/tests/utils/test_general.py index a475930dda..570182ab0e 100644 --- a/tests/utils/test_general.py +++ b/tests/utils/test_general.py @@ -572,7 +572,6 @@ def test_failed_base64_conversion(input): assert to_base64(input) is None -# fmt: off def test_strip_string(): # If value is None returns None. assert strip_string(None) is None @@ -588,6 +587,5 @@ def test_strip_string(): assert stripped_text.value.count("a") == 1021 # + '...' is 1024 # If text has unicode characters, it counts bytes and not number of characters. - text_with_unicode_character = u"éê" - assert strip_string(text_with_unicode_character, max_length=2).value == u"é..." -# fmt: on + text_with_unicode_character = "éê" + assert strip_string(text_with_unicode_character, max_length=2).value == "é..." From 53ae75d8d6d07a031fef4535e969b12da4ac55af Mon Sep 17 00:00:00 2001 From: Anton Pirker Date: Thu, 30 Mar 2023 13:48:14 +0200 Subject: [PATCH 34/34] Renamed _socket back to socket to try if it was a GH problem --- sentry_sdk/integrations/{socket_.py => socket.py} | 0 tests/integrations/{socket_ => socket}/__init__.py | 0 tests/integrations/{socket_ => socket}/test_socket.py | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) rename sentry_sdk/integrations/{socket_.py => socket.py} (100%) rename tests/integrations/{socket_ => socket}/__init__.py (100%) rename tests/integrations/{socket_ => socket}/test_socket.py (95%) diff --git a/sentry_sdk/integrations/socket_.py b/sentry_sdk/integrations/socket.py similarity index 100% rename from sentry_sdk/integrations/socket_.py rename to sentry_sdk/integrations/socket.py diff --git a/tests/integrations/socket_/__init__.py b/tests/integrations/socket/__init__.py similarity index 100% rename from tests/integrations/socket_/__init__.py rename to tests/integrations/socket/__init__.py diff --git a/tests/integrations/socket_/test_socket.py b/tests/integrations/socket/test_socket.py similarity index 95% rename from tests/integrations/socket_/test_socket.py rename to tests/integrations/socket/test_socket.py index dd7b7b50a1..914ba0bf84 100644 --- a/tests/integrations/socket_/test_socket.py +++ b/tests/integrations/socket/test_socket.py @@ -1,7 +1,7 @@ import socket from sentry_sdk import start_transaction -from sentry_sdk.integrations.socket_ import SocketIntegration +from sentry_sdk.integrations.socket import SocketIntegration def test_getaddrinfo_trace(sentry_init, capture_events):