diff --git a/solarwinds_apm/k8s.py b/solarwinds_apm/k8s.py index 25823e049..824e706d3 100644 --- a/solarwinds_apm/k8s.py +++ b/solarwinds_apm/k8s.py @@ -8,7 +8,11 @@ from contextlib import suppress from opentelemetry.sdk.resources import Resource, ResourceDetector -from opentelemetry.semconv.resource import ResourceAttributes +from opentelemetry.semconv.attributes.k8s_attributes import ( + K8S_NAMESPACE_NAME, + K8S_POD_NAME, + K8S_POD_UID, +) logger = logging.getLogger(__name__) @@ -132,16 +136,16 @@ def detect(self) -> Resource: namespace = _pod_namespace(self._namespace) if namespace: - attributes[ResourceAttributes.K8S_NAMESPACE_NAME] = namespace + attributes[K8S_NAMESPACE_NAME] = namespace else: return Resource.get_empty() uid = _pod_uid(self._mountinfo) if uid: - attributes[ResourceAttributes.K8S_POD_UID] = uid + attributes[K8S_POD_UID] = uid name = _pod_name() if name: - attributes[ResourceAttributes.K8S_POD_NAME] = name + attributes[K8S_POD_NAME] = name return Resource(attributes) diff --git a/solarwinds_apm/trace/response_time_processor.py b/solarwinds_apm/trace/response_time_processor.py index e5a1587d1..f1c94d1da 100644 --- a/solarwinds_apm/trace/response_time_processor.py +++ b/solarwinds_apm/trace/response_time_processor.py @@ -8,7 +8,14 @@ from opentelemetry.metrics import get_meter from opentelemetry.sdk.trace import SpanProcessor -from opentelemetry.semconv.trace import SpanAttributes +from opentelemetry.semconv._incubating.attributes.http_attributes import ( + HTTP_METHOD, + HTTP_STATUS_CODE, +) +from opentelemetry.semconv.attributes.http_attributes import ( + HTTP_REQUEST_METHOD, + HTTP_RESPONSE_STATUS_CODE, +) from opentelemetry.trace import SpanKind, StatusCode from solarwinds_apm.apm_constants import ( @@ -32,16 +39,12 @@ class ResponseTimeProcessor(SpanProcessor): including response time, error status, and HTTP-specific attributes. """ - _HTTP_REQUEST_METHOD = ( - SpanAttributes.HTTP_REQUEST_METHOD - ) # http.request.method - _HTTP_RESPONSE_STATUS_CODE = ( - SpanAttributes.HTTP_RESPONSE_STATUS_CODE - ) # "http.response.status_code" + _HTTP_REQUEST_METHOD = HTTP_REQUEST_METHOD # http.request.method + _HTTP_RESPONSE_STATUS_CODE = HTTP_RESPONSE_STATUS_CODE # Deprecated, but potentially still used by some instrumentors - _HTTP_METHOD = SpanAttributes.HTTP_METHOD # "http.method" - _HTTP_STATUS_CODE = SpanAttributes.HTTP_STATUS_CODE # "http.status_code" + _HTTP_METHOD = HTTP_METHOD # "http.method" + _HTTP_STATUS_CODE = HTTP_STATUS_CODE # "http.status_code" _HTTP_SPAN_STATUS_UNAVAILABLE = 0 diff --git a/solarwinds_apm/trace/serviceentry_processor.py b/solarwinds_apm/trace/serviceentry_processor.py index b1863a943..f259e851a 100644 --- a/solarwinds_apm/trace/serviceentry_processor.py +++ b/solarwinds_apm/trace/serviceentry_processor.py @@ -12,8 +12,11 @@ from opentelemetry import context from opentelemetry.sdk.trace import Span, SpanProcessor -from opentelemetry.semconv.resource import ResourceAttributes -from opentelemetry.semconv.trace import SpanAttributes +from opentelemetry.semconv._incubating.attributes.faas_attributes import ( + FAAS_NAME, +) +from opentelemetry.semconv.attributes.http_attributes import HTTP_ROUTE +from opentelemetry.semconv.attributes.url_attributes import URL_PATH from solarwinds_apm.apm_constants import ( INTL_SWO_OTEL_CONTEXT_ENTRY_SPAN, @@ -107,10 +110,10 @@ def on_start( # Calculate non-custom txn name for entry span if we can retrieve the URL # or serverless name. Otherwise, use the span's name sw_apm_txn_name = os.environ.get("SW_APM_TRANSACTION_NAME", None) - faas_name = span.attributes.get(ResourceAttributes.FAAS_NAME, None) + faas_name = span.attributes.get(FAAS_NAME, None) lambda_function_name = os.environ.get("AWS_LAMBDA_FUNCTION_NAME", None) - http_route = span.attributes.get(SpanAttributes.HTTP_ROUTE, None) - url_path = span.attributes.get(SpanAttributes.URL_PATH, None) + http_route = span.attributes.get(HTTP_ROUTE, None) + url_path = span.attributes.get(URL_PATH, None) if sw_apm_txn_name: self.set_default_transaction_name(span, sw_apm_txn_name) elif faas_name: diff --git a/solarwinds_apm/uams.py b/solarwinds_apm/uams.py index b4b26aa8a..8f3a6bac6 100644 --- a/solarwinds_apm/uams.py +++ b/solarwinds_apm/uams.py @@ -12,7 +12,9 @@ set_value, ) from opentelemetry.sdk.resources import Resource, ResourceDetector -from opentelemetry.semconv.resource import ResourceAttributes +from opentelemetry.semconv._incubating.attributes.host_attributes import ( + HOST_ID, +) logger = logging.getLogger(__name__) @@ -43,7 +45,7 @@ def _read_from_file(uams_file: str) -> dict: uams_id = file.read().strip() return { ATTR_UAMS_CLIENT_ID: uams_id, - ResourceAttributes.HOST_ID: uams_id, + HOST_ID: uams_id, } except Exception as error: # pylint: disable=broad-exception-caught logger.debug("file error", exc_info=error) @@ -70,7 +72,7 @@ def _read_from_api() -> dict: id = data[UAMS_CLIENT_ID_FIELD] return { ATTR_UAMS_CLIENT_ID: id, - ResourceAttributes.HOST_ID: id, + HOST_ID: id, } except Exception as error: # pylint: disable=broad-exception-caught logger.debug("api response error", exc_info=error) diff --git a/tests/unit/test_k8s.py b/tests/unit/test_k8s.py index 7d7123346..49730a13d 100644 --- a/tests/unit/test_k8s.py +++ b/tests/unit/test_k8s.py @@ -10,7 +10,11 @@ from contextlib import suppress import pytest -from opentelemetry.semconv.resource import ResourceAttributes +from opentelemetry.semconv.attributes.k8s_attributes import ( + K8S_NAMESPACE_NAME, + K8S_POD_NAME, + K8S_POD_UID, +) from solarwinds_apm.k8s import K8sResourceDetector @@ -89,9 +93,9 @@ def test_detects_attributes_from_env(mocker): resource = k8s_detector.detect() assert resource.attributes == { - ResourceAttributes.K8S_NAMESPACE_NAME: ENV_NAMESPACE, - ResourceAttributes.K8S_POD_UID: ENV_UID, - ResourceAttributes.K8S_POD_NAME: ENV_NAME, + K8S_NAMESPACE_NAME: ENV_NAMESPACE, + K8S_POD_UID: ENV_UID, + K8S_POD_NAME: ENV_NAME, } @@ -103,11 +107,11 @@ def test_detects_attributes_from_files(): resource = k8s_detector.detect() expected_attributes = { - ResourceAttributes.K8S_NAMESPACE_NAME: FILE_NAMESPACE, - ResourceAttributes.K8S_POD_NAME: os.uname().nodename, + K8S_NAMESPACE_NAME: FILE_NAMESPACE, + K8S_POD_NAME: os.uname().nodename, } if os.name != "nt": - expected_attributes[ResourceAttributes.K8S_POD_UID] = FILE_UID + expected_attributes[K8S_POD_UID] = FILE_UID assert resource.attributes == expected_attributes @@ -128,9 +132,9 @@ def test_prefers_env_over_files(mocker): resource = k8s_detector.detect() assert resource.attributes == { - ResourceAttributes.K8S_NAMESPACE_NAME: ENV_NAMESPACE, - ResourceAttributes.K8S_POD_UID: ENV_UID, - ResourceAttributes.K8S_POD_NAME: ENV_NAME, + K8S_NAMESPACE_NAME: ENV_NAMESPACE, + K8S_POD_UID: ENV_UID, + K8S_POD_NAME: ENV_NAME, } diff --git a/tests/unit/test_processors/test_response_time_processor.py b/tests/unit/test_processors/test_response_time_processor.py index dfc555f46..7cfb33be1 100644 --- a/tests/unit/test_processors/test_response_time_processor.py +++ b/tests/unit/test_processors/test_response_time_processor.py @@ -1,6 +1,14 @@ # Copyright SolarWinds Worldwide, LLC. # SPDX-License-Identifier: Apache-2.0 +from opentelemetry.semconv._incubating.attributes.http_attributes import ( + HTTP_METHOD, +) +from opentelemetry.semconv.attributes.http_attributes import ( + HTTP_REQUEST_METHOD, +) +from opentelemetry.trace import SpanKind + from solarwinds_apm.trace import ResponseTimeProcessor @@ -40,49 +48,28 @@ def test__init(self, mocker): assert processor.lambda_function_name == "foo-lambda-name" def test_is_span_http_true(self, mocker): - mock_spankind = mocker.patch( - "solarwinds_apm.trace.response_time_processor.SpanKind" - ) - mock_spankind.configure_mock(SERVER="foo") - mock_spanattributes = mocker.patch( - "solarwinds_apm.trace.response_time_processor.SpanAttributes" - ) - mock_spanattributes.configure_mock( - HTTP_REQUEST_METHOD="http.request.method" - ) mock_span = mocker.Mock() mock_span.configure_mock( - kind="foo", attributes={"http.request.method": "bar"} + kind=SpanKind.SERVER, + attributes={HTTP_REQUEST_METHOD: "GET"}, ) processor = ResponseTimeProcessor(mocker.Mock()) assert processor.is_span_http(mock_span) def test_is_span_http_true_old_attr(self, mocker): - mock_spankind = mocker.patch( - "solarwinds_apm.trace.response_time_processor.SpanKind" - ) - mock_spankind.configure_mock(SERVER="foo") - mock_spanattributes = mocker.patch( - "solarwinds_apm.trace.response_time_processor.SpanAttributes" - ) - mock_spanattributes.configure_mock(HTTP_METHOD="http.method") mock_span = mocker.Mock() - mock_span.configure_mock(kind="foo", attributes={"http.method": "bar"}) + mock_span.configure_mock( + kind=SpanKind.SERVER, + attributes={HTTP_METHOD: "GET"}, + ) processor = ResponseTimeProcessor(mocker.Mock()) assert processor.is_span_http(mock_span) def test_is_span_http_false_no_http_method(self, mocker): - mock_spankind = mocker.patch( - "solarwinds_apm.trace.response_time_processor.SpanKind" - ) - mock_spankind.configure_mock(SERVER="foo") - mock_spanattributes = mocker.patch( - "solarwinds_apm.trace.response_time_processor.SpanAttributes" - ) - mock_spanattributes.configure_mock(HTTP_METHOD="http.method") mock_span = mocker.Mock() mock_span.configure_mock( - kind="foo", attributes={"NOT.http.method.hehehehe": "bar"} + kind=SpanKind.SERVER, + attributes={"NOT.http.method.hehehehe": "bar"}, ) processor = ResponseTimeProcessor(mocker.Mock()) assert not processor.is_span_http(mock_span) diff --git a/tests/unit/test_uams.py b/tests/unit/test_uams.py index ef5576ee2..4b509c3f0 100644 --- a/tests/unit/test_uams.py +++ b/tests/unit/test_uams.py @@ -8,7 +8,9 @@ from unittest.mock import MagicMock, patch import pytest -from opentelemetry.semconv.resource import ResourceAttributes +from opentelemetry.semconv._incubating.attributes.host_attributes import ( + HOST_ID, +) from solarwinds_apm.uams import ATTR_UAMS_CLIENT_ID, UamsResourceDetector @@ -41,7 +43,7 @@ def test_detects_id_from_file_when_file_present_and_api_running( resource = detector.detect() assert resource.attributes == { ATTR_UAMS_CLIENT_ID: UAMS_FILE_ID, - ResourceAttributes.HOST_ID: UAMS_FILE_ID, + HOST_ID: UAMS_FILE_ID, } # Ensure the API was not called mock_get.assert_not_called() @@ -54,7 +56,7 @@ def test_detects_id_from_file_when_file_present_and_api_not_running( resource = detector.detect() assert resource.attributes == { ATTR_UAMS_CLIENT_ID: UAMS_FILE_ID, - ResourceAttributes.HOST_ID: UAMS_FILE_ID, + HOST_ID: UAMS_FILE_ID, } @@ -72,7 +74,7 @@ def test_detects_id_from_file_when_file_present_and_unrelated_running( resource = detector.detect() assert resource.attributes == { ATTR_UAMS_CLIENT_ID: UAMS_FILE_ID, - ResourceAttributes.HOST_ID: UAMS_FILE_ID, + HOST_ID: UAMS_FILE_ID, } # Ensure the API was not called mock_get.assert_not_called() @@ -90,7 +92,7 @@ def test_detects_id_from_api_when_file_not_present_and_api_running(mock_get): resource = detector.detect() assert resource.attributes == { ATTR_UAMS_CLIENT_ID: UAMS_API_ID, - ResourceAttributes.HOST_ID: UAMS_API_ID, + HOST_ID: UAMS_API_ID, } # Ensure the API was called mock_get.assert_called_once()