diff --git a/.changelog/5705.fixed b/.changelog/5705.fixed new file mode 100644 index 00000000000..6165ab0a5b8 --- /dev/null +++ b/.changelog/5705.fixed @@ -0,0 +1 @@ +`opentelemetry-exporter-prometheus`: warn and fall back to the default port instead of raising `ValueError` when `OTEL_EXPORTER_PROMETHEUS_PORT` holds a non-integer value in the auto-configured metric reader. diff --git a/exporter/opentelemetry-exporter-prometheus/src/opentelemetry/exporter/prometheus/__init__.py b/exporter/opentelemetry-exporter-prometheus/src/opentelemetry/exporter/prometheus/__init__.py index 0fef403b90a..a709e875542 100644 --- a/exporter/opentelemetry-exporter-prometheus/src/opentelemetry/exporter/prometheus/__init__.py +++ b/exporter/opentelemetry-exporter-prometheus/src/opentelemetry/exporter/prometheus/__init__.py @@ -113,6 +113,32 @@ _TARGET_INFO_NAME = "target" _TARGET_INFO_DESCRIPTION = "Target metadata" +_DEFAULT_PORT = 9464 + + +def _port_from_env() -> int: + """Return ``OTEL_EXPORTER_PROMETHEUS_PORT`` as an int, defaulting to + ``_DEFAULT_PORT`` when the variable is unset, empty, or not an integer. + + An invalid value is logged and ignored instead of raising, mirroring the + OTLP/Zipkin exporters so a malformed environment variable cannot take + auto-instrumentation startup down. + """ + raw = environ.get(OTEL_EXPORTER_PROMETHEUS_PORT) + if raw is None or not raw.strip(): + return _DEFAULT_PORT + try: + return int(raw) + except ValueError: + _logger.warning( + "Invalid value %r for %s, using default port %s", + raw, + OTEL_EXPORTER_PROMETHEUS_PORT, + _DEFAULT_PORT, + ) + return _DEFAULT_PORT + + _OTEL_SCOPE_NAME_LABEL = "otel_scope_name" _OTEL_SCOPE_VERSION_LABEL = "otel_scope_version" _OTEL_SCOPE_SCHEMA_URL_LABEL = "otel_scope_schema_url" @@ -518,6 +544,6 @@ def __init__(self) -> None: # Default values are specified in # https://github.com/open-telemetry/opentelemetry-specification/blob/v1.24.0/specification/configuration/sdk-environment-variables.md#prometheus-exporter start_http_server( - port=int(environ.get(OTEL_EXPORTER_PROMETHEUS_PORT, "9464")), + port=_port_from_env(), addr=environ.get(OTEL_EXPORTER_PROMETHEUS_HOST, "localhost"), ) diff --git a/exporter/opentelemetry-exporter-prometheus/tests/test_entrypoints.py b/exporter/opentelemetry-exporter-prometheus/tests/test_entrypoints.py index 9eb7e037e3b..af00a4dedb1 100644 --- a/exporter/opentelemetry-exporter-prometheus/tests/test_entrypoints.py +++ b/exporter/opentelemetry-exporter-prometheus/tests/test_entrypoints.py @@ -52,3 +52,21 @@ def test_starts_http_server_host_envvar(self, mock_start_http_server: Mock) -> N def test_starts_http_server_port_envvar(self, mock_start_http_server: Mock) -> None: _AutoPrometheusMetricReader() mock_start_http_server.assert_called_once_with(port=9999, addr=ANY) + + @patch("opentelemetry.exporter.prometheus.start_http_server") + @patch.dict(os.environ, {OTEL_EXPORTER_PROMETHEUS_PORT: "9464abc"}, clear=False) + def test_starts_http_server_invalid_port_envvar_falls_back(self, mock_start_http_server: Mock) -> None: + with self.assertLogs("opentelemetry.exporter.prometheus", level="WARNING") as cm: + _AutoPrometheusMetricReader() + + mock_start_http_server.assert_called_once_with(port=9464, addr=ANY) + self.assertTrue( + any("Invalid value" in message for message in cm.output), + cm.output, + ) + + @patch("opentelemetry.exporter.prometheus.start_http_server") + @patch.dict(os.environ, {OTEL_EXPORTER_PROMETHEUS_PORT: ""}, clear=False) + def test_starts_http_server_empty_port_envvar_falls_back(self, mock_start_http_server: Mock) -> None: + _AutoPrometheusMetricReader() + mock_start_http_server.assert_called_once_with(port=9464, addr=ANY)