getsentry / sentry-python

The official Python SDK for Sentry.io
https://sentry.io/for/python/
MIT License
1.8k stars 473 forks source link

grpclib support #2976

Open DeoLeung opened 2 months ago

DeoLeung commented 2 months ago

Problem Statement

I use grpclib as my gprc server implementation, sentry has a grpcio integration , but no grpclib

Solution Brainstorm

add grpclib support

szokeasaurusrex commented 2 months ago

Hi @DeoLeung, thank you for the suggestion!

We will place this issue on our backlog, but it might take us some time to get around to implementing a grpclib integration. However, we gladly accept PRs if you would like to contribute!

bettdouglas commented 2 months ago

Hi @szokeasaurusrex I'd also be interesting in having this implemented. How does one go about capturing the trace/monitor a specific run?

From https://grpclib.readthedocs.io/en/latest/events.html,

Given a server

from grpclib.events import (RecvRequest, SendInitialMetadata, SendMessage,
                            SendTrailingMetadata, listen)

def setup_server_logger(server: Server):
    logger = logging.getLogger('ChatServiceLogger')
    async def recv_request(event: RecvRequest):
        # Dispatches after request was received from the client
        # event.metadata['request-id'] = str(uuid.uuid4())
        logger.info(f'---------\nRecevied RequestID: {event.metadata.get('request-id')}\nMethodName:{event.method_name}\nMetadata: {str(list(event.metadata.keys()))}\nUser-Agent:{event.user_agent}\n---------\n\n')

    async def send_message(event: SendMessage):
        # Dispatches before sending message to the client
        logger.info(f'---------\nSending Response : {type(event.message)}\n---------\n\n')

    async def send_trailing_metadata(event: SendTrailingMetadata):
        # Dispatches before sending trailers with trailing metadata to the client
        logger.info(f'---------\nClosing RequestID: {event.metadata.get('request-id')}\nMetadata: {str(list(event.metadata.keys()))}\nStatus:{event.status}\nStatusMessage:{event.status_message}\nStatusDetails:{event.status_details}\n---------\n\n')

    async def send_initial_metadata(event: SendInitialMetadata):
        # Dispatches before sending headers with initial metadata to the client
        event.metadata['request-id'] = str(uuid.uuid4())
        logger.info(f'---------\nSendingInitialMetadata: {str(event.metadata)}')

    listen(server, RecvRequest, recv_request)
    listen(server,SendMessage,send_message)
    listen(server,SendTrailingMetadata,send_trailing_metadata)
    listen(server,SendInitialMetadata,send_initial_metadata)

if __name__ == "__main__":
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)

    async def main():
        for _ in ('databases','test'):
            logging.getLogger(_).setLevel(logging.CRITICAL)

        database_url = db.create_postgres_conn_string()
        database = await db.get_database(conn_string=database_url)
        await db.create_tables(database)

        server = Server([ChatService(loop=loop, db=database)])
        setup_server_logger(server=server)

        port = int(os.environ.get("PORT", "50051"))
        await server.start("0.0.0.0", port)
        print(f"Server running on {port}")

        await server.wait_closed()

    loop.run_until_complete(main())

How would one go about implementing tracing the request from start to completion?

sl0thentr0py commented 2 months ago

@bettdouglas i'm not sure if those events will suffice but I haven't read the source of the library in detail. For instance, RecvRequest will trigger on receive, but you also need another event to signal that the processing of the request has completed.


IF you also have that event, then you can basically


However, since the other event doesn't seem to be available, the best way might just be to monkeypatch request_handler and use the with sentry_sdk.start_transaction context manager like we do in most other integrations.