Skip to content

Commit b3b9ded

Browse files
author
Corvin Lasogga
committed
bugfix of contextmanager of generator
1 parent 97d89d5 commit b3b9ded

File tree

1 file changed

+139
-105
lines changed
  • instrumentation/opentelemetry-instrumentation-grpc/src/opentelemetry/instrumentation/grpc

1 file changed

+139
-105
lines changed

instrumentation/opentelemetry-instrumentation-grpc/src/opentelemetry/instrumentation/grpc/_server.py

Lines changed: 139 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ def __init__(self, meter, tracer):
252252
self._duration_histogram = self._meter.create_histogram(
253253
name="rpc.server.duration",
254254
unit="ms",
255-
description="measures the duration of the inbound rpc",
255+
description="measures duration of inbound RPC",
256256
)
257257
self._request_size_histogram = self._meter.create_histogram(
258258
name="rpc.server.request.size",
@@ -339,70 +339,16 @@ def _create_attributes(self, context, full_method):
339339
def intercept_service(self, continuation, handler_call_details):
340340
def telemetry_wrapper(behavior, request_streaming, response_streaming):
341341
def telemetry_interceptor(request_or_iterator, context):
342-
with self._set_remote_context(context):
343-
attributes = self._create_attributes(context, handler_call_details.method)
344-
345-
with self._tracer.start_as_current_span(
346-
name=handler_call_details.method,
347-
kind=trace.SpanKind.SERVER,
348-
attributes=attributes,
349-
end_on_exit=False,
350-
record_exception=False,
351-
set_status_on_exception=False
352-
) as span:
353-
354-
try:
355-
# wrap the context
356-
context = _OpenTelemetryServicerContext(context, span)
357-
358-
# wrap / log the request (iterator)
359-
if request_streaming:
360-
request_or_iterator = self._log_stream_requests(
361-
request_or_iterator, span, attributes
362-
)
363-
else:
364-
self._log_unary_request(
365-
request_or_iterator, span, attributes
366-
)
367-
368-
# call the actual RPC and track the duration
369-
with self._record_duration(attributes, context):
370-
response_or_iterator = behavior(request_or_iterator, context)
371-
372-
# wrap / log the response (iterator)
373-
if response_streaming:
374-
response_or_iterator = self._log_stream_responses(
375-
response_or_iterator, span, attributes, context
376-
)
377-
else:
378-
self._log_unary_response(
379-
response_or_iterator, span, attributes, context
380-
)
381-
382-
return response_or_iterator
383-
384-
except Exception as exc:
385-
# Bare exceptions are likely to be gRPC aborts, which
386-
# we handle in our context wrapper.
387-
# Here, we're interested in uncaught exceptions.
388-
# pylint:disable=unidiomatic-typecheck
389-
if type(exc) != Exception:
390-
span.set_attribute(
391-
SpanAttributes.RPC_GRPC_STATUS_CODE,
392-
grpc.StatusCode.UNKNOWN.value[0]
393-
)
394-
span.set_status(
395-
Status(
396-
status_code=StatusCode.ERROR,
397-
description=f"{type(exc).__name__}: {exc}",
398-
)
399-
)
400-
span.record_exception(exc)
401-
raise exc
402-
403-
finally:
404-
if not response_streaming:
405-
span.end()
342+
if response_streaming:
343+
return self._intercept_streaming_response(
344+
behavior, request_or_iterator, context,
345+
request_streaming, handler_call_details.method
346+
)
347+
348+
return self._intercept_unary_response(
349+
behavior, request_or_iterator, context,
350+
request_streaming, handler_call_details.method
351+
)
406352

407353
return telemetry_interceptor
408354

@@ -411,6 +357,118 @@ def telemetry_interceptor(request_or_iterator, context):
411357
telemetry_wrapper
412358
)
413359

