Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions sentry_sdk/consts.py
Original file line number Diff line number Diff line change
Expand Up @@ -893,6 +893,18 @@ class SPANDATA:
Example: "5249fbada8d5416482c2f6e47e337372"
"""

RPC_METHOD = "rpc.method"
"""
The fully-qualified logical name of the method from the RPC interface perspective.
Example: "com.example.ExampleService/exampleMethod"
"""

RPC_RESPONSE_STATUS_CODE = "rpc.response.status_code"
"""
Status code of the RPC returned by the RPC server or generated by the client.
Example: "DEADLINE_EXCEEDED"
"""

SERVER_ADDRESS = "server.address"
"""
Name of the database host.
Expand Down
123 changes: 88 additions & 35 deletions sentry_sdk/integrations/grpc/aio/client.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
from typing import Callable, Union, AsyncIterable, Any

import sentry_sdk
from sentry_sdk.consts import OP
from sentry_sdk.consts import OP, SPANDATA
from sentry_sdk.integrations import DidNotEnable
from sentry_sdk.integrations.grpc.consts import SPAN_ORIGIN
from sentry_sdk.tracing_utils import has_span_streaming_enabled

try:
from grpc.aio import (
Expand Down Expand Up @@ -49,23 +50,50 @@ async def intercept_unary_unary(
) -> "Union[UnaryUnaryCall, Message]":
method = client_call_details.method

with sentry_sdk.start_span(
op=OP.GRPC_CLIENT,
name="unary unary call to %s" % method.decode(),
origin=SPAN_ORIGIN,
) as span:
span.set_data("type", "unary unary")
span.set_data("method", method)

client_call_details = self._update_client_call_details_metadata_from_scope(
client_call_details
)

response = await continuation(client_call_details, request)
status_code = await response.code()
span.set_data("code", status_code.name)

return response
client = sentry_sdk.get_client()
span_streaming = has_span_streaming_enabled(client.options)

if span_streaming:
with sentry_sdk.traces.start_span(
name="unary unary call to %s" % method.decode(),
attributes={
"sentry.op": OP.GRPC_CLIENT,
"sentry.origin": SPAN_ORIGIN,
},
) as span:
span.set_attribute(SPANDATA.RPC_METHOD, method.decode())

client_call_details = (
self._update_client_call_details_metadata_from_scope(
client_call_details
)
)

response = await continuation(client_call_details, request)
status_code = await response.code()
span.set_attribute(SPANDATA.RPC_RESPONSE_STATUS_CODE, status_code.name)

return response
else:
with sentry_sdk.start_span(
op=OP.GRPC_CLIENT,
name="unary unary call to %s" % method.decode(),
origin=SPAN_ORIGIN,
) as span:
span.set_data("type", "unary unary")
span.set_data("method", method)

client_call_details = (
self._update_client_call_details_metadata_from_scope(
client_call_details
)
)

response = await continuation(client_call_details, request)
status_code = await response.code()
span.set_data("code", status_code.name)

return response


class SentryUnaryStreamClientInterceptor(
Expand All @@ -80,20 +108,45 @@ async def intercept_unary_stream(
) -> "Union[AsyncIterable[Any], UnaryStreamCall]":
method = client_call_details.method

with sentry_sdk.start_span(
op=OP.GRPC_CLIENT,
name="unary stream call to %s" % method.decode(),
origin=SPAN_ORIGIN,
) as span:
span.set_data("type", "unary stream")
span.set_data("method", method)

client_call_details = self._update_client_call_details_metadata_from_scope(
client_call_details
)

response = await continuation(client_call_details, request)
# status_code = await response.code()
# span.set_data("code", status_code)

return response
client = sentry_sdk.get_client()
span_streaming = has_span_streaming_enabled(client.options)

if span_streaming:
with sentry_sdk.traces.start_span(
name="unary stream call to %s" % method.decode(),
attributes={
"sentry.op": OP.GRPC_CLIENT,
"sentry.origin": SPAN_ORIGIN,
},
) as span:
span.set_attribute(SPANDATA.RPC_METHOD, method.decode())

client_call_details = (
self._update_client_call_details_metadata_from_scope(
client_call_details
)
)

response = await continuation(client_call_details, request)

return response
else:
with sentry_sdk.start_span(
op=OP.GRPC_CLIENT,
name="unary stream call to %s" % method.decode(),
origin=SPAN_ORIGIN,
) as span:
span.set_data("type", "unary stream")
span.set_data("method", method)

client_call_details = (
self._update_client_call_details_metadata_from_scope(
client_call_details
)
)

response = await continuation(client_call_details, request)
# status_code = await response.code()
# span.set_data("code", status_code)

return response
71 changes: 50 additions & 21 deletions sentry_sdk/integrations/grpc/aio/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from sentry_sdk.integrations.grpc.consts import SPAN_ORIGIN
from sentry_sdk.tracing import TransactionSource
from sentry_sdk.utils import event_from_exception
from sentry_sdk.tracing_utils import has_span_streaming_enabled

from typing import TYPE_CHECKING

Expand Down Expand Up @@ -52,27 +53,55 @@ async def wrapped(request: "Any", context: "ServicerContext") -> "Any":
if not name:
return await handler(request, context)

# What if the headers are empty?
transaction = sentry_sdk.continue_trace(
dict(context.invocation_metadata()),
op=OP.GRPC_SERVER,
name=name,
source=TransactionSource.CUSTOM,
origin=SPAN_ORIGIN,
)

with sentry_sdk.start_transaction(transaction=transaction):
try:
return await handler.unary_unary(request, context)
except AbortError:
raise
except Exception as exc:
event, hint = event_from_exception(
exc,
mechanism={"type": "grpc", "handled": False},
)
sentry_sdk.capture_event(event, hint=hint)
raise
client = sentry_sdk.get_client()
span_streaming = has_span_streaming_enabled(client.options)
if span_streaming:
# What if the headers are empty?
sentry_sdk.traces.continue_trace(
dict(context.invocation_metadata())
)

with sentry_sdk.traces.start_span(
name=name,
attributes={
"sentry.op": OP.GRPC_SERVER,
"sentry.span.source": TransactionSource.CUSTOM,
"sentry.origin": SPAN_ORIGIN,
},
):
Comment thread
alexander-alderman-webb marked this conversation as resolved.
try:
return await handler.unary_unary(request, context)
except AbortError:
raise
except Exception as exc:
event, hint = event_from_exception(
exc,
mechanism={"type": "grpc", "handled": False},
)
sentry_sdk.capture_event(event, hint=hint)
raise
else:
# What if the headers are empty?
transaction = sentry_sdk.continue_trace(
dict(context.invocation_metadata()),
op=OP.GRPC_SERVER,
name=name,
source=TransactionSource.CUSTOM,
origin=SPAN_ORIGIN,
)

with sentry_sdk.start_transaction(transaction=transaction):
try:
return await handler.unary_unary(request, context)
except AbortError:
raise
except Exception as exc:
event, hint = event_from_exception(
exc,
mechanism={"type": "grpc", "handled": False},
)
sentry_sdk.capture_event(event, hint=hint)
raise

elif not handler.request_streaming and handler.response_streaming:
handler_factory = grpc.unary_stream_rpc_method_handler
Expand Down
123 changes: 89 additions & 34 deletions sentry_sdk/integrations/grpc/client.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import sentry_sdk
from sentry_sdk.consts import OP
from sentry_sdk.consts import OP, SPANDATA
from sentry_sdk.integrations import DidNotEnable
from sentry_sdk.integrations.grpc.consts import SPAN_ORIGIN
from sentry_sdk.tracing_utils import has_span_streaming_enabled

from typing import TYPE_CHECKING

Expand Down Expand Up @@ -30,22 +31,49 @@ def intercept_unary_unary(
) -> "_UnaryOutcome":
method = client_call_details.method

with sentry_sdk.start_span(
op=OP.GRPC_CLIENT,
name="unary unary call to %s" % method,
origin=SPAN_ORIGIN,
) as span:
span.set_data("type", "unary unary")
span.set_data("method", method)

client_call_details = self._update_client_call_details_metadata_from_scope(
client_call_details
)

response = continuation(client_call_details, request)
span.set_data("code", response.code().name)

return response
client = sentry_sdk.get_client()
span_streaming = has_span_streaming_enabled(client.options)
if span_streaming:
with sentry_sdk.traces.start_span(
name="unary unary call to %s" % method,
attributes={
"sentry.op": OP.GRPC_CLIENT,
"sentry.origin": SPAN_ORIGIN,
},
) as span:
span.set_attribute(SPANDATA.RPC_METHOD, method)

client_call_details = (
self._update_client_call_details_metadata_from_scope(
client_call_details
)
)

response = continuation(client_call_details, request)
span.set_attribute(
SPANDATA.RPC_RESPONSE_STATUS_CODE, response.code().name
)

return response
else:
with sentry_sdk.start_span(
op=OP.GRPC_CLIENT,
name="unary unary call to %s" % method,
origin=SPAN_ORIGIN,
) as span:
span.set_data("type", "unary unary")
span.set_data("method", method)

client_call_details = (
self._update_client_call_details_metadata_from_scope(
client_call_details
)
)

response = continuation(client_call_details, request)
span.set_data("code", response.code().name)

return response

def intercept_unary_stream(
self: "ClientInterceptor",
Expand All @@ -55,23 +83,50 @@ def intercept_unary_stream(
) -> "Union[Iterator[Message], Call]":
method = client_call_details.method

with sentry_sdk.start_span(
op=OP.GRPC_CLIENT,
name="unary stream call to %s" % method,
origin=SPAN_ORIGIN,
) as span:
span.set_data("type", "unary stream")
span.set_data("method", method)

client_call_details = self._update_client_call_details_metadata_from_scope(
client_call_details
)

response: "UnaryStreamCall" = continuation(client_call_details, request)
# Setting code on unary-stream leads to execution getting stuck
# span.set_data("code", response.code().name)

return response
client = sentry_sdk.get_client()
span_streaming = has_span_streaming_enabled(client.options)
response: "UnaryStreamCall"
if span_streaming:
with sentry_sdk.traces.start_span(
name="unary stream call to %s" % method,
attributes={
"sentry.op": OP.GRPC_CLIENT,
"sentry.origin": SPAN_ORIGIN,
},
) as span:
span.set_attribute(SPANDATA.RPC_METHOD, method)

client_call_details = (
self._update_client_call_details_metadata_from_scope(
client_call_details
)
)

response = continuation(client_call_details, request)
# Setting code on unary-stream leads to execution getting stuck
# span.set_data("code", response.code().name)

return response
else:
with sentry_sdk.start_span(
op=OP.GRPC_CLIENT,
name="unary stream call to %s" % method,
origin=SPAN_ORIGIN,
) as span:
span.set_data("type", "unary stream")
span.set_data("method", method)

client_call_details = (
self._update_client_call_details_metadata_from_scope(
client_call_details
)
)

response = continuation(client_call_details, request)
# Setting code on unary-stream leads to execution getting stuck
# span.set_data("code", response.code().name)

return response

@staticmethod
def _update_client_call_details_metadata_from_scope(
Expand Down
Loading
Loading