Skip to content
This repository has been archived by the owner on Oct 14, 2024. It is now read-only.

fix(spans): adhere attribute name to otel semver #434

Merged
merged 3 commits into from
Oct 11, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.3.4] - 2024-10-11

### Changed
- Updated HTTP span attributes to comply with updated OpenTelemetry semantic conventions. [#409](https://github.com/microsoft/kiota-http-python/issues/409)

## [1.3.3] - 2024-08-12

### Added
Expand Down
2 changes: 1 addition & 1 deletion kiota_http/_version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
VERSION: str = '1.3.3'
VERSION: str = "1.3.4"
30 changes: 18 additions & 12 deletions kiota_http/httpx_request_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,13 @@
)
from kiota_abstractions.store import BackingStoreFactory, BackingStoreFactorySingleton
from opentelemetry import trace
from opentelemetry.semconv.trace import SpanAttributes
from opentelemetry.semconv.attributes.http_attributes import (
HTTP_RESPONSE_STATUS_CODE,
HTTP_REQUEST_METHOD,
)
from opentelemetry.semconv.attributes.network_attributes import NETWORK_PROTOCOL_NAME
from opentelemetry.semconv.attributes.server_attributes import SERVER_ADDRESS
from opentelemetry.semconv.attributes.url_attributes import URL_SCHEME, URL_FULL

from kiota_http._exceptions import (
BackingStoreError,
Expand Down Expand Up @@ -529,15 +535,15 @@ async def get_http_response_message(
resp = await self._http_client.send(request)
if not resp:
raise ResponseError("Unable to get response from request")
parent_span.set_attribute(SpanAttributes.HTTP_STATUS_CODE, resp.status_code)
parent_span.set_attribute(HTTP_RESPONSE_STATUS_CODE, resp.status_code)
if http_version := resp.http_version:
parent_span.set_attribute(SpanAttributes.HTTP_FLAVOR, http_version)
parent_span.set_attribute(NETWORK_PROTOCOL_NAME, http_version)

if content_length := resp.headers.get("Content-Length", None):
parent_span.set_attribute(SpanAttributes.HTTP_RESPONSE_CONTENT_LENGTH, content_length)
parent_span.set_attribute("http.response.body.size", content_length)

if content_type := resp.headers.get("Content-Type", None):
parent_span.set_attribute("http.response_content_type", content_type)
parent_span.set_attribute("http.response.header.content-type", content_type)
_get_http_resp_span.end()
return await self.retry_cae_response_if_required(resp, request_info, claims)

Expand Down Expand Up @@ -586,15 +592,15 @@ def get_request_from_request_information(
)
url = parse.urlparse(request_info.url)
otel_attributes = {
SpanAttributes.HTTP_METHOD: request_info.http_method,
HTTP_REQUEST_METHOD: request_info.http_method,
"http.port": url.port,
SpanAttributes.HTTP_HOST: url.hostname,
SpanAttributes.HTTP_SCHEME: url.scheme,
"http.uri_template": request_info.url_template,
URL_SCHEME: url.hostname,
SERVER_ADDRESS: url.scheme,
"url.uri_template": request_info.url_template,
}

if self.observability_options.include_euii_attributes:
otel_attributes.update({"http.uri": url.geturl()})
otel_attributes.update({URL_FULL: url.geturl()})

request = self._http_client.build_request(
method=request_info.http_method.value,
Expand All @@ -610,10 +616,10 @@ def get_request_from_request_information(
setattr(request, "options", request_options)

if content_length := request.headers.get("Content-Length", None):
otel_attributes.update({SpanAttributes.HTTP_REQUEST_CONTENT_LENGTH: content_length})
otel_attributes.update({"http.request.body.size": content_length})

if content_type := request.headers.get("Content-Type", None):
otel_attributes.update({"http.request_content_type": content_type})
otel_attributes.update({"http.request.header.content-type": content_type})
attribute_span.set_attributes(otel_attributes)
_get_request_span.set_attributes(otel_attributes)
_get_request_span.end()
Expand Down
8 changes: 6 additions & 2 deletions kiota_http/middleware/redirect_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

import httpx
from kiota_abstractions.request_option import RequestOption
from opentelemetry.semconv.trace import SpanAttributes
from opentelemetry.semconv.attributes.http_attributes import (
HTTP_RESPONSE_STATUS_CODE,
)

from .._exceptions import RedirectError
from .middleware import BaseMiddleware
Expand Down Expand Up @@ -75,7 +77,9 @@ async def send(
request, f"RedirectHandler_send - redirect {len(history)}"
)
response = await super().send(request, transport)
_redirect_span.set_attribute(SpanAttributes.HTTP_STATUS_CODE, response.status_code)
_redirect_span.set_attribute(
HTTP_RESPONSE_STATUS_CODE, response.status_code
)
redirect_location = self.get_redirect_location(response)

if redirect_location and current_options.should_redirect:
Expand Down
8 changes: 5 additions & 3 deletions kiota_http/middleware/retry_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@

import httpx
from kiota_abstractions.request_option import RequestOption
from opentelemetry.semconv.trace import SpanAttributes
from opentelemetry.semconv.attributes.http_attributes import (
HTTP_RESPONSE_STATUS_CODE,
)

from .middleware import BaseMiddleware
from .options import RetryHandlerOption
Expand Down Expand Up @@ -82,7 +84,7 @@ async def send(self, request: httpx.Request, transport: httpx.AsyncBaseTransport
while retry_valid:
start_time = time.time()
response = await super().send(request, transport)
_retry_span.set_attribute(SpanAttributes.HTTP_STATUS_CODE, response.status_code)
_retry_span.set_attribute(HTTP_RESPONSE_STATUS_CODE, response.status_code)
# check that max retries has not been hit
retry_valid = self.check_retry_valid(retry_count, current_options)

Expand All @@ -99,7 +101,7 @@ async def send(self, request: httpx.Request, transport: httpx.AsyncBaseTransport
# increment the count for retries
retry_count += 1
request.headers.update({'retry-attempt': f'{retry_count}'})
_retry_span.set_attribute(SpanAttributes.HTTP_RETRY_COUNT, retry_count)
_retry_span.set_attribute('http.resend_count', retry_count)
baywet marked this conversation as resolved.
Show resolved Hide resolved
continue
break
if response is None:
Expand Down
6 changes: 4 additions & 2 deletions kiota_http/middleware/url_replace_handler.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import httpx
from kiota_abstractions.request_option import RequestOption
from opentelemetry.semconv.trace import SpanAttributes
from opentelemetry.semconv.attributes.url_attributes import (
URL_FULL
)

from .middleware import BaseMiddleware
from .options import UrlReplaceHandlerOption
Expand Down Expand Up @@ -40,7 +42,7 @@ async def send(
url_string: str = str(request.url) # type: ignore
url_string = self.replace_url_segment(url_string, current_options)
request.url = httpx.URL(url_string)
_enable_span.set_attribute(SpanAttributes.HTTP_URL, str(request.url))
_enable_span.set_attribute(URL_FULL, str(request.url))
response = await super().send(request, transport)
_enable_span.end()
return response
Expand Down
1 change: 0 additions & 1 deletion kiota_http/middleware/user_agent_handler.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from httpx import AsyncBaseTransport, Request, Response
from kiota_abstractions.request_option import RequestOption
from opentelemetry.semconv.trace import SpanAttributes

from .middleware import BaseMiddleware
from .options import UserAgentHandlerOption
Expand Down