360+
def _intercept_unary_response(self, behavior, request_or_iterator, context, request_streaming, full_method):
361+
with self._set_remote_context(context):
362+
attributes = self._create_attributes(context, full_method)
363+
364+
with self._tracer.start_as_current_span(
365+
name=full_method,
366+
kind=trace.SpanKind.SERVER,
367+
attributes=attributes,
368+
end_on_exit=True,
369+
record_exception=False,
370+
set_status_on_exception=False
371+
) as span:
372+
373+
try:
374+
# wrap the context
375+
context = _OpenTelemetryServicerContext(context, span)
376+
377+
# wrap / log the request (iterator)
378+
if request_streaming:
379+
request_or_iterator = self._log_streaming_request(
380+
request_or_iterator, span, attributes
381+
)
382+
else:
383+
self._log_unary_request(
384+
request_or_iterator, span, attributes
385+
)
386+
387+
# call the actual RPC and track the duration
388+
with self._record_duration(attributes, context):
389+
response_or_iterator = behavior(request_or_iterator, context)
390+
391+
# log the response (iterator)
392+
self._log_unary_response(
393+
response_or_iterator, span, attributes, context
394+
)
395+
396+
return response_or_iterator
397+
398+
except Exception as exc:
399+
# Bare exceptions are likely to be gRPC aborts, which
400+
# we handle in our context wrapper.
401+
# Here, we're interested in uncaught exceptions.
402+
# pylint:disable=unidiomatic-typecheck
403+
if type(exc) != Exception:
404+
span.set_attribute(
405+
SpanAttributes.RPC_GRPC_STATUS_CODE,
406+
grpc.StatusCode.UNKNOWN.value[0]
407+
)
408+
span.set_status(
409+
Status(
410+
status_code=StatusCode.ERROR,
411+
description=f"{type(exc).__name__}: {exc}",
412+
)
413+
)
414+
span.record_exception(exc)
415+
raise exc
416+
417+
def _intercept_streaming_response(self, behavior, request_or_iterator, context, request_streaming, full_method):
418+
with self._set_remote_context(context):
419+
attributes = self._create_attributes(context, full_method)
420+
421+
with self._tracer.start_as_current_span(
422+
name=full_method,
423+
kind=trace.SpanKind.SERVER,
424+
attributes=attributes,
425+
end_on_exit=True,
426+
record_exception=False,
427+
set_status_on_exception=False
428+
) as span:
429+
430+
try:
431+
# wrap the context
432+
context = _OpenTelemetryServicerContext(context, span)
433+
434+
# wrap / log the request (iterator)
435+
if request_streaming:
436+
request_or_iterator = self._log_streaming_request(
437+
request_or_iterator, span, attributes
438+
)
439+
else:
440+
self._log_unary_request(
441+
request_or_iterator, span, attributes
442+
)
443+
444+
# call the actual RPC and track the duration
445+
with self._record_duration(attributes, context):
446+
response_or_iterator = behavior(request_or_iterator, context)
447+
448+
# log the response (iterator)
449+
yield from self._log_streaming_response(
450+
response_or_iterator, span, attributes, context
451+
)
452+
453+
except Exception as exc:
454+
# Bare exceptions are likely to be gRPC aborts, which
455+
# we handle in our context wrapper.
456+
# Here, we're interested in uncaught exceptions.
457+
# pylint:disable=unidiomatic-typecheck
458+
if type(exc) != Exception:
459+
span.set_attribute(
460+
SpanAttributes.RPC_GRPC_STATUS_CODE,
461+
grpc.StatusCode.UNKNOWN.value[0]
462+
)
463+
span.set_status(
464+
Status(
465+
status_code=StatusCode.ERROR,
466+
description=f"{type(exc).__name__}: {exc}",
467+
)
468+
)
469+
span.record_exception(exc)
470+
raise exc
471+
414472
def _log_unary_request(self, request, active_span, attributes):
415473
message_size_by = request.ByteSize()
416474
_add_message_event(
@@ -429,7 +487,7 @@ def _log_unary_response(self, response, active_span, attributes, context):
429487
self._response_size_histogram.record(message_size_by, attributes)
430488
self._responses_per_rpc_histogram.record(1, attributes)
431489

432-
def _log_stream_requests(self, request_iterator, active_span, attributes):
490+
def _log_streaming_request(self, request_iterator, active_span, attributes):
433491
req_id = 1
434492
for req_id, msg in enumerate(request_iterator, start=1):
435493
message_size_by = msg.ByteSize()
@@ -441,52 +499,28 @@ def _log_stream_requests(self, request_iterator, active_span, attributes):
441499

442500
self._requests_per_rpc_histogram.record(req_id, attributes)
443501

444-
def _log_stream_responses(self, response_iterator, active_span, attributes, context):
445-
with trace.use_span(
446-
active_span,
447-
end_on_exit=True,
448-
record_exception=False,
449-
set_status_on_exception=False
450-
):
451-
try:
452-
res_id = 1
453-
for res_id, msg in enumerate(response_iterator, start=1):
454-
message_size_by = msg.ByteSize()
455-
_add_message_event(
456-
active_span, MessageTypeValues.SENT.value, message_size_by, message_id=res_id
457-
)
458-
self._response_size_histogram.record(message_size_by, attributes)
459-
yield msg
460-
except Exception as exc:
461-
# Bare exceptions are likely to be gRPC aborts, which
462-
# we handle in our context wrapper.
463-
# Here, we're interested in uncaught exceptions.
464-
# pylint:disable=unidiomatic-typecheck
465-
if type(exc) != Exception:
466-
active_span.set_attribute(
467-
SpanAttributes.RPC_GRPC_STATUS_CODE,
468-
grpc.StatusCode.UNKNOWN.value[0]
469-
)
470-
active_span.set_status(
471-
Status(
472-
status_code=StatusCode.ERROR,
473-
description=f"{type(exc).__name__}: {exc}",
474-
)
475-
)
476-
active_span.record_exception(exc)
477-
raise exc
478-
finally:
479-
if context._code != grpc.StatusCode.OK:
480-
attributes[SpanAttributes.RPC_GRPC_STATUS_CODE] = context._code.value[0]
481-
self._responses_per_rpc_histogram.record(res_id, attributes)
502+
def _log_streaming_response(self, response_iterator, active_span, attributes, context):
503+
try:
504+
res_id = 1
505+
for res_id, msg in enumerate(response_iterator, start=1):
506+
message_size_by = msg.ByteSize()
507+
_add_message_event(
508+
active_span, MessageTypeValues.SENT.value, message_size_by, message_id=res_id
509+
)
510+
self._response_size_histogram.record(message_size_by, attributes)
511+
yield msg
512+
finally:
513+
if context._code != grpc.StatusCode.OK:
514+
attributes[SpanAttributes.RPC_GRPC_STATUS_CODE] = context._code.value[0]
515+
self._responses_per_rpc_histogram.record(res_id, attributes)
482516

483517
@contextmanager
484518
def _record_duration(self, attributes, context):
485519
start = _time_ns()
486520
try:
487521
yield
488522
finally:
489-
duration = max(round((_time_ns() - start) * 1000), 0)
523+
duration = max(round((_time_ns() - start) / 1000), 0)
490524
if context._code != grpc.StatusCode.OK:
491525
attributes[SpanAttributes.RPC_GRPC_STATUS_CODE] = context._code.value[0]
492526
self._duration_histogram.record(duration, attributes)

0 commit comments

Comments
 (0)