Skip to content

Commit 609eb70

Browse files
Merge branch 'main' into feature/convention-http-server-duration
2 parents 8eeafbb + 565e78d commit 609eb70

File tree

8 files changed

+166
-128
lines changed

8 files changed

+166
-128
lines changed

Diff for: CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## Unreleased
99

10+
### Fixed
1011
- Ensure all http.server.duration metrics have the same description
1112
([#2151](https://github.com/open-telemetry/opentelemetry-python-contrib/issues/2298))
1213

14+
### Fixed
15+
- Align gRPC span status codes to OTEL specification ([#1756](https://github.com/open-telemetry/opentelemetry-python-contrib/issues/1756))
16+
1317
## Version 1.23.0/0.44b0 (2024-02-23)
1418

1519
- Drop support for 3.7

Diff for: instrumentation/opentelemetry-instrumentation-aio-pika/README.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,6 @@ Installation
1818
References
1919
----------
2020

21-
* `OpenTelemetry Aio-pika instrumentation <https://opentelemetry-python-contrib.readthedocs.io/en/latest/instrumentation/aio-pika/aio-pika.html>`_
21+
* `OpenTelemetry Aio-pika instrumentation <https://opentelemetry-python-contrib.readthedocs.io/en/latest/instrumentation/aio_pika/aio_pika.html>`_
2222
* `OpenTelemetry Project <https://opentelemetry.io/>`_
2323
* `OpenTelemetry Python Examples <https://github.com/open-telemetry/opentelemetry-python/tree/main/docs/examples>`_

Diff for: instrumentation/opentelemetry-instrumentation-grpc/src/opentelemetry/instrumentation/grpc/_aio_server.py

+7-19
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@
1717
import wrapt
1818

1919
from opentelemetry.semconv.trace import SpanAttributes
20-
from opentelemetry.trace.status import Status, StatusCode
2120

2221
from ._server import OpenTelemetryServerInterceptor, _wrap_rpc_behavior
22+
from ._utilities import _server_status
2323

2424

2525
# pylint:disable=abstract-method
@@ -36,12 +36,8 @@ async def abort(self, code, details="", trailing_metadata=tuple()):
3636
self._self_active_span.set_attribute(
3737
SpanAttributes.RPC_GRPC_STATUS_CODE, code.value[0]
3838
)
39-
self._self_active_span.set_status(
40-
Status(
41-
status_code=StatusCode.ERROR,
42-
description=f"{code}:{details}",
43-
)
44-
)
39+
status = _server_status(code, details)
40+
self._self_active_span.set_status(status)
4541
return await self.__wrapped__.abort(code, details, trailing_metadata)
4642

4743
def set_code(self, code):
@@ -51,23 +47,15 @@ def set_code(self, code):
5147
SpanAttributes.RPC_GRPC_STATUS_CODE, code.value[0]
5248
)
5349
if code != grpc.StatusCode.OK:
54-
self._self_active_span.set_status(
55-
Status(
56-
status_code=StatusCode.ERROR,
57-
description=f"{code}:{details}",
58-
)
59-
)
50+
status = _server_status(code, details)
51+
self._self_active_span.set_status(status)
6052
return self.__wrapped__.set_code(code)
6153

6254
def set_details(self, details):
6355
self._self_details = details
6456
if self._self_code != grpc.StatusCode.OK:
65-
self._self_active_span.set_status(
66-
Status(
67-
status_code=StatusCode.ERROR,
68-
description=f"{self._self_code}:{details}",
69-
)
70-
)
57+
status = _server_status(self._self_code, details)
58+
self._self_active_span.set_status(status)
7159
return self.__wrapped__.set_details(details)
7260

7361

Diff for: instrumentation/opentelemetry-instrumentation-grpc/src/opentelemetry/instrumentation/grpc/_server.py

+8-19
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@
3131
from opentelemetry.context import attach, detach
3232
from opentelemetry.propagate import extract
3333
from opentelemetry.semconv.trace import SpanAttributes
34-
from opentelemetry.trace.status import Status, StatusCode
34+
35+
from ._utilities import _server_status
3536

3637
logger = logging.getLogger(__name__)
3738

@@ -124,12 +125,8 @@ def abort(self, code, details):
124125
self._active_span.set_attribute(
125126
SpanAttributes.RPC_GRPC_STATUS_CODE, code.value[0]
126127
)
127-
self._active_span.set_status(
128-
Status(
129-
status_code=StatusCode.ERROR,
130-
description=f"{code}:{details}",
131-
)
132-
)
128+
status = _server_status(code, details)
129+
self._active_span.set_status(status)
133130
return self._servicer_context.abort(code, details)
134131

135132
def abort_with_status(self, status):
@@ -158,23 +155,15 @@ def set_code(self, code):
158155
SpanAttributes.RPC_GRPC_STATUS_CODE, code.value[0]
159156
)
160157
if code != grpc.StatusCode.OK:
161-
self._active_span.set_status(
162-
Status(
163-
status_code=StatusCode.ERROR,
164-
description=f"{code}:{details}",
165-
)
166-
)
158+
status = _server_status(code, details)
159+
self._active_span.set_status(status)
167160
return self._servicer_context.set_code(code)
168161

169162
def set_details(self, details):
170163
self._details = details
171164
if self._code != grpc.StatusCode.OK:
172-
self._active_span.set_status(
173-
Status(
174-
status_code=StatusCode.ERROR,
175-
description=f"{self._code}:{details}",
176-
)
177-
)
165+
status = _server_status(self._code, details)
166+
self._active_span.set_status(status)
178167
return self._servicer_context.set_details(details)
179168

180169

Diff for: instrumentation/opentelemetry-instrumentation-grpc/src/opentelemetry/instrumentation/grpc/_utilities.py

+22
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@
1414

1515
"""Internal utilities."""
1616

17+
import grpc
18+
19+
from opentelemetry.trace.status import Status, StatusCode
20+
1721

1822
class RpcInfo:
1923
def __init__(
@@ -31,3 +35,21 @@ def __init__(
3135
self.request = request
3236
self.response = response
3337
self.error = error
38+
39+
40+
def _server_status(code, details):
41+
error_status = Status(
42+
status_code=StatusCode.ERROR, description=f"{code}:{details}"
43+
)
44+
status_codes = {
45+
grpc.StatusCode.UNKNOWN: error_status,
46+
grpc.StatusCode.DEADLINE_EXCEEDED: error_status,
47+
grpc.StatusCode.UNIMPLEMENTED: error_status,
48+
grpc.StatusCode.INTERNAL: error_status,
49+
grpc.StatusCode.UNAVAILABLE: error_status,
50+
grpc.StatusCode.DATA_LOSS: error_status,
51+
}
52+
53+
return status_codes.get(
54+
code, Status(status_code=StatusCode.UNSET, description="")
55+
)

Diff for: instrumentation/opentelemetry-instrumentation-grpc/tests/test_aio_server_interceptor.py

+6-13
Original file line numberDiff line numberDiff line change
@@ -507,9 +507,7 @@ async def test_abort(self):
507507
class AbortServicer(GRPCTestServerServicer):
508508
# pylint:disable=C0103
509509
async def SimpleMethod(self, request, context):
510-
await context.abort(
511-
grpc.StatusCode.FAILED_PRECONDITION, failure_message
512-
)
510+
await context.abort(grpc.StatusCode.INTERNAL, failure_message)
513511

514512
testcase = self
515513

@@ -520,9 +518,7 @@ async def request(channel):
520518
with testcase.assertRaises(grpc.RpcError) as cm:
521519
await channel.unary_unary(rpc_call)(msg)
522520

523-
self.assertEqual(
524-
cm.exception.code(), grpc.StatusCode.FAILED_PRECONDITION
525-
)
521+
self.assertEqual(cm.exception.code(), grpc.StatusCode.INTERNAL)
526522
self.assertEqual(cm.exception.details(), failure_message)
527523

528524
await run_with_test_server(request, servicer=AbortServicer())
@@ -543,7 +539,7 @@ async def request(channel):
543539
self.assertEqual(span.status.status_code, StatusCode.ERROR)
544540
self.assertEqual(
545541
span.status.description,
546-
f"{grpc.StatusCode.FAILED_PRECONDITION}:{failure_message}",
542+
f"{grpc.StatusCode.INTERNAL}:{failure_message}",
547543
)
548544

549545
# Check attributes
@@ -555,7 +551,7 @@ async def request(channel):
555551
SpanAttributes.RPC_METHOD: "SimpleMethod",
556552
SpanAttributes.RPC_SERVICE: "GRPCTestServer",
557553
SpanAttributes.RPC_SYSTEM: "grpc",
558-
SpanAttributes.RPC_GRPC_STATUS_CODE: grpc.StatusCode.FAILED_PRECONDITION.value[
554+
SpanAttributes.RPC_GRPC_STATUS_CODE: grpc.StatusCode.INTERNAL.value[
559555
0
560556
],
561557
},
@@ -605,11 +601,8 @@ async def request(channel):
605601
)
606602

607603
# make sure this span errored, with the right status and detail
608-
self.assertEqual(span.status.status_code, StatusCode.ERROR)
609-
self.assertEqual(
610-
span.status.description,
611-
f"{grpc.StatusCode.FAILED_PRECONDITION}:{failure_message}",
612-
)
604+
self.assertEqual(span.status.status_code, StatusCode.UNSET)
605+
self.assertEqual(span.status.description, None)
613606

614607
# Check attributes
615608
self.assertSpanHasAttributes(

Diff for: instrumentation/opentelemetry-instrumentation-grpc/tests/test_server_interceptor.py

+62-17
Original file line numberDiff line numberDiff line change
@@ -552,28 +552,45 @@ def test_abort(self):
552552
# our detailed failure message
553553
failure_message = "This is a test failure"
554554

555-
# aborting RPC handler
556-
def handler(request, context):
555+
# aborting RPC handlers
556+
def error_status_handler(request, context):
557+
context.abort(grpc.StatusCode.INTERNAL, failure_message)
558+
559+
def unset_status_handler(request, context):
557560
context.abort(grpc.StatusCode.FAILED_PRECONDITION, failure_message)
558561

559-
with self.server(
560-
max_workers=1,
561-
interceptors=[interceptor],
562-
) as (server, channel):
563-
server.add_generic_rpc_handlers((UnaryUnaryRpcHandler(handler),))
564-
rpc_call = "TestServicer/handler"
562+
rpc_call_error = "TestServicer/error_status_handler"
563+
rpc_call_unset = "TestServicer/unset_status_handler"
564+
565+
rpc_calls = {
566+
rpc_call_error: error_status_handler,
567+
rpc_call_unset: unset_status_handler,
568+
}
569+
570+
for rpc_call, handler in rpc_calls.items():
571+
with self.server(
572+
max_workers=1,
573+
interceptors=[interceptor],
574+
) as (server, channel):
575+
server.add_generic_rpc_handlers(
576+
(UnaryUnaryRpcHandler(handler),)
577+
)
565578

566-
server.start()
567-
# unfortunately, these are just bare exceptions in grpc...
568-
with self.assertRaises(Exception):
569-
channel.unary_unary(rpc_call)(b"")
570-
server.stop(None)
579+
server.start()
580+
581+
with self.assertRaises(Exception):
582+
channel.unary_unary(rpc_call)(b"")
583+
584+
# unfortunately, these are just bare exceptions in grpc...
585+
server.stop(None)
571586

572587
spans_list = self.memory_exporter.get_finished_spans()
573-
self.assertEqual(len(spans_list), 1)
588+
self.assertEqual(len(spans_list), 2)
589+
590+
# check error span
574591
span = spans_list[0]
575592

576-
self.assertEqual(span.name, rpc_call)
593+
self.assertEqual(span.name, rpc_call_error)
577594
self.assertIs(span.kind, trace.SpanKind.SERVER)
578595

579596
# Check version and name in span's instrumentation info
@@ -585,15 +602,43 @@ def handler(request, context):
585602
self.assertEqual(span.status.status_code, StatusCode.ERROR)
586603
self.assertEqual(
587604
span.status.description,
588-
f"{grpc.StatusCode.FAILED_PRECONDITION}:{failure_message}",
605+
f"{grpc.StatusCode.INTERNAL}:{failure_message}",
606+
)
607+
608+
# Check attributes
609+
self.assertSpanHasAttributes(
610+
span,
611+
{
612+
**self.net_peer_span_attributes,
613+
SpanAttributes.RPC_METHOD: "error_status_handler",
614+
SpanAttributes.RPC_SERVICE: "TestServicer",
615+
SpanAttributes.RPC_SYSTEM: "grpc",
616+
SpanAttributes.RPC_GRPC_STATUS_CODE: grpc.StatusCode.INTERNAL.value[
617+
0
618+
],
619+
},
589620
)
590621

622+
# check unset status span
623+
span = spans_list[1]
624+
625+
self.assertEqual(span.name, rpc_call_unset)
626+
self.assertIs(span.kind, trace.SpanKind.SERVER)
627+
628+
# Check version and name in span's instrumentation info
629+
self.assertEqualSpanInstrumentationInfo(
630+
span, opentelemetry.instrumentation.grpc
631+
)
632+
633+
self.assertEqual(span.status.description, None)
634+
self.assertEqual(span.status.status_code, StatusCode.UNSET)
635+
591636
# Check attributes
592637
self.assertSpanHasAttributes(
593638
span,
594639
{
595640
**self.net_peer_span_attributes,
596-
SpanAttributes.RPC_METHOD: "handler",
641+
SpanAttributes.RPC_METHOD: "unset_status_handler",
597642
SpanAttributes.RPC_SERVICE: "TestServicer",
598643
SpanAttributes.RPC_SYSTEM: "grpc",
599644
SpanAttributes.RPC_GRPC_STATUS_CODE: grpc.StatusCode.FAILED_PRECONDITION.value[

0 commit comments

Comments
 (0)