Skip to content

Commit bc8e670

Browse files
brettimusBrett Beutell
authored and
Brett Beutell
committed
Merge branch 'main' into export-nonmonotonic-sums-as-gauges-in-prometheus
2 parents 8334dd6 + 5ec5064 commit bc8e670

File tree

14 files changed

+94
-73
lines changed

14 files changed

+94
-73
lines changed

CHANGELOG.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99

1010
- Modify Prometheus exporter to translate non-monotonic Sums into Gauges
1111
([#3306](https://github.com/open-telemetry/opentelemetry-python/pull/3306))
12-
- Use BoundedAttributes instead of raw dict to extract attributes from LogRecord and Support dropped_attributes_count in LogRecord
13-
([#3310](https://github.com/open-telemetry/opentelemetry-python/pull/3310))
12+
- Add max_scale option to Exponential Bucket Histogram Aggregation [#3323](https://github.com/open-telemetry/opentelemetry-python/pull/3323))
13+
- Use BoundedAttributes instead of raw dict to extract attributes from LogRecord and Support dropped_attributes_count in LogRecord ([#3310](https://github.com/open-telemetry/opentelemetry-python/pull/3310))
1414

1515
## Version 1.18.0/0.39b0 (2023-05-04)
1616

dev-requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,5 @@ mypy-protobuf~=3.0.0
2222
markupsafe==2.0.1
2323
bleach==4.1.0 # This dependency was updated to a breaking version.
2424
codespell==2.1.0
25-
requests==2.28.1
25+
requests==2.31.0
2626
ruamel.yaml==0.17.21

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,12 @@ def _translate_data(
107107
def export(self, batch: Sequence[LogData]) -> LogExportResult:
108108
return self._export(batch)
109109

110-
def shutdown(self) -> None:
111-
pass
110+
def shutdown(self, timeout_millis: float = 30_000, **kwargs) -> None:
111+
OTLPExporterMixin.shutdown(self, timeout_millis=timeout_millis)
112+
113+
def force_flush(self, timeout_millis: float = 10_000) -> bool:
114+
"""Nothing is buffered in this exporter, so this method does nothing."""
115+
return True
112116

113117
@property
114118
def _exporting(self) -> str:

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

Lines changed: 12 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,20 @@
1616

1717
import threading
1818
from abc import ABC, abstractmethod
19-
from collections.abc import Sequence
19+
from collections.abc import Sequence # noqa: F401
2020
from logging import getLogger
2121
from os import environ
2222
from time import sleep
23-
from typing import Any, Callable, Dict, Generic, List, Optional, Tuple, Union
23+
from typing import ( # noqa: F401
24+
Any,
25+
Callable,
26+
Dict,
27+
Generic,
28+
List,
29+
Optional,
30+
Tuple,
31+
Union,
32+
)
2433
from typing import Sequence as TypingSequence
2534
from typing import TypeVar
2635
from urllib.parse import urlparse
@@ -45,7 +54,7 @@
4554
from opentelemetry.exporter.otlp.proto.grpc import (
4655
_OTLP_GRPC_HEADERS,
4756
)
48-
from opentelemetry.proto.common.v1.common_pb2 import (
57+
from opentelemetry.proto.common.v1.common_pb2 import ( # noqa: F401
4958
AnyValue,
5059
ArrayValue,
5160
KeyValue,
@@ -97,44 +106,6 @@ def environ_to_compression(environ_key: str) -> Optional[Compression]:
97106
return _ENVIRON_TO_COMPRESSION[environ_value]
98107

99108

100-
def _translate_value(value: Any) -> KeyValue:
101-
if isinstance(value, bool):
102-
any_value = AnyValue(bool_value=value)
103-
104-
elif isinstance(value, str):
105-
any_value = AnyValue(string_value=value)
106-
107-
elif isinstance(value, int):
108-
any_value = AnyValue(int_value=value)
109-
110-
elif isinstance(value, float):
111-
any_value = AnyValue(double_value=value)
112-
113-
elif isinstance(value, Sequence):
114-
any_value = AnyValue(
115-
array_value=ArrayValue(values=[_translate_value(v) for v in value])
116-
)
117-
118-
# Tracing specs currently does not support Mapping type attributes
119-
# elif isinstance(value, Mapping):
120-
# any_value = AnyValue(
121-
# kvlist_value=KeyValueList(
122-
# values=[
123-
# _translate_key_values(str(k), v) for k, v in value.items()
124-
# ]
125-
# )
126-
# )
127-
128-
else:
129-
raise Exception(f"Invalid type {type(value)} of value {value}")
130-
131-
return any_value
132-
133-
134-
def _translate_key_values(key: str, value: Any) -> KeyValue:
135-
return KeyValue(key=key, value=_translate_value(value))
136-
137-
138109
@deprecated(
139110
version="1.18.0",
140111
reason="Use one of the encoders from opentelemetry-exporter-otlp-proto-common instead",
@@ -271,17 +242,6 @@ def _translate_data(
271242
) -> ExportServiceRequestT:
272243
pass
273244

274-
def _translate_attributes(self, attributes) -> TypingSequence[KeyValue]:
275-
output = []
276-
if attributes:
277-
278-
for key, value in attributes.items():
279-
try:
280-
output.append(_translate_key_values(key, value))
281-
except Exception as error: # pylint: disable=broad-except
282-
logger.exception(error)
283-
return output
284-
285245
def _export(
286246
self, data: Union[TypingSequence[ReadableSpan], MetricsData]
287247
) -> ExportResultT:

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,4 +258,5 @@ def _exporting(self) -> str:
258258
return "metrics"
259259

260260
def force_flush(self, timeout_millis: float = 10_000) -> bool:
261+
"""Nothing is buffered in this exporter, so this method does nothing."""
261262
return True

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ def shutdown(self) -> None:
144144
OTLPExporterMixin.shutdown(self)
145145

146146
def force_flush(self, timeout_millis: int = 30000) -> bool:
147+
"""Nothing is buffered in this exporter, so this method does nothing."""
147148
return True
148149

149150
@property

exporter/opentelemetry-exporter-otlp-proto-grpc/tests/logs/test_otlp_logs_exporter.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,10 @@
2323
from grpc import ChannelCredentials, Compression, StatusCode, server
2424

2525
from opentelemetry._logs import SeverityNumber
26+
from opentelemetry.exporter.otlp.proto.common._internal import _encode_value
2627
from opentelemetry.exporter.otlp.proto.grpc._log_exporter import (
2728
OTLPLogExporter,
2829
)
29-
from opentelemetry.exporter.otlp.proto.grpc.exporter import _translate_value
3030
from opentelemetry.exporter.otlp.proto.grpc.version import __version__
3131
from opentelemetry.proto.collector.logs.v1.logs_service_pb2 import (
3232
ExportLogsServiceRequest,
@@ -367,7 +367,7 @@ def test_translate_log_data(self):
367367
16,
368368
"big",
369369
),
370-
body=_translate_value(
370+
body=_encode_value(
371371
"Zhengzhou, We have a heaviest rains in 1000 years"
372372
),
373373
attributes=[
@@ -426,7 +426,7 @@ def test_translate_multiple_logs(self):
426426
16,
427427
"big",
428428
),
429-
body=_translate_value(
429+
body=_encode_value(
430430
"Zhengzhou, We have a heaviest rains in 1000 years"
431431
),
432432
attributes=[
@@ -463,13 +463,13 @@ def test_translate_multiple_logs(self):
463463
16,
464464
"big",
465465
),
466-
body=_translate_value(
466+
body=_encode_value(
467467
"Sydney, Opera House is closed"
468468
),
469469
attributes=[
470470
KeyValue(
471471
key="custom_attr",
472-
value=_translate_value([1, 2, 3]),
472+
value=_encode_value([1, 2, 3]),
473473
),
474474
],
475475
flags=int(
@@ -508,7 +508,7 @@ def test_translate_multiple_logs(self):
508508
16,
509509
"big",
510510
),
511-
body=_translate_value(
511+
body=_encode_value(
512512
"Mumbai, Boil water before drinking"
513513
),
514514
attributes=[],

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -746,6 +746,7 @@ def test_shutdown(self):
746746
warning.records[0].message,
747747
"Exporter already shutdown, ignoring batch",
748748
)
749+
self.exporter = OTLPMetricExporter()
749750

750751
def test_shutdown_wait_last_export(self):
751752
add_MetricsServiceServicer_to_server(

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

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,10 @@
2626
from grpc import ChannelCredentials, Compression, StatusCode, server
2727

2828
from opentelemetry.attributes import BoundedAttributes
29-
from opentelemetry.exporter.otlp.proto.grpc.exporter import (
30-
_is_backoff_v2,
31-
_translate_key_values,
29+
from opentelemetry.exporter.otlp.proto.common._internal import (
30+
_encode_key_value,
3231
)
32+
from opentelemetry.exporter.otlp.proto.grpc.exporter import _is_backoff_v2
3333
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import (
3434
OTLPSpanExporter,
3535
)
@@ -840,31 +840,31 @@ def test_span_status_translate(self):
840840

841841
# pylint:disable=no-member
842842
def test_translate_key_values(self):
843-
bool_value = _translate_key_values("bool_type", False)
843+
bool_value = _encode_key_value("bool_type", False)
844844
self.assertTrue(isinstance(bool_value, KeyValue))
845845
self.assertEqual(bool_value.key, "bool_type")
846846
self.assertTrue(isinstance(bool_value.value, AnyValue))
847847
self.assertFalse(bool_value.value.bool_value)
848848

849-
str_value = _translate_key_values("str_type", "str")
849+
str_value = _encode_key_value("str_type", "str")
850850
self.assertTrue(isinstance(str_value, KeyValue))
851851
self.assertEqual(str_value.key, "str_type")
852852
self.assertTrue(isinstance(str_value.value, AnyValue))
853853
self.assertEqual(str_value.value.string_value, "str")
854854

855-
int_value = _translate_key_values("int_type", 2)
855+
int_value = _encode_key_value("int_type", 2)
856856
self.assertTrue(isinstance(int_value, KeyValue))
857857
self.assertEqual(int_value.key, "int_type")
858858
self.assertTrue(isinstance(int_value.value, AnyValue))
859859
self.assertEqual(int_value.value.int_value, 2)
860860

861-
double_value = _translate_key_values("double_type", 3.2)
861+
double_value = _encode_key_value("double_type", 3.2)
862862
self.assertTrue(isinstance(double_value, KeyValue))
863863
self.assertEqual(double_value.key, "double_type")
864864
self.assertTrue(isinstance(double_value.value, AnyValue))
865865
self.assertEqual(double_value.value.double_value, 3.2)
866866

867-
seq_value = _translate_key_values("seq_type", ["asd", "123"])
867+
seq_value = _encode_key_value("seq_type", ["asd", "123"])
868868
self.assertTrue(isinstance(seq_value, KeyValue))
869869
self.assertEqual(seq_value.key, "seq_type")
870870
self.assertTrue(isinstance(seq_value.value, AnyValue))

exporter/opentelemetry-exporter-otlp-proto-http/src/opentelemetry/exporter/otlp/proto/http/_log_exporter/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,10 @@ def export(self, batch: Sequence[LogData]) -> LogExportResult:
173173
return LogExportResult.FAILURE
174174
return LogExportResult.FAILURE
175175

176+
def force_flush(self, timeout_millis: float = 10_000) -> bool:
177+
"""Nothing is buffered in this exporter, so this method does nothing."""
178+
return True
179+
176180
def shutdown(self):
177181
if self._shutdown:
178182
_logger.warning("Exporter already shutdown, ignoring call")

exporter/opentelemetry-exporter-otlp-proto-http/src/opentelemetry/exporter/otlp/proto/http/metric_exporter/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@ def _exporting(self) -> str:
215215
return "metrics"
216216

217217
def force_flush(self, timeout_millis: float = 10_000) -> bool:
218+
"""Nothing is buffered in this exporter, so this method does nothing."""
218219
return True
219220

220221

exporter/opentelemetry-exporter-otlp-proto-http/src/opentelemetry/exporter/otlp/proto/http/trace_exporter/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ def shutdown(self):
179179
self._shutdown = True
180180

181181
def force_flush(self, timeout_millis: int = 30000) -> bool:
182+
"""Nothing is buffered in this exporter, so this method does nothing."""
182183
return True
183184

184185

opentelemetry-sdk/src/opentelemetry/sdk/metrics/_internal/aggregation.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,7 @@ def __init__(
386386
# See the derivation here:
387387
# https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk.md#exponential-bucket-histogram-aggregation)
388388
max_size: int = 160,
389+
max_scale: int = 20,
389390
):
390391
super().__init__(attributes)
391392
# max_size is the maximum capacity of the positive and negative
@@ -403,6 +404,7 @@ def __init__(
403404
)
404405

405406
self._max_size = max_size
407+
self._max_scale = max_scale
406408

407409
# _sum is the sum of all the values aggregated by this aggregator.
408410
self._sum = 0
@@ -428,7 +430,14 @@ def __init__(
428430

429431
# _mapping corresponds to the current scale, is shared by both the
430432
# positive and negative buckets.
431-
self._mapping = LogarithmMapping(LogarithmMapping._max_scale)
433+
434+
if self._max_scale > 20:
435+
_logger.warning(
436+
"max_scale is set to %s which is "
437+
"larger than the recommended value of 20",
438+
self._max_scale,
439+
)
440+
self._mapping = LogarithmMapping(self._max_scale)
432441

433442
self._instrument_temporality = AggregationTemporality.DELTA
434443
self._start_time_unix_nano = start_time_unix_nano
@@ -941,9 +950,10 @@ class ExponentialBucketHistogramAggregation(Aggregation):
941950
def __init__(
942951
self,
943952
max_size: int = 160,
953+
max_scale: int = 20,
944954
):
945-
946955
self._max_size = max_size
956+
self._max_scale = max_scale
947957

948958
def _create_aggregation(
949959
self,
@@ -955,6 +965,7 @@ def _create_aggregation(
955965
attributes,
956966
start_time_unix_nano,
957967
max_size=self._max_size,
968+
max_scale=self._max_scale,
958969
)
959970

960971

opentelemetry-sdk/tests/metrics/exponential_histogram/test_exponential_bucket_histogram_aggregation.py

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

1515
from itertools import permutations
16+
from logging import WARNING
1617
from math import ldexp
1718
from sys import float_info
1819
from types import MethodType
@@ -37,6 +38,9 @@
3738
LogarithmMapping,
3839
)
3940
from opentelemetry.sdk.metrics._internal.measurement import Measurement
41+
from opentelemetry.sdk.metrics.view import (
42+
ExponentialBucketHistogramAggregation,
43+
)
4044

4145

4246
def get_counts(buckets: Buckets) -> int:
@@ -77,6 +81,39 @@ def swap(
7781

7882

7983
class TestExponentialBucketHistogramAggregation(TestCase):
84+
@patch("opentelemetry.sdk.metrics._internal.aggregation.LogarithmMapping")
85+
def test_create_aggregation(self, mock_logarithm_mapping):
86+
exponential_bucket_histogram_aggregation = (
87+
ExponentialBucketHistogramAggregation()
88+
)._create_aggregation(Mock(), Mock(), Mock())
89+
90+
self.assertEqual(
91+
exponential_bucket_histogram_aggregation._max_scale, 20
92+
)
93+
94+
mock_logarithm_mapping.assert_called_with(20)
95+
96+
exponential_bucket_histogram_aggregation = (
97+
ExponentialBucketHistogramAggregation(max_scale=10)
98+
)._create_aggregation(Mock(), Mock(), Mock())
99+
100+
self.assertEqual(
101+
exponential_bucket_histogram_aggregation._max_scale, 10
102+
)
103+
104+
mock_logarithm_mapping.assert_called_with(10)
105+
106+
with self.assertLogs(level=WARNING):
107+
exponential_bucket_histogram_aggregation = (
108+
ExponentialBucketHistogramAggregation(max_scale=100)
109+
)._create_aggregation(Mock(), Mock(), Mock())
110+
111+
self.assertEqual(
112+
exponential_bucket_histogram_aggregation._max_scale, 100
113+
)
114+
115+
mock_logarithm_mapping.assert_called_with(100)
116+
80117
def assertInEpsilon(self, first, second, epsilon):
81118
self.assertLessEqual(first, (second * (1 + epsilon)))
82119
self.assertGreaterEqual(first, (second * (1 - epsilon)))

0 commit comments

Comments
 (0)