Skip to content

Commit d31d1cc

Browse files
committed
fix: error raised for env checks in LogLimits and SpanLimits
Current implementation raises a value error trying to create the error message. Updated error message format to use positional instead of named params. Added test cases to validate the correct errors are raised.
1 parent 1bd9ec6 commit d31d1cc

File tree

8 files changed

+105
-8
lines changed

8 files changed

+105
-8
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1414
([#4402](https://github.com/open-telemetry/opentelemetry-python/pull/4402))
1515
- Tolerates exceptions when loading resource detectors via `OTEL_EXPERIMENTAL_RESOURCE_DETECTORS`
1616
([#4373](https://github.com/open-telemetry/opentelemetry-python/pull/4373))
17+
- Disconnect gRPC client stub when shutting down `OTLPSpanExporter`
18+
([#4370](https://github.com/open-telemetry/opentelemetry-python/pull/4370))
1719
- opentelemetry-sdk: fix OTLP exporting of Histograms with explicit buckets advisory
1820
([#4434](https://github.com/open-telemetry/opentelemetry-python/pull/4434))
1921
- opentelemetry-exporter-otlp-proto-grpc: better dependency version range for Python 3.13
@@ -24,6 +26,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2426
([#4448](https://github.com/open-telemetry/opentelemetry-python/pull/4448))
2527
- Make `trace_api.use_span()` record `BaseException` as well as `Exception`
2628
([#4406](https://github.com/open-telemetry/opentelemetry-python/pull/4406))
29+
- Fix env var error message for TraceLimits/SpanLimits
30+
([#4458](https://github.com/open-telemetry/opentelemetry-python/pull/4458))
2731

2832
## Version 1.30.0/0.51b0 (2025-02-03)
2933

exporter/opentelemetry-exporter-otlp-proto-grpc/src/opentelemetry/exporter/otlp/proto/grpc/exporter.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -243,8 +243,8 @@ def __init__(
243243
) or Compression.NoCompression
244244

245245
if insecure:
246-
self._client = self._stub(
247-
insecure_channel(self._endpoint, compression=compression)
246+
self._channel = insecure_channel(
247+
self._endpoint, compression=compression
248248
)
249249
else:
250250
credentials = _get_credentials(
@@ -253,11 +253,10 @@ def __init__(
253253
OTEL_EXPORTER_OTLP_CLIENT_KEY,
254254
OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE,
255255
)
256-
self._client = self._stub(
257-
secure_channel(
258-
self._endpoint, credentials, compression=compression
259-
)
256+
self._channel = secure_channel(
257+
self._endpoint, credentials, compression=compression
260258
)
259+
self._client = self._stub(self._channel)
261260

262261
self._export_lock = threading.Lock()
263262
self._shutdown = False
@@ -360,6 +359,7 @@ def shutdown(self, timeout_millis: float = 30_000, **kwargs) -> None:
360359
# wait for the last export if any
361360
self._export_lock.acquire(timeout=timeout_millis / 1e3)
362361
self._shutdown = True
362+
self._channel.close()
363363
self._export_lock.release()
364364

365365
@property

exporter/opentelemetry-exporter-otlp-proto-grpc/tests/test_otlp_metrics_exporter.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -874,6 +874,21 @@ def test_shutdown_wait_last_export(self):
874874
finally:
875875
export_thread.join()
876876

877+
def test_export_over_closed_grpc_channel(self):
878+
# pylint: disable=protected-access
879+
880+
add_MetricsServiceServicer_to_server(
881+
MetricsServiceServicerSUCCESS(), self.server
882+
)
883+
self.exporter.export(self.metrics["sum_int"])
884+
self.exporter.shutdown()
885+
data = self.exporter._translate_data(self.metrics["sum_int"])
886+
with self.assertRaises(ValueError) as err:
887+
self.exporter._client.Export(request=data)
888+
self.assertEqual(
889+
str(err.exception), "Cannot invoke RPC on closed channel!"
890+
)
891+
877892
def test_aggregation_temporality(self):
878893
# pylint: disable=protected-access
879894

exporter/opentelemetry-exporter-otlp-proto-grpc/tests/test_otlp_trace_exporter.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1017,6 +1017,21 @@ def test_shutdown_wait_last_export(self):
10171017
finally:
10181018
export_thread.join()
10191019

1020+
def test_export_over_closed_grpc_channel(self):
1021+
# pylint: disable=protected-access
1022+
1023+
add_TraceServiceServicer_to_server(
1024+
TraceServiceServicerSUCCESS(), self.server
1025+
)
1026+
self.exporter.export([self.span])
1027+
self.exporter.shutdown()
1028+
data = self.exporter._translate_data([self.span])
1029+
with self.assertRaises(ValueError) as err:
1030+
self.exporter._client.Export(request=data)
1031+
self.assertEqual(
1032+
str(err.exception), "Cannot invoke RPC on closed channel!"
1033+
)
1034+
10201035

10211036
def _create_span_with_status(status: SDKStatus):
10221037
span = _Span(

opentelemetry-sdk/src/opentelemetry/sdk/_logs/_internal/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ def _from_env_if_absent(
134134
if value == cls.UNSET:
135135
return None
136136

137-
err_msg = "{0} must be a non-negative integer but got {}"
137+
err_msg = "{} must be a non-negative integer but got {}"
138138

139139
# if no value is provided for the limit, try to load it from env
140140
if value is None:

opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -692,7 +692,7 @@ def _from_env_if_absent(
692692
if value == cls.UNSET:
693693
return None
694694

695-
err_msg = "{0} must be a non-negative integer but got {}"
695+
err_msg = "{} must be a non-negative integer but got {}"
696696

697697
# if no value is provided for the limit, try to load it from env
698698
if value is None:

opentelemetry-sdk/tests/logs/test_log_limits.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,16 @@
1313
# limitations under the License.
1414

1515
import unittest
16+
from unittest.mock import patch
1617

1718
from opentelemetry.sdk._logs import LogLimits
1819
from opentelemetry.sdk._logs._internal import (
1920
_DEFAULT_OTEL_ATTRIBUTE_COUNT_LIMIT,
2021
)
22+
from opentelemetry.sdk.environment_variables import (
23+
OTEL_ATTRIBUTE_COUNT_LIMIT,
24+
OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT,
25+
)
2126

2227

2328
class TestLogLimits(unittest.TestCase):
@@ -38,3 +43,30 @@ def test_log_limits_max_attribute_length(self):
3843
limits = LogLimits(max_attribute_length=1)
3944

4045
self.assertEqual(expected, limits.max_attribute_length)
46+
47+
def test_invalid_env_vars_raise(self):
48+
env_vars = [
49+
OTEL_ATTRIBUTE_COUNT_LIMIT,
50+
OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT,
51+
]
52+
53+
bad_values = ["bad", "-1"]
54+
test_cases = {
55+
env_var: bad_value
56+
for env_var in env_vars
57+
for bad_value in bad_values
58+
}
59+
60+
for env_var, bad_value in test_cases.items():
61+
with self.subTest(f"Testing {env_var}={bad_value}"):
62+
with self.assertRaises(ValueError) as error, patch.dict(
63+
"os.environ", {env_var: bad_value}, clear=True
64+
):
65+
LogLimits()
66+
67+
expected_msg = f"{env_var} must be a non-negative integer but got {bad_value}"
68+
self.assertEqual(
69+
expected_msg,
70+
str(error.exception),
71+
f"Unexpected error message for {env_var}={bad_value}",
72+
)

opentelemetry-sdk/tests/trace/test_trace.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2007,6 +2007,37 @@ def _test_span_no_limits(self, tracer):
20072007
for attr_val in root.attributes.values():
20082008
self.assertEqual(attr_val, self.long_val)
20092009

2010+
def test_invalid_env_vars_raise(self):
2011+
env_vars = [
2012+
OTEL_SPAN_EVENT_COUNT_LIMIT,
2013+
OTEL_SPAN_LINK_COUNT_LIMIT,
2014+
OTEL_ATTRIBUTE_COUNT_LIMIT,
2015+
OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT,
2016+
OTEL_EVENT_ATTRIBUTE_COUNT_LIMIT,
2017+
OTEL_LINK_ATTRIBUTE_COUNT_LIMIT,
2018+
OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT,
2019+
]
2020+
bad_values = ["bad", "-1"]
2021+
test_cases = {
2022+
env_var: bad_value
2023+
for env_var in env_vars
2024+
for bad_value in bad_values
2025+
}
2026+
2027+
for env_var, bad_value in test_cases.items():
2028+
with self.subTest(f"Testing {env_var}={bad_value}"):
2029+
with self.assertRaises(ValueError) as error, patch.dict(
2030+
"os.environ", {env_var: bad_value}, clear=True
2031+
):
2032+
trace.SpanLimits()
2033+
2034+
expected_msg = f"{env_var} must be a non-negative integer but got {bad_value}"
2035+
self.assertEqual(
2036+
expected_msg,
2037+
str(error.exception),
2038+
f"Unexpected error message for {env_var}={bad_value}",
2039+
)
2040+
20102041

20112042
class TestTraceFlags(unittest.TestCase):
20122043
def test_constant_default(self):

0 commit comments

Comments
 (0)