Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 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
1 change: 1 addition & 0 deletions .changelog/5389.changed
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
`opentelemetry-exporter-otlp-proto-http`: refactor to use shared opentelemetry-exporter-otlp-common and opentelemetry-exporter-http-transport packages
Comment thread
herin049 marked this conversation as resolved.
Resolved
2 changes: 1 addition & 1 deletion docs-requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ sphinx-jekyll-builder==0.3.0
./shim/opentelemetry-opencensus-shim
./shim/opentelemetry-opentracing-shim
./exporter/opentelemetry-exporter-otlp-proto-common
./exporter/opentelemetry-exporter-otlp-proto-http
./exporter/opentelemetry-exporter-otlp-proto-http[requests]
./exporter/opentelemetry-exporter-otlp-proto-grpc

# Required by instrumentation and exporter packages
Expand Down
3 changes: 3 additions & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@
"wrapt": ("https://wrapt.readthedocs.io/en/latest/", None),
"pymongo": ("https://pymongo.readthedocs.io/en/stable/", None),
"grpc": ("https://grpc.github.io/grpc/python/", None),
"requests": ("https://requests.readthedocs.io/en/latest/", None),
}

# http://www.sphinx-doc.org/en/master/config.html#confval-nitpicky
Expand Down Expand Up @@ -194,6 +195,8 @@
# ``from os import PathLike`` renders as the bare name ``PathLike`` in the
# file exporter type hints, which sphinx cannot resolve to os.PathLike.
("py:class", "PathLike"),
("py:class", "BaseHTTPTransport"),
("py:class", "opentelemetry.exporter.otlp.common._http.Compression"),
]

# Add any paths that contain templates here, relative to this directory.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ dependencies = [
"opentelemetry-proto == 1.44.0.dev",
"opentelemetry-sdk ~= 1.44.0.dev",
"opentelemetry-exporter-otlp-proto-common == 1.44.0.dev",
"requests ~= 2.7",
"opentelemetry-exporter-otlp-common == 0.65b0.dev",
"opentelemetry-exporter-http-transport[urllib3] == 0.65b0.dev",
"typing-extensions >= 4.5.0",
]

Expand All @@ -52,6 +53,10 @@ Repository = "https://github.com/open-telemetry/opentelemetry-python"
gcp-auth = [
"opentelemetry-exporter-credential-provider-gcp >= 0.59b0",
]
requests = [
"requests ~= 2.7",
"opentelemetry-exporter-http-transport[requests] == 0.65b0.dev",
]

[tool.hatch.version]
path = "src/opentelemetry/exporter/otlp/proto/http/version/__init__.py"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,36 +1,65 @@
# Copyright The OpenTelemetry Authors
# SPDX-License-Identifier: Apache-2.0

from os import environ
from typing import Literal
from __future__ import annotations

import requests
import logging
import os
from collections.abc import Mapping
from os import environ
from typing import TYPE_CHECKING, Literal

from opentelemetry.exporter.http.transport._requests import (
RequestsHTTPTransport,
)
from opentelemetry.exporter.http.transport._urllib3 import (
Urllib3HTTPTransport,
)
from opentelemetry.exporter.otlp.common import _http
from opentelemetry.exporter.otlp.proto.http import (
_OTLP_HTTP_HEADERS,
Compression,
)
from opentelemetry.sdk.environment_variables import (
_OTEL_PYTHON_EXPORTER_OTLP_HTTP_CREDENTIAL_PROVIDER,
OTEL_EXPORTER_OTLP_CERTIFICATE,
OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE,
OTEL_EXPORTER_OTLP_CLIENT_KEY,
OTEL_EXPORTER_OTLP_COMPRESSION,
OTEL_EXPORTER_OTLP_ENDPOINT,
OTEL_EXPORTER_OTLP_HEADERS,
OTEL_EXPORTER_OTLP_TIMEOUT,
)
from opentelemetry.util._importlib_metadata import entry_points
from opentelemetry.util.re import parse_env_headers

if TYPE_CHECKING:
import requests

def _is_retryable(resp: requests.Response) -> bool:
if resp.status_code == 408:
return True
if resp.status_code >= 500 and resp.status_code <= 599:
return True
return False

from opentelemetry.exporter.http.transport._base import BaseHTTPTransport

def _load_session_from_envvar(
cred_envvar: Literal[
_CredentialEnvVar = Literal[
"OTEL_PYTHON_EXPORTER_OTLP_HTTP_LOGS_CREDENTIAL_PROVIDER",
"OTEL_PYTHON_EXPORTER_OTLP_HTTP_TRACES_CREDENTIAL_PROVIDER",
"OTEL_PYTHON_EXPORTER_OTLP_HTTP_METRICS_CREDENTIAL_PROVIDER",
],
]

_logger = logging.getLogger(__name__)

_DEFAULT_ENDPOINT = "http://localhost:4318"
_DEFAULT_TIMEOUT = 10


def _load_session_from_envvar(
cred_envvar: _CredentialEnvVar,
) -> requests.Session | None:
_credential_env = environ.get(
_OTEL_PYTHON_EXPORTER_OTLP_HTTP_CREDENTIAL_PROVIDER
) or environ.get(cred_envvar)
if _credential_env:
# pylint: disable-next=import-outside-toplevel
import requests # noqa: PLC0415

Comment thread
herin049 marked this conversation as resolved.
Resolved
try:
maybe_session = next(
iter(
Expand All @@ -53,3 +82,126 @@ def _load_session_from_envvar(
f" must be of type `requests.Session`."
)
return None


def _normalize_compression(
compression: Compression | _http.Compression | None,
) -> _http.Compression | None:
match compression:
case Compression.NoCompression:
return _http.Compression.NONE
case Compression.Deflate:
return _http.Compression.DEFLATE
case Compression.Gzip:
return _http.Compression.GZIP
case _:
return compression


def _resolve_endpoint(
endpoint_env_var: str,
default_path: Literal["v1/traces", "v1/metrics", "v1/logs"],
) -> str:
if endpoint := os.environ.get(endpoint_env_var):
return endpoint

base_endpoint = (
os.environ.get(OTEL_EXPORTER_OTLP_ENDPOINT) or _DEFAULT_ENDPOINT
)

return f"{base_endpoint.removesuffix('/')}/{default_path}"


def _resolve_headers(
headers: Mapping[str, str] | None,
headers_env_var: str,
) -> dict[str, str]:
headers_ = {k.lower(): v for k, v in _OTLP_HTTP_HEADERS.items()}
env_headers = parse_env_headers(
os.environ.get(headers_env_var)
or os.environ.get(OTEL_EXPORTER_OTLP_HEADERS, ""),
liberal=True,
)
headers_.update(env_headers)
if headers:
headers_.update({key.lower(): value for key, value in headers.items()})
return headers_


def _resolve_timeout(
timeout_env_var: str,
) -> float:
raw = (
os.environ.get(timeout_env_var)
or os.environ.get(OTEL_EXPORTER_OTLP_TIMEOUT)
or _DEFAULT_TIMEOUT
)

try:
return float(raw)
except ValueError:
_logger.warning(
"Invalid timeout value %r, using default of %s seconds",
raw,
_DEFAULT_TIMEOUT,
)
return float(_DEFAULT_TIMEOUT)


def _resolve_compression(compression_env_var: str) -> _http.Compression:
value = (
(
os.environ.get(compression_env_var)
or os.environ.get(OTEL_EXPORTER_OTLP_COMPRESSION)
or "none"
)
.lower()
.strip()
)

try:
return _http.Compression.from_str(value)
except ValueError:
_logger.warning("Unsupported compression type: %s", value)
return _http.Compression.NONE


def _build_transport(
certificate_file: str | bool | None,
client_key_file: str | None,
client_certificate_file: str | None,
certificate_env_var: str,
client_key_env_var: str,
client_certificate_env_var: str,
session: requests.Session | None,
) -> BaseHTTPTransport:
verify: bool | str
if certificate_file is None:
verify = (
os.environ.get(certificate_env_var)
or os.environ.get(OTEL_EXPORTER_OTLP_CERTIFICATE)
or True
)
else:
verify = certificate_file
client_key_file = (
client_key_file
or os.environ.get(client_key_env_var)
or os.environ.get(OTEL_EXPORTER_OTLP_CLIENT_KEY)
)
client_certificate_file = (
client_certificate_file
or os.environ.get(client_certificate_env_var)
or os.environ.get(OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE)
)
cert = (
(client_certificate_file, client_key_file)
if client_certificate_file and client_key_file
else client_certificate_file
)

return (
RequestsHTTPTransport(verify=verify, cert=cert, session=session)
if session
else Urllib3HTTPTransport(verify=verify, cert=cert)
Comment thread
lzchen marked this conversation as resolved.
Resolved
)
Loading
Loading