diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 2dacdd6b05..651b13ab55 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,7 +10,7 @@ env: # Otherwise, set variable to the commit of your branch on # opentelemetry-python-contrib which is compatible with these Core repo # changes. - CONTRIB_REPO_SHA: 9a7c2f7ba16669d00be273aa9e988af0df7aba4c + CONTRIB_REPO_SHA: 3c2788469834aa4f5976e1644d757f43d60bc219 # This is needed because we do not clone the core repo in contrib builds anymore. # When running contrib builds as part of core builds, we use actions/checkout@v2 which # does not set an environment variable (simply just runs tox), which is different when @@ -176,7 +176,7 @@ jobs: - "tornado" - "tortoiseorm" - "urllib" - - "urllib3v" + - "urllib3" - "wsgi" - "prometheus-remote-write" - "richconsole" diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d4a7add3c..122c50334a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +- Add to_json method to ExponentialHistogram + ([#3780](https://github.com/open-telemetry/opentelemetry-python/pull/3780)) +- Bump mypy to 1.9.0 + ([#3795](https://github.com/open-telemetry/opentelemetry-python/pull/3795)) +- Fix exponential histograms + ([#3798](https://github.com/open-telemetry/opentelemetry-python/pull/3798)) +- Fix otlp exporter to export log_record.observed_timestamp + ([#3785](https://github.com/open-telemetry/opentelemetry-python/pull/3785)) + +## Version 1.24.0/0.45b0 (2024-03-28) + +- Make create_gauge non-abstract method + ([#3817](https://github.com/open-telemetry/opentelemetry-python/pull/3817)) - Make `tracer.start_as_current_span()` decorator work with async functions ([#3633](https://github.com/open-telemetry/opentelemetry-python/pull/3633)) - Fix python 3.12 deprecation warning @@ -17,6 +30,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ([#3648](https://github.com/open-telemetry/opentelemetry-python/pull/3648)) - Fix ValueError message for PeriodicExportingMetricsReader ([#3769](https://github.com/open-telemetry/opentelemetry-python/pull/3769)) +- Use `BaseException` instead of `Exception` in `record_exception` + ([#3354](https://github.com/open-telemetry/opentelemetry-python/pull/3354)) - Make span.record_exception more robust ([#3778](https://github.com/open-telemetry/opentelemetry-python/pull/3778)) - Fix license field in pyproject.toml files @@ -1496,3 +1511,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Remove dependency on 'backoff' library ([#3679](https://github.com/open-telemetry/opentelemetry-python/pull/3679)) + +- Make create_gauge non-abstract method + ([#3817](https://github.com/open-telemetry/opentelemetry-python/pull/3817)) +- Make `tracer.start_as_current_span()` decorator work with async functions + ([#3633](https://github.com/open-telemetry/opentelemetry-python/pull/3633)) +- Fix python 3.12 deprecation warning + ([#3751](https://github.com/open-telemetry/opentelemetry-python/pull/3751)) +- bump mypy to 0.982 + ([#3776](https://github.com/open-telemetry/opentelemetry-python/pull/3776)) +- Add support for OTEL_SDK_DISABLED environment variable + ([#3648](https://github.com/open-telemetry/opentelemetry-python/pull/3648)) +- Fix ValueError message for PeriodicExportingMetricsReader + ([#3769](https://github.com/open-telemetry/opentelemetry-python/pull/3769)) +- Use `BaseException` instead of `Exception` in `record_exception` + ([#3354](https://github.com/open-telemetry/opentelemetry-python/pull/3354)) +- Make span.record_exception more robust + ([#3778](https://github.com/open-telemetry/opentelemetry-python/pull/3778)) +- Fix license field in pyproject.toml files + ([#3803](https://github.com/open-telemetry/opentelemetry-python/pull/3803)) + diff --git a/README.md b/README.md index c36a64062c..588b7ccb39 100644 --- a/README.md +++ b/README.md @@ -100,8 +100,12 @@ Approvers ([@open-telemetry/python-approvers](https://github.com/orgs/open-telem - [Aaron Abbott](https://github.com/aabmass), Google - [Jeremy Voss](https://github.com/jeremydvoss), Microsoft -- [Sanket Mehta](https://github.com/sanketmehta28), Cisco +- [Owais Lone](https://github.com/owais), Splunk +- [Pablo Collins](https://github.com/pmcollins), Splunk +- [Riccardo Magliocchetti](https://github.com/xrmx), Elastic - [Shalev Roda](https://github.com/shalevr), Cisco +- [Srikanth Chekuri](https://github.com/srikanthccv), signoz.io +- [Tammy Baylis](https://github.com/tammy-baylis-swi), SolarWinds Emeritus Approvers @@ -111,6 +115,8 @@ Emeritus Approvers - [Héctor Hernández](https://github.com/hectorhdzg), Microsoft - [Mauricio Vásquez](https://github.com/mauriciovasquezbernal), Kinvolk - [Nathaniel Ruiz Nowell](https://github.com/NathanielRN), AWS +- [Nikolay Sokolik](https://github.com/oxeye-nikolay), Oxeye +- [Sanket Mehta](https://github.com/sanketmehta28), Cisco - [Tahir H. Butt](https://github.com/majorgreys), DataDog *For more information about the approver role, see the [community repository](https://github.com/open-telemetry/community/blob/main/community-membership.md#approver).* diff --git a/dev-requirements.txt b/dev-requirements.txt index 15462dea50..01f46ae87e 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -3,7 +3,7 @@ flake8==6.1.0 isort==5.12.0 black==22.3.0 httpretty==1.1.4 -mypy==0.982 +mypy==1.9.0 sphinx==7.1.2 sphinx-rtd-theme==2.0.0rc4 sphinx-autodoc-typehints==1.25.2 diff --git a/eachdist.ini b/eachdist.ini index 7749b33a84..b7d73f192a 100644 --- a/eachdist.ini +++ b/eachdist.ini @@ -11,7 +11,7 @@ sortfirst= exporter/* [stable] -version=1.24.0.dev +version=1.25.0.dev packages= opentelemetry-sdk @@ -27,7 +27,7 @@ packages= opentelemetry-api [prerelease] -version=0.45b0.dev +version=0.46b0.dev packages= opentelemetry-opentracing-shim diff --git a/exporter/opentelemetry-exporter-opencensus/pyproject.toml b/exporter/opentelemetry-exporter-opencensus/pyproject.toml index fc2a8f2c2c..44ba08ebcb 100644 --- a/exporter/opentelemetry-exporter-opencensus/pyproject.toml +++ b/exporter/opentelemetry-exporter-opencensus/pyproject.toml @@ -27,7 +27,7 @@ classifiers = [ dependencies = [ "grpcio >= 1.0.0, < 2.0.0", "opencensus-proto >= 0.1.0, < 1.0.0", - "opentelemetry-api >= 1.24.0.dev", + "opentelemetry-api >= 1.25.0.dev", "opentelemetry-sdk >= 1.15", "protobuf ~= 3.13", "setuptools >= 16.0", diff --git a/exporter/opentelemetry-exporter-opencensus/src/opentelemetry/exporter/opencensus/version.py b/exporter/opentelemetry-exporter-opencensus/src/opentelemetry/exporter/opencensus/version.py index 2b23bc4994..ff4933b20b 100644 --- a/exporter/opentelemetry-exporter-opencensus/src/opentelemetry/exporter/opencensus/version.py +++ b/exporter/opentelemetry-exporter-opencensus/src/opentelemetry/exporter/opencensus/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.45b0.dev" +__version__ = "0.46b0.dev" diff --git a/exporter/opentelemetry-exporter-otlp-proto-common/pyproject.toml b/exporter/opentelemetry-exporter-otlp-proto-common/pyproject.toml index 3963d60c94..64e1b02c7a 100644 --- a/exporter/opentelemetry-exporter-otlp-proto-common/pyproject.toml +++ b/exporter/opentelemetry-exporter-otlp-proto-common/pyproject.toml @@ -24,7 +24,7 @@ classifiers = [ "Programming Language :: Python :: 3.11", ] dependencies = [ - "opentelemetry-proto == 1.24.0.dev", + "opentelemetry-proto == 1.25.0.dev", ] [project.urls] diff --git a/exporter/opentelemetry-exporter-otlp-proto-common/src/opentelemetry/exporter/otlp/proto/common/_internal/_log_encoder/__init__.py b/exporter/opentelemetry-exporter-otlp-proto-common/src/opentelemetry/exporter/otlp/proto/common/_internal/_log_encoder/__init__.py index c664e3ba88..4252ab7f13 100644 --- a/exporter/opentelemetry-exporter-otlp-proto-common/src/opentelemetry/exporter/otlp/proto/common/_internal/_log_encoder/__init__.py +++ b/exporter/opentelemetry-exporter-otlp-proto-common/src/opentelemetry/exporter/otlp/proto/common/_internal/_log_encoder/__init__.py @@ -41,6 +41,7 @@ def encode_logs(batch: Sequence[LogData]) -> ExportLogsServiceRequest: def _encode_log(log_data: LogData) -> PB2LogRecord: return PB2LogRecord( time_unix_nano=log_data.log_record.timestamp, + observed_time_unix_nano=log_data.log_record.observed_timestamp, span_id=_encode_span_id(log_data.log_record.span_id), trace_id=_encode_trace_id(log_data.log_record.trace_id), flags=int(log_data.log_record.trace_flags), diff --git a/exporter/opentelemetry-exporter-otlp-proto-common/src/opentelemetry/exporter/otlp/proto/common/version.py b/exporter/opentelemetry-exporter-otlp-proto-common/src/opentelemetry/exporter/otlp/proto/common/version.py index 8c35630f0e..e8b404f050 100644 --- a/exporter/opentelemetry-exporter-otlp-proto-common/src/opentelemetry/exporter/otlp/proto/common/version.py +++ b/exporter/opentelemetry-exporter-otlp-proto-common/src/opentelemetry/exporter/otlp/proto/common/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "1.24.0.dev" +__version__ = "1.25.0.dev" diff --git a/exporter/opentelemetry-exporter-otlp-proto-common/tests/test_log_encoder.py b/exporter/opentelemetry-exporter-otlp-proto-common/tests/test_log_encoder.py index 0731bc5125..58620b963e 100644 --- a/exporter/opentelemetry-exporter-otlp-proto-common/tests/test_log_encoder.py +++ b/exporter/opentelemetry-exporter-otlp-proto-common/tests/test_log_encoder.py @@ -69,6 +69,7 @@ def _get_sdk_log_data() -> List[LogData]: log1 = LogData( log_record=SDKLogRecord( timestamp=1644650195189786880, + observed_timestamp=1644650195189786881, trace_id=89564621134313219400156819398935297684, span_id=1312458408527513268, trace_flags=TraceFlags(0x01), @@ -89,6 +90,7 @@ def _get_sdk_log_data() -> List[LogData]: log2 = LogData( log_record=SDKLogRecord( timestamp=1644650249738562048, + observed_timestamp=1644650249738562049, trace_id=0, span_id=0, trace_flags=TraceFlags.DEFAULT, @@ -106,6 +108,7 @@ def _get_sdk_log_data() -> List[LogData]: log3 = LogData( log_record=SDKLogRecord( timestamp=1644650427658989056, + observed_timestamp=1644650427658989057, trace_id=271615924622795969659406376515024083555, span_id=4242561578944770265, trace_flags=TraceFlags(0x01), @@ -121,6 +124,7 @@ def _get_sdk_log_data() -> List[LogData]: log4 = LogData( log_record=SDKLogRecord( timestamp=1644650584292683008, + observed_timestamp=1644650584292683009, trace_id=212592107417388365804938480559624925555, span_id=6077757853989569223, trace_flags=TraceFlags(0x01), @@ -164,6 +168,7 @@ def get_test_logs( log_records=[ PB2LogRecord( time_unix_nano=1644650195189786880, + observed_time_unix_nano=1644650195189786881, trace_id=_encode_trace_id( 89564621134313219400156819398935297684 ), @@ -190,6 +195,7 @@ def get_test_logs( log_records=[ PB2LogRecord( time_unix_nano=1644650584292683008, + observed_time_unix_nano=1644650584292683009, trace_id=_encode_trace_id( 212592107417388365804938480559624925555 ), @@ -232,6 +238,7 @@ def get_test_logs( log_records=[ PB2LogRecord( time_unix_nano=1644650249738562048, + observed_time_unix_nano=1644650249738562049, trace_id=_encode_trace_id(0), span_id=_encode_span_id(0), flags=int(TraceFlags.DEFAULT), @@ -249,6 +256,7 @@ def get_test_logs( log_records=[ PB2LogRecord( time_unix_nano=1644650427658989056, + observed_time_unix_nano=1644650427658989057, trace_id=_encode_trace_id( 271615924622795969659406376515024083555 ), diff --git a/exporter/opentelemetry-exporter-otlp-proto-grpc/pyproject.toml b/exporter/opentelemetry-exporter-otlp-proto-grpc/pyproject.toml index a54c1e86e3..967dcebe94 100644 --- a/exporter/opentelemetry-exporter-otlp-proto-grpc/pyproject.toml +++ b/exporter/opentelemetry-exporter-otlp-proto-grpc/pyproject.toml @@ -28,9 +28,9 @@ dependencies = [ "googleapis-common-protos ~= 1.52", "grpcio >= 1.0.0, < 2.0.0", "opentelemetry-api ~= 1.15", - "opentelemetry-proto == 1.24.0.dev", - "opentelemetry-sdk ~= 1.24.0.dev", - "opentelemetry-exporter-otlp-proto-common == 1.24.0.dev", + "opentelemetry-proto == 1.25.0.dev", + "opentelemetry-sdk ~= 1.25.0.dev", + "opentelemetry-exporter-otlp-proto-common == 1.25.0.dev", ] [project.optional-dependencies] diff --git a/exporter/opentelemetry-exporter-otlp-proto-grpc/src/opentelemetry/exporter/otlp/proto/grpc/version.py b/exporter/opentelemetry-exporter-otlp-proto-grpc/src/opentelemetry/exporter/otlp/proto/grpc/version.py index 8c35630f0e..e8b404f050 100644 --- a/exporter/opentelemetry-exporter-otlp-proto-grpc/src/opentelemetry/exporter/otlp/proto/grpc/version.py +++ b/exporter/opentelemetry-exporter-otlp-proto-grpc/src/opentelemetry/exporter/otlp/proto/grpc/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "1.24.0.dev" +__version__ = "1.25.0.dev" diff --git a/exporter/opentelemetry-exporter-otlp-proto-grpc/tests/logs/test_otlp_logs_exporter.py b/exporter/opentelemetry-exporter-otlp-proto-grpc/tests/logs/test_otlp_logs_exporter.py index a6479a1474..be0c7e1b0f 100644 --- a/exporter/opentelemetry-exporter-otlp-proto-grpc/tests/logs/test_otlp_logs_exporter.py +++ b/exporter/opentelemetry-exporter-otlp-proto-grpc/tests/logs/test_otlp_logs_exporter.py @@ -361,6 +361,7 @@ def test_translate_log_data(self): PB2LogRecord( # pylint: disable=no-member time_unix_nano=self.log_data_1.log_record.timestamp, + observed_time_unix_nano=self.log_data_1.log_record.observed_timestamp, severity_number=self.log_data_1.log_record.severity_number.value, severity_text="WARNING", span_id=int.to_bytes( @@ -420,6 +421,7 @@ def test_translate_multiple_logs(self): PB2LogRecord( # pylint: disable=no-member time_unix_nano=self.log_data_1.log_record.timestamp, + observed_time_unix_nano=self.log_data_1.log_record.observed_timestamp, severity_number=self.log_data_1.log_record.severity_number.value, severity_text="WARNING", span_id=int.to_bytes( @@ -457,6 +459,7 @@ def test_translate_multiple_logs(self): PB2LogRecord( # pylint: disable=no-member time_unix_nano=self.log_data_2.log_record.timestamp, + observed_time_unix_nano=self.log_data_2.log_record.observed_timestamp, severity_number=self.log_data_2.log_record.severity_number.value, severity_text="INFO", span_id=int.to_bytes( @@ -502,6 +505,7 @@ def test_translate_multiple_logs(self): PB2LogRecord( # pylint: disable=no-member time_unix_nano=self.log_data_3.log_record.timestamp, + observed_time_unix_nano=self.log_data_3.log_record.observed_timestamp, severity_number=self.log_data_3.log_record.severity_number.value, severity_text="ERROR", span_id=int.to_bytes( diff --git a/exporter/opentelemetry-exporter-otlp-proto-http/pyproject.toml b/exporter/opentelemetry-exporter-otlp-proto-http/pyproject.toml index f1c88db5c9..1e17052851 100644 --- a/exporter/opentelemetry-exporter-otlp-proto-http/pyproject.toml +++ b/exporter/opentelemetry-exporter-otlp-proto-http/pyproject.toml @@ -27,9 +27,9 @@ dependencies = [ "Deprecated >= 1.2.6", "googleapis-common-protos ~= 1.52", "opentelemetry-api ~= 1.15", - "opentelemetry-proto == 1.24.0.dev", - "opentelemetry-sdk ~= 1.24.0.dev", - "opentelemetry-exporter-otlp-proto-common == 1.24.0.dev", + "opentelemetry-proto == 1.25.0.dev", + "opentelemetry-sdk ~= 1.25.0.dev", + "opentelemetry-exporter-otlp-proto-common == 1.25.0.dev", "requests ~= 2.7", ] diff --git a/exporter/opentelemetry-exporter-otlp-proto-http/src/opentelemetry/exporter/otlp/proto/http/trace_exporter/__init__.py b/exporter/opentelemetry-exporter-otlp-proto-http/src/opentelemetry/exporter/otlp/proto/http/trace_exporter/__init__.py index c624dfe476..ea21cc664b 100644 --- a/exporter/opentelemetry-exporter-otlp-proto-http/src/opentelemetry/exporter/otlp/proto/http/trace_exporter/__init__.py +++ b/exporter/opentelemetry-exporter-otlp-proto-http/src/opentelemetry/exporter/otlp/proto/http/trace_exporter/__init__.py @@ -126,19 +126,13 @@ def _retryable(resp: requests.Response) -> bool: return True return False - def export(self, spans) -> SpanExportResult: - # After the call to Shutdown subsequent calls to Export are - # not allowed and should return a Failure result. - if self._shutdown: - _logger.warning("Exporter already shutdown, ignoring batch") - return SpanExportResult.FAILURE - - serialized_data = encode_spans(spans).SerializeToString() + def _serialize_spans(self, spans): + return encode_spans(spans).SerializePartialToString() + def _export_serialized_spans(self, serialized_data): for delay in _create_exp_backoff_generator( max_value=self._MAX_RETRY_TIMEOUT ): - if delay == self._MAX_RETRY_TIMEOUT: return SpanExportResult.FAILURE @@ -163,6 +157,17 @@ def export(self, spans) -> SpanExportResult: return SpanExportResult.FAILURE return SpanExportResult.FAILURE + def export(self, spans) -> SpanExportResult: + # After the call to Shutdown subsequent calls to Export are + # not allowed and should return a Failure result. + if self._shutdown: + _logger.warning("Exporter already shutdown, ignoring batch") + return SpanExportResult.FAILURE + + serialized_data = self._serialize_spans(spans) + + return self._export_serialized_spans(serialized_data) + def shutdown(self): if self._shutdown: _logger.warning("Exporter already shutdown, ignoring call") diff --git a/exporter/opentelemetry-exporter-otlp-proto-http/src/opentelemetry/exporter/otlp/proto/http/version.py b/exporter/opentelemetry-exporter-otlp-proto-http/src/opentelemetry/exporter/otlp/proto/http/version.py index 8c35630f0e..e8b404f050 100644 --- a/exporter/opentelemetry-exporter-otlp-proto-http/src/opentelemetry/exporter/otlp/proto/http/version.py +++ b/exporter/opentelemetry-exporter-otlp-proto-http/src/opentelemetry/exporter/otlp/proto/http/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "1.24.0.dev" +__version__ = "1.25.0.dev" diff --git a/exporter/opentelemetry-exporter-otlp/pyproject.toml b/exporter/opentelemetry-exporter-otlp/pyproject.toml index 7750cfda59..d6aa3aa4cd 100644 --- a/exporter/opentelemetry-exporter-otlp/pyproject.toml +++ b/exporter/opentelemetry-exporter-otlp/pyproject.toml @@ -25,8 +25,8 @@ classifiers = [ "Typing :: Typed", ] dependencies = [ - "opentelemetry-exporter-otlp-proto-grpc == 1.24.0.dev", - "opentelemetry-exporter-otlp-proto-http == 1.24.0.dev", + "opentelemetry-exporter-otlp-proto-grpc == 1.25.0.dev", + "opentelemetry-exporter-otlp-proto-http == 1.25.0.dev", ] [project.entry-points.opentelemetry_logs_exporter] diff --git a/exporter/opentelemetry-exporter-otlp/src/opentelemetry/exporter/otlp/version.py b/exporter/opentelemetry-exporter-otlp/src/opentelemetry/exporter/otlp/version.py index 8c35630f0e..e8b404f050 100644 --- a/exporter/opentelemetry-exporter-otlp/src/opentelemetry/exporter/otlp/version.py +++ b/exporter/opentelemetry-exporter-otlp/src/opentelemetry/exporter/otlp/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "1.24.0.dev" +__version__ = "1.25.0.dev" diff --git a/exporter/opentelemetry-exporter-prometheus/pyproject.toml b/exporter/opentelemetry-exporter-prometheus/pyproject.toml index 1c3c9e89dd..6fdb327124 100644 --- a/exporter/opentelemetry-exporter-prometheus/pyproject.toml +++ b/exporter/opentelemetry-exporter-prometheus/pyproject.toml @@ -26,7 +26,7 @@ classifiers = [ dependencies = [ "opentelemetry-api ~= 1.12", # DONOTMERGE: confirm that this will becomes ~= 1.21 in the next release - "opentelemetry-sdk ~= 1.24.0.dev", + "opentelemetry-sdk ~= 1.25.0.dev", "prometheus_client >= 0.5.0, < 1.0.0", ] diff --git a/exporter/opentelemetry-exporter-prometheus/src/opentelemetry/exporter/prometheus/version.py b/exporter/opentelemetry-exporter-prometheus/src/opentelemetry/exporter/prometheus/version.py index 2b23bc4994..ff4933b20b 100644 --- a/exporter/opentelemetry-exporter-prometheus/src/opentelemetry/exporter/prometheus/version.py +++ b/exporter/opentelemetry-exporter-prometheus/src/opentelemetry/exporter/prometheus/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.45b0.dev" +__version__ = "0.46b0.dev" diff --git a/exporter/opentelemetry-exporter-zipkin-json/src/opentelemetry/exporter/zipkin/json/version.py b/exporter/opentelemetry-exporter-zipkin-json/src/opentelemetry/exporter/zipkin/json/version.py index 8c35630f0e..e8b404f050 100644 --- a/exporter/opentelemetry-exporter-zipkin-json/src/opentelemetry/exporter/zipkin/json/version.py +++ b/exporter/opentelemetry-exporter-zipkin-json/src/opentelemetry/exporter/zipkin/json/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "1.24.0.dev" +__version__ = "1.25.0.dev" diff --git a/exporter/opentelemetry-exporter-zipkin-proto-http/pyproject.toml b/exporter/opentelemetry-exporter-zipkin-proto-http/pyproject.toml index 03a400dce7..a934fc7edd 100644 --- a/exporter/opentelemetry-exporter-zipkin-proto-http/pyproject.toml +++ b/exporter/opentelemetry-exporter-zipkin-proto-http/pyproject.toml @@ -26,7 +26,7 @@ classifiers = [ ] dependencies = [ "opentelemetry-api ~= 1.3", - "opentelemetry-exporter-zipkin-json == 1.24.0.dev", + "opentelemetry-exporter-zipkin-json == 1.25.0.dev", "opentelemetry-sdk ~= 1.11", "protobuf ~= 3.12", "requests ~= 2.7", diff --git a/exporter/opentelemetry-exporter-zipkin-proto-http/src/opentelemetry/exporter/zipkin/proto/http/version.py b/exporter/opentelemetry-exporter-zipkin-proto-http/src/opentelemetry/exporter/zipkin/proto/http/version.py index 8c35630f0e..e8b404f050 100644 --- a/exporter/opentelemetry-exporter-zipkin-proto-http/src/opentelemetry/exporter/zipkin/proto/http/version.py +++ b/exporter/opentelemetry-exporter-zipkin-proto-http/src/opentelemetry/exporter/zipkin/proto/http/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "1.24.0.dev" +__version__ = "1.25.0.dev" diff --git a/exporter/opentelemetry-exporter-zipkin/pyproject.toml b/exporter/opentelemetry-exporter-zipkin/pyproject.toml index 7ec3ac135f..905a52fae7 100644 --- a/exporter/opentelemetry-exporter-zipkin/pyproject.toml +++ b/exporter/opentelemetry-exporter-zipkin/pyproject.toml @@ -25,8 +25,8 @@ classifiers = [ "Typing :: Typed", ] dependencies = [ - "opentelemetry-exporter-zipkin-json == 1.24.0.dev", - "opentelemetry-exporter-zipkin-proto-http == 1.24.0.dev", + "opentelemetry-exporter-zipkin-json == 1.25.0.dev", + "opentelemetry-exporter-zipkin-proto-http == 1.25.0.dev", ] [project.entry-points.opentelemetry_traces_exporter] diff --git a/exporter/opentelemetry-exporter-zipkin/src/opentelemetry/exporter/zipkin/version.py b/exporter/opentelemetry-exporter-zipkin/src/opentelemetry/exporter/zipkin/version.py index 8c35630f0e..e8b404f050 100644 --- a/exporter/opentelemetry-exporter-zipkin/src/opentelemetry/exporter/zipkin/version.py +++ b/exporter/opentelemetry-exporter-zipkin/src/opentelemetry/exporter/zipkin/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "1.24.0.dev" +__version__ = "1.25.0.dev" diff --git a/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py b/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py index 156b2598e4..ccf9f4597a 100644 --- a/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py +++ b/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py @@ -193,7 +193,6 @@ def get_logger( schema_url: Optional[str] = None, ) -> Logger: """Returns a NoOpLogger.""" - super().get_logger(name, version=version, schema_url=schema_url) return NoOpLogger(name, version=version, schema_url=schema_url) diff --git a/opentelemetry-api/src/opentelemetry/metrics/_internal/__init__.py b/opentelemetry-api/src/opentelemetry/metrics/_internal/__init__.py index 2e6914f8e3..9cbf14d2ed 100644 --- a/opentelemetry-api/src/opentelemetry/metrics/_internal/__init__.py +++ b/opentelemetry-api/src/opentelemetry/metrics/_internal/__init__.py @@ -41,6 +41,7 @@ """ +import warnings from abc import ABC, abstractmethod from logging import getLogger from os import environ @@ -140,7 +141,6 @@ def get_meter( schema_url: Optional[str] = None, ) -> "Meter": """Returns a NoOpMeter.""" - super().get_meter(name, version=version, schema_url=schema_url) return NoOpMeter(name, version=version, schema_url=schema_url) @@ -385,8 +385,7 @@ def create_histogram( description: A description for this instrument and what it measures. """ - @abstractmethod - def create_gauge( + def create_gauge( # type: ignore # pylint: disable=no-self-use self, name: str, unit: str = "", @@ -400,6 +399,7 @@ def create_gauge( example, ``By`` for bytes. UCUM units are recommended. description: A description for this instrument and what it measures. """ + warnings.warn("create_gauge() is not implemented and will be a no-op") @abstractmethod def create_observable_gauge( @@ -598,7 +598,6 @@ def create_counter( description: str = "", ) -> Counter: """Returns a no-op Counter.""" - super().create_counter(name, unit=unit, description=description) if self._is_instrument_registered( name, NoOpCounter, unit, description )[0]: @@ -619,7 +618,6 @@ def create_gauge( description: str = "", ) -> Gauge: """Returns a no-op Gauge.""" - super().create_gauge(name, unit=unit, description=description) if self._is_instrument_registered(name, NoOpGauge, unit, description)[ 0 ]: @@ -640,9 +638,6 @@ def create_up_down_counter( description: str = "", ) -> UpDownCounter: """Returns a no-op UpDownCounter.""" - super().create_up_down_counter( - name, unit=unit, description=description - ) if self._is_instrument_registered( name, NoOpUpDownCounter, unit, description )[0]: @@ -664,9 +659,6 @@ def create_observable_counter( description: str = "", ) -> ObservableCounter: """Returns a no-op ObservableCounter.""" - super().create_observable_counter( - name, callbacks, unit=unit, description=description - ) if self._is_instrument_registered( name, NoOpObservableCounter, unit, description )[0]: @@ -692,7 +684,6 @@ def create_histogram( description: str = "", ) -> Histogram: """Returns a no-op Histogram.""" - super().create_histogram(name, unit=unit, description=description) if self._is_instrument_registered( name, NoOpHistogram, unit, description )[0]: @@ -714,9 +705,6 @@ def create_observable_gauge( description: str = "", ) -> ObservableGauge: """Returns a no-op ObservableGauge.""" - super().create_observable_gauge( - name, callbacks, unit=unit, description=description - ) if self._is_instrument_registered( name, NoOpObservableGauge, unit, description )[0]: @@ -743,9 +731,6 @@ def create_observable_up_down_counter( description: str = "", ) -> ObservableUpDownCounter: """Returns a no-op ObservableUpDownCounter.""" - super().create_observable_up_down_counter( - name, callbacks, unit=unit, description=description - ) if self._is_instrument_registered( name, NoOpObservableUpDownCounter, unit, description )[0]: diff --git a/opentelemetry-api/src/opentelemetry/trace/span.py b/opentelemetry-api/src/opentelemetry/trace/span.py index 8201fdb251..5d46ffcb4a 100644 --- a/opentelemetry-api/src/opentelemetry/trace/span.py +++ b/opentelemetry-api/src/opentelemetry/trace/span.py @@ -169,7 +169,7 @@ def set_status( @abc.abstractmethod def record_exception( self, - exception: Exception, + exception: BaseException, attributes: types.Attributes = None, timestamp: typing.Optional[int] = None, escaped: bool = False, @@ -563,7 +563,7 @@ def set_status( def record_exception( self, - exception: Exception, + exception: BaseException, attributes: types.Attributes = None, timestamp: typing.Optional[int] = None, escaped: bool = False, diff --git a/opentelemetry-api/src/opentelemetry/util/_decorator.py b/opentelemetry-api/src/opentelemetry/util/_decorator.py index 233f29ff79..870c97bd98 100644 --- a/opentelemetry-api/src/opentelemetry/util/_decorator.py +++ b/opentelemetry-api/src/opentelemetry/util/_decorator.py @@ -78,4 +78,5 @@ def _agnosticcontextmanager( def helper(*args: Pargs, **kwargs: Pkwargs) -> _AgnosticContextManager[R]: return _AgnosticContextManager(func, args, kwargs) - return helper + # Ignoring the type to keep the original signature of the function + return helper # type: ignore[return-value] diff --git a/opentelemetry-api/src/opentelemetry/util/_providers.py b/opentelemetry-api/src/opentelemetry/util/_providers.py index d255ac999f..307650bb1d 100644 --- a/opentelemetry-api/src/opentelemetry/util/_providers.py +++ b/opentelemetry-api/src/opentelemetry/util/_providers.py @@ -29,7 +29,7 @@ def _load_provider( provider_environment_variable: str, provider: str -) -> Provider: +) -> Provider: # type: ignore[type-var] try: diff --git a/opentelemetry-api/src/opentelemetry/version.py b/opentelemetry-api/src/opentelemetry/version.py index 8c35630f0e..e8b404f050 100644 --- a/opentelemetry-api/src/opentelemetry/version.py +++ b/opentelemetry-api/src/opentelemetry/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "1.24.0.dev" +__version__ = "1.25.0.dev" diff --git a/opentelemetry-api/tests/logs/test_proxy.py b/opentelemetry-api/tests/logs/test_proxy.py index d8fa0a9743..cda187cae3 100644 --- a/opentelemetry-api/tests/logs/test_proxy.py +++ b/opentelemetry-api/tests/logs/test_proxy.py @@ -18,7 +18,6 @@ import opentelemetry._logs._internal as _logs_internal from opentelemetry import _logs -from opentelemetry.sdk._logs import LogRecord # type: ignore from opentelemetry.test.globals_test import LoggingGlobalsTest @@ -33,8 +32,8 @@ def get_logger( class TestLogger(_logs.NoOpLogger): - def emit(self, *args, **kwargs): - return LogRecord(timestamp=0) + def emit(self, record: _logs.LogRecord) -> None: + pass class TestProxy(LoggingGlobalsTest, unittest.TestCase): diff --git a/opentelemetry-api/tests/metrics/test_meter.py b/opentelemetry-api/tests/metrics/test_meter.py index 8b427a7372..2226965521 100644 --- a/opentelemetry-api/tests/metrics/test_meter.py +++ b/opentelemetry-api/tests/metrics/test_meter.py @@ -134,7 +134,6 @@ def test_create_gauge(self): """ self.assertTrue(hasattr(Meter, "create_gauge")) - self.assertTrue(Meter.create_gauge.__isabstractmethod__) def test_create_observable_gauge(self): """ diff --git a/opentelemetry-api/tests/metrics/test_subclass_instantiation.py b/opentelemetry-api/tests/metrics/test_subclass_instantiation.py new file mode 100644 index 0000000000..a5b68d1c06 --- /dev/null +++ b/opentelemetry-api/tests/metrics/test_subclass_instantiation.py @@ -0,0 +1,209 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# type: ignore + +# NOTE: The tests in this file are intended to test the semver compatibility of the public API. +# Any tests that fail here indicate that the public API has changed in a way that is not backwards compatible. +# Either bump the major version of the API, or make the necessary changes to the API to remain semver compatible. + +from typing import Optional + +from opentelemetry.metrics import ( + Asynchronous, + Counter, + Histogram, + Instrument, + Meter, + MeterProvider, + ObservableCounter, + ObservableGauge, + ObservableUpDownCounter, + Synchronous, + UpDownCounter, + _Gauge, +) + + +class MeterProviderImplTest(MeterProvider): + def get_meter( + self, + name: str, + version: Optional[str] = None, + schema_url: Optional[str] = None, + ) -> Meter: + return super().get_meter(name, version, schema_url) + + +def test_meter_provider_subclass_instantiation(): + meter_provider = MeterProviderImplTest() + assert isinstance(meter_provider, MeterProvider) + + +class MeterImplTest(Meter): + def create_counter(self, name, description, **kwargs): + pass + + def create_up_down_counter(self, name, description, **kwargs): + pass + + def create_observable_counter(self, name, description, **kwargs): + pass + + def create_histogram(self, name, description, **kwargs): + pass + + def create_observable_gauge(self, name, description, **kwargs): + pass + + def create_observable_up_down_counter(self, name, description, **kwargs): + pass + + +def test_meter_subclass_instantiation(): + meter = MeterImplTest("subclass_test") + assert isinstance(meter, Meter) + + +class SynchronousImplTest(Synchronous): + def __init__( + self, name: str, unit: str = "", description: str = "" + ) -> None: + super().__init__(name, unit, description) + + +def test_synchronous_subclass_instantiation(): + synchronous = SynchronousImplTest("subclass_test") + assert isinstance(synchronous, Synchronous) + + +class AsynchronousImplTest(Asynchronous): + def __init__( + self, name: str, unit: str = "", description: str = "" + ) -> None: + super().__init__(name, unit, description) + + +def test_asynchronous_subclass_instantiation(): + asynchronous = AsynchronousImplTest("subclass_test") + assert isinstance(asynchronous, Asynchronous) + + +class CounterImplTest(Counter): + def __init__( + self, name: str, unit: str = "", description: str = "" + ) -> None: + super().__init__(name, unit, description) + + def add(self, amount: int, **kwargs): + pass + + +def test_counter_subclass_instantiation(): + counter = CounterImplTest("subclass_test") + assert isinstance(counter, Counter) + + +class UpDownCounterImplTest(UpDownCounter): + def __init__( + self, name: str, unit: str = "", description: str = "" + ) -> None: + super().__init__(name, unit, description) + + def add(self, amount: int, **kwargs): + pass + + +def test_up_down_counter_subclass_instantiation(): + up_down_counter = UpDownCounterImplTest("subclass_test") + assert isinstance(up_down_counter, UpDownCounter) + + +class ObservableCounterImplTest(ObservableCounter): + def __init__( + self, name: str, unit: str = "", description: str = "" + ) -> None: + super().__init__(name, unit, description) + + +def test_observable_counter_subclass_instantiation(): + observable_counter = ObservableCounterImplTest("subclass_test") + assert isinstance(observable_counter, ObservableCounter) + + +class HistogramImplTest(Histogram): + def __init__( + self, name: str, unit: str = "", description: str = "" + ) -> None: + super().__init__(name, unit, description) + + def record(self, amount: int, **kwargs): + pass + + +def test_histogram_subclass_instantiation(): + histogram = HistogramImplTest("subclass_test") + assert isinstance(histogram, Histogram) + + +class GaugeImplTest(_Gauge): + def __init__( + self, name: str, unit: str = "", description: str = "" + ) -> None: + super().__init__(name, unit, description) + + def set(self, amount: int, **kwargs): + pass + + +def test_gauge_subclass_instantiation(): + gauge = GaugeImplTest("subclass_test") + assert isinstance(gauge, _Gauge) + + +class InstrumentImplTest(Instrument): + def __init__( + self, name: str, unit: str = "", description: str = "" + ) -> None: + super().__init__(name, unit, description) + + +def test_instrument_subclass_instantiation(): + instrument = InstrumentImplTest("subclass_test") + assert isinstance(instrument, Instrument) + + +class ObservableGaugeImplTest(ObservableGauge): + def __init__( + self, name: str, unit: str = "", description: str = "" + ) -> None: + super().__init__(name, unit, description) + + +def test_observable_gauge_subclass_instantiation(): + observable_gauge = ObservableGaugeImplTest("subclass_test") + assert isinstance(observable_gauge, ObservableGauge) + + +class ObservableUpDownCounterImplTest(ObservableUpDownCounter): + def __init__( + self, name: str, unit: str = "", description: str = "" + ) -> None: + super().__init__(name, unit, description) + + +def test_observable_up_down_counter_subclass_instantiation(): + observable_up_down_counter = ObservableUpDownCounterImplTest( + "subclass_test" + ) + assert isinstance(observable_up_down_counter, ObservableUpDownCounter) diff --git a/opentelemetry-proto/src/opentelemetry/proto/version.py b/opentelemetry-proto/src/opentelemetry/proto/version.py index 8c35630f0e..e8b404f050 100644 --- a/opentelemetry-proto/src/opentelemetry/proto/version.py +++ b/opentelemetry-proto/src/opentelemetry/proto/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "1.24.0.dev" +__version__ = "1.25.0.dev" diff --git a/opentelemetry-sdk/pyproject.toml b/opentelemetry-sdk/pyproject.toml index ea5d1ec2b0..25568d42c6 100644 --- a/opentelemetry-sdk/pyproject.toml +++ b/opentelemetry-sdk/pyproject.toml @@ -25,8 +25,8 @@ classifiers = [ "Typing :: Typed", ] dependencies = [ - "opentelemetry-api == 1.24.0.dev", - "opentelemetry-semantic-conventions == 0.45b0.dev", + "opentelemetry-api == 1.25.0.dev", + "opentelemetry-semantic-conventions == 0.46b0.dev", "typing-extensions >= 3.7.4", ] diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/metrics/_internal/aggregation.py b/opentelemetry-sdk/src/opentelemetry/sdk/metrics/_internal/aggregation.py index 3ec37473f6..3f93c91fa2 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/metrics/_internal/aggregation.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/metrics/_internal/aggregation.py @@ -37,6 +37,9 @@ from opentelemetry.sdk.metrics._internal.exponential_histogram.buckets import ( Buckets, ) +from opentelemetry.sdk.metrics._internal.exponential_histogram.mapping import ( + Mapping, +) from opentelemetry.sdk.metrics._internal.exponential_histogram.mapping.exponent_mapping import ( ExponentMapping, ) @@ -519,6 +522,12 @@ def collect( return None +def _new_exponential_mapping(scale: int) -> Mapping: + if scale <= 0: + return ExponentMapping(scale) + return LogarithmMapping(scale) + + # pylint: disable=protected-access class _ExponentialBucketHistogramAggregation(_Aggregation[HistogramPoint]): # _min_max_size and _max_max_size are the smallest and largest values @@ -592,13 +601,15 @@ def __init__( "larger than the recommended value of 20", self._max_scale, ) - self._mapping = LogarithmMapping(self._max_scale) + self._mapping = _new_exponential_mapping(self._max_scale) self._instrument_aggregation_temporality = AggregationTemporality.DELTA self._start_time_unix_nano = start_time_unix_nano self._previous_scale = None self._previous_start_time_unix_nano = None + self._previous_zero_count = None + self._previous_count = None self._previous_sum = None self._previous_max = None self._previous_min = None @@ -678,11 +689,14 @@ def aggregate(self, measurement: Measurement) -> None: # 4. Rescale the mapping if needed. if is_rescaling_needed: + scale_change = self._get_scale_change(low, high) self._downscale( - self._get_scale_change(low, high), + scale_change, self._positive, self._negative, ) + new_scale = self._mapping.scale - scale_change + self._mapping = _new_exponential_mapping(new_scale) index = self._mapping.map_to_index(value) @@ -756,28 +770,6 @@ def collect( self._min = inf self._max = -inf - current_point = ExponentialHistogramDataPoint( - attributes=self._attributes, - start_time_unix_nano=current_start_time_unix_nano, - time_unix_nano=collection_start_nano, - count=current_count, - sum=current_sum, - scale=current_scale, - zero_count=current_zero_count, - positive=BucketsPoint( - offset=current_positive.offset, - bucket_counts=current_positive.counts, - ), - negative=BucketsPoint( - offset=current_negative.offset, - bucket_counts=current_negative.counts, - ), - # FIXME: Find the right value for flags - flags=0, - min=current_min, - max=current_max, - ) - if self._previous_scale is None or ( self._instrument_aggregation_temporality is collection_aggregation_temporality @@ -789,18 +781,48 @@ def collect( self._previous_max = current_max self._previous_min = current_min self._previous_sum = current_sum + self._previous_count = current_count + self._previous_zero_count = current_zero_count self._previous_positive = current_positive self._previous_negative = current_negative + current_point = ExponentialHistogramDataPoint( + attributes=self._attributes, + start_time_unix_nano=current_start_time_unix_nano, + time_unix_nano=collection_start_nano, + count=current_count, + sum=current_sum, + scale=current_scale, + zero_count=current_zero_count, + positive=BucketsPoint( + offset=current_positive.offset, + bucket_counts=current_positive.get_offset_counts(), + ), + negative=BucketsPoint( + offset=current_negative.offset, + bucket_counts=current_negative.get_offset_counts(), + ), + # FIXME: Find the right value for flags + flags=0, + min=current_min, + max=current_max, + ) + return current_point min_scale = min(self._previous_scale, current_scale) low_positive, high_positive = self._get_low_high_previous_current( - self._previous_positive, current_positive, min_scale + self._previous_positive, + current_positive, + current_scale, + min_scale, ) low_negative, high_negative = self._get_low_high_previous_current( - self._previous_negative, current_negative, min_scale + self._previous_negative, + current_negative, + current_scale, + min_scale, ) min_scale = min( @@ -814,10 +836,11 @@ def collect( # but the histogram) has a count larger than zero, if not, scale # (the histogram scale) would be zero. See exponential.go 191 self._downscale( - self._mapping.scale - min_scale, + self._previous_scale - min_scale, self._previous_positive, self._previous_negative, ) + self._previous_scale = min_scale if ( collection_aggregation_temporality @@ -826,6 +849,8 @@ def collect( start_time_unix_nano = self._previous_start_time_unix_nano sum_ = current_sum + self._previous_sum + zero_count = current_zero_count + self._previous_zero_count + count = current_count + self._previous_count # Only update min/max on delta -> cumulative max_ = max(current_max, self._previous_max) min_ = min(current_min, self._previous_min) @@ -844,10 +869,16 @@ def collect( min_scale, collection_aggregation_temporality, ) + current_scale = min_scale + + current_positive = self._previous_positive + current_negative = self._previous_negative else: start_time_unix_nano = self._previous_start_time_unix_nano sum_ = current_sum - self._previous_sum + zero_count = current_zero_count + count = current_count max_ = current_max min_ = current_min @@ -870,17 +901,17 @@ def collect( attributes=self._attributes, start_time_unix_nano=start_time_unix_nano, time_unix_nano=collection_start_nano, - count=current_count, + count=count, sum=sum_, scale=current_scale, - zero_count=current_zero_count, + zero_count=zero_count, positive=BucketsPoint( offset=current_positive.offset, - bucket_counts=current_positive.counts, + bucket_counts=current_positive.get_offset_counts(), ), negative=BucketsPoint( offset=current_negative.offset, - bucket_counts=current_negative.counts, + bucket_counts=current_negative.get_offset_counts(), ), # FIXME: Find the right value for flags flags=0, @@ -892,19 +923,27 @@ def collect( self._previous_positive = current_positive self._previous_negative = current_negative self._previous_start_time_unix_nano = current_start_time_unix_nano - self._previous_sum = current_sum + self._previous_sum = sum_ + self._previous_count = count + self._previous_max = max_ + self._previous_min = min_ + self._previous_zero_count = zero_count return current_point def _get_low_high_previous_current( - self, previous_point_buckets, current_point_buckets, min_scale + self, + previous_point_buckets, + current_point_buckets, + current_scale, + min_scale, ): (previous_point_low, previous_point_high) = self._get_low_high( - previous_point_buckets, min_scale + previous_point_buckets, self._previous_scale, min_scale ) (current_point_low, current_point_high) = self._get_low_high( - current_point_buckets, min_scale + current_point_buckets, current_scale, min_scale ) if current_point_low > current_point_high: @@ -921,11 +960,12 @@ def _get_low_high_previous_current( return low, high - def _get_low_high(self, buckets, min_scale): + @staticmethod + def _get_low_high(buckets, scale, min_scale): if buckets.counts == [0]: return 0, -1 - shift = self._mapping._scale - min_scale + shift = scale - min_scale return buckets.index_start >> shift, buckets.index_end >> shift @@ -941,7 +981,8 @@ def _get_scale_change(self, low, high): return change - def _downscale(self, change: int, positive, negative): + @staticmethod + def _downscale(change: int, positive, negative): if change == 0: return @@ -949,22 +990,13 @@ def _downscale(self, change: int, positive, negative): if change < 0: raise Exception("Invalid change of scale") - new_scale = self._mapping.scale - change - positive.downscale(change) negative.downscale(change) - if new_scale <= 0: - mapping = ExponentMapping(new_scale) - else: - mapping = LogarithmMapping(new_scale) - - self._mapping = mapping - def _merge( self, - previous_buckets, - current_buckets, + previous_buckets: Buckets, + current_buckets: Buckets, current_scale, min_scale, aggregation_temporality, @@ -983,9 +1015,11 @@ def _merge( # would not happen because self._previous_point is only assigned to # an ExponentialHistogramDataPoint object if self._count != 0. - index = ( - current_buckets.offset + current_bucket_index - ) >> current_change + current_index = current_buckets.index_base + current_bucket_index + if current_index > current_buckets.index_end: + current_index -= len(current_buckets.counts) + + index = current_index >> current_change if index < previous_buckets.index_start: span = previous_buckets.index_end - index @@ -999,7 +1033,7 @@ def _merge( previous_buckets.index_start = index if index > previous_buckets.index_end: - span = index - previous_buckets.index_end + span = index - previous_buckets.index_start if span >= self._max_size: raise Exception("Incorrect merge scale") diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/metrics/_internal/exponential_histogram/buckets.py b/opentelemetry-sdk/src/opentelemetry/sdk/metrics/_internal/exponential_histogram/buckets.py index 5c6b04bd39..4dbe8f385e 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/metrics/_internal/exponential_histogram/buckets.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/metrics/_internal/exponential_histogram/buckets.py @@ -73,6 +73,10 @@ def index_base(self, value: int) -> None: def counts(self): return self._counts + def get_offset_counts(self): + bias = self.__index_base - self.__index_start + return self._counts[-bias:] + self._counts[:-bias] + def grow(self, needed: int, max_size: int) -> None: size = len(self._counts) @@ -129,7 +133,6 @@ def downscale(self, amount: int) -> None: bias = self.__index_base - self.__index_start if bias != 0: - self.__index_base = self.__index_start # [0, 1, 2, 3, 4] Original backing array diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/metrics/_internal/point.py b/opentelemetry-sdk/src/opentelemetry/sdk/metrics/_internal/point.py index c30705c59a..42420b9008 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/metrics/_internal/point.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/metrics/_internal/point.py @@ -101,6 +101,18 @@ class ExponentialHistogram: "opentelemetry.sdk.metrics.export.AggregationTemporality" ) + def to_json(self, indent=4) -> str: + return dumps( + { + "data_points": [ + loads(data_point.to_json(indent=indent)) + for data_point in self.data_points + ], + "aggregation_temporality": self.aggregation_temporality, + }, + indent=indent, + ) + @dataclass(frozen=True) class Sum: diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py index ff999b9ba8..0110a5c0e0 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py @@ -983,7 +983,7 @@ def __exit__( def record_exception( self, - exception: Exception, + exception: BaseException, attributes: types.Attributes = None, timestamp: Optional[int] = None, escaped: bool = False, diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/version.py b/opentelemetry-sdk/src/opentelemetry/sdk/version.py index 8c35630f0e..e8b404f050 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/version.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "1.24.0.dev" +__version__ = "1.25.0.dev" diff --git a/opentelemetry-sdk/tests/metrics/exponential_histogram/test_exponential_bucket_histogram_aggregation.py b/opentelemetry-sdk/tests/metrics/exponential_histogram/test_exponential_bucket_histogram_aggregation.py index 311f00a0b0..bae0aca20b 100644 --- a/opentelemetry-sdk/tests/metrics/exponential_histogram/test_exponential_bucket_histogram_aggregation.py +++ b/opentelemetry-sdk/tests/metrics/exponential_histogram/test_exponential_bucket_histogram_aggregation.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +import random as insecure_random from itertools import permutations from logging import WARNING from math import ldexp @@ -37,6 +38,9 @@ LogarithmMapping, ) from opentelemetry.sdk.metrics._internal.measurement import Measurement +from opentelemetry.sdk.metrics._internal.point import ( + ExponentialHistogramDataPoint, +) from opentelemetry.sdk.metrics.view import ( ExponentialBucketHistogramAggregation, ) @@ -853,13 +857,14 @@ def test_aggregate_collect(self): AggregationTemporality.CUMULATIVE, 0 ) - def test_collect_results_cumulative(self): + def test_collect_results_cumulative(self) -> None: exponential_histogram_aggregation = ( _ExponentialBucketHistogramAggregation( Mock(), Mock(), ) ) + self.maxDiff = None self.assertEqual(exponential_histogram_aggregation._mapping._scale, 20) @@ -884,7 +889,7 @@ def test_collect_results_cumulative(self): self.assertEqual(collection_0.zero_count, 0) self.assertEqual( collection_0.positive.bucket_counts, - [1, *[0] * 63, 1, *[0] * 31, 1, *[0] * 63], + [1, *[0] * 63, 1, *[0] * 63, 1, *[0] * 31], ) self.assertEqual(collection_0.flags, 0) self.assertEqual(collection_0.min, 1) @@ -911,7 +916,7 @@ def test_collect_results_cumulative(self): previous_count = count count_counts.append([previous_count, 1]) - self.assertEqual(collection_1.count, 5) + self.assertEqual(collection_1.count, 8) self.assertEqual(collection_1.sum, 16.645) self.assertEqual(collection_1.scale, 4) self.assertEqual(collection_1.zero_count, 0) @@ -920,21 +925,68 @@ def test_collect_results_cumulative(self): collection_1.positive.bucket_counts, [ 1, - *[0] * 15, + *[0] * 17, 1, - *[0] * 47, + *[0] * 36, 1, - *[0] * 40, + *[0] * 15, + 2, + *[0] * 15, 1, - *[0] * 17, + *[0] * 15, 1, - *[0] * 36, + *[0] * 15, + 1, + *[0] * 40, ], ) self.assertEqual(collection_1.flags, 0) self.assertEqual(collection_1.min, 0.045) self.assertEqual(collection_1.max, 8) + def test_cumulative_aggregation_with_random_data(self) -> None: + histogram = _ExponentialBucketHistogramAggregation(Mock(), Mock()) + + def collect_and_validate() -> None: + result: ExponentialHistogramDataPoint = histogram.collect( + AggregationTemporality.CUMULATIVE, 0 + ) + buckets = result.positive.bucket_counts + scale = result.scale + index_start = result.positive.offset + + for i in range(len(buckets)): + index = index_start + i + count = buckets[i] + lower_bound = 2 ** (index / (2**scale)) + upper_bound = 2 ** ((index + 1) / (2**scale)) + matches = 0 + for value in values: + if value > lower_bound and value <= upper_bound: + matches += 1 + assert ( + matches == count + ), f"index: {index}, count: {count}, scale: {scale}, lower_bound: {lower_bound}, upper_bound: {upper_bound}, matches: {matches}" + + assert sum(buckets) + result.zero_count == len(values) + assert result.sum == sum(values) + assert result.count == len(values) + assert result.min == min(values) + assert result.max == max(values) + assert result.zero_count == len([v for v in values if v == 0]) + assert scale >= 3 + + random = insecure_random.Random("opentelemetry2") + values = [] + for i in range(2000): + value = random.randint(0, 1000) + values.append(value) + histogram.aggregate(Measurement(value, Mock())) + if i % 20 == 0: + collect_and_validate() + + collect_and_validate() + def test_merge_collect_cumulative(self): exponential_histogram_aggregation = ( _ExponentialBucketHistogramAggregation(Mock(), Mock(), max_size=4) @@ -974,7 +1026,8 @@ def test_merge_collect_cumulative(self): 0, ) - self.assertEqual(result.scale, result_1.scale) + self.assertEqual(result.scale, 0) + self.assertEqual(result_1.scale, -1) def test_merge_collect_delta(self): exponential_histogram_aggregation = ( diff --git a/opentelemetry-sdk/tests/metrics/test_point.py b/opentelemetry-sdk/tests/metrics/test_point.py index 5d6640fdea..20dd0e7238 100644 --- a/opentelemetry-sdk/tests/metrics/test_point.py +++ b/opentelemetry-sdk/tests/metrics/test_point.py @@ -16,6 +16,9 @@ from opentelemetry.sdk.metrics.export import ( AggregationTemporality, + Buckets, + ExponentialHistogram, + ExponentialHistogramDataPoint, Gauge, Histogram, HistogramDataPoint, @@ -100,6 +103,22 @@ def setUpClass(cls): ) cls.histogram_data_point_1_str = f'{{"attributes": {cls.attributes_1_str}, "start_time_unix_nano": 2, "time_unix_nano": 3, "count": 4, "sum": 4.4, "bucket_counts": [2, 1, 1], "explicit_bounds": [1.2, 2.3, 3.4, 4.5], "min": 0.3, "max": 4.4}}' + cls.exp_histogram_data_point_0 = ExponentialHistogramDataPoint( + attributes=cls.attributes_0, + start_time_unix_nano=1, + time_unix_nano=2, + count=1, + sum=10, + scale=1, + zero_count=0, + positive=Buckets(offset=0, bucket_counts=[1]), + negative=Buckets(offset=0, bucket_counts=[0]), + flags=0, + min=10, + max=10, + ) + cls.exp_histogram_data_point_0_str = f'{{"attributes": {cls.attributes_0_str}, "start_time_unix_nano": 1, "time_unix_nano": 2, "count": 1, "sum": 10, "scale": 1, "zero_count": 0, "positive": {{"offset": 0, "bucket_counts": [1]}}, "negative": {{"offset": 0, "bucket_counts": [0]}}, "flags": 0, "min": 10, "max": 10}}' + cls.sum_0 = Sum( data_points=[cls.number_data_point_0, cls.number_data_point_1], aggregation_temporality=AggregationTemporality.DELTA, @@ -121,6 +140,14 @@ def setUpClass(cls): ) cls.histogram_0_str = f'{{"data_points": [{cls.histogram_data_point_0_str}, {cls.histogram_data_point_1_str}], "aggregation_temporality": 1}}' + cls.exp_histogram_0 = ExponentialHistogram( + data_points=[ + cls.exp_histogram_data_point_0, + ], + aggregation_temporality=AggregationTemporality.CUMULATIVE, + ) + cls.exp_histogram_0_str = f'{{"data_points": [{cls.exp_histogram_data_point_0_str}], "aggregation_temporality": 2}}' + cls.metric_0 = Metric( name="metric_0", description="description_0", @@ -209,6 +236,15 @@ def test_histogram_data_point(self): self.histogram_data_point_1_str, ) + def test_exp_histogram_data_point(self): + + self.maxDiff = None + + self.assertEqual( + self.exp_histogram_data_point_0.to_json(indent=None), + self.exp_histogram_data_point_0_str, + ) + def test_sum(self): self.assertEqual(self.sum_0.to_json(indent=None), self.sum_0_str) @@ -225,6 +261,14 @@ def test_histogram(self): self.histogram_0.to_json(indent=None), self.histogram_0_str ) + def test_exp_histogram(self): + + self.maxDiff = None + + self.assertEqual( + self.exp_histogram_0.to_json(indent=None), self.exp_histogram_0_str + ) + def test_metric(self): self.assertEqual(self.metric_0.to_json(indent=None), self.metric_0_str) diff --git a/opentelemetry-semantic-conventions/src/opentelemetry/semconv/version.py b/opentelemetry-semantic-conventions/src/opentelemetry/semconv/version.py index 2b23bc4994..ff4933b20b 100644 --- a/opentelemetry-semantic-conventions/src/opentelemetry/semconv/version.py +++ b/opentelemetry-semantic-conventions/src/opentelemetry/semconv/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.45b0.dev" +__version__ = "0.46b0.dev" diff --git a/propagator/opentelemetry-propagator-b3/src/opentelemetry/propagators/b3/version.py b/propagator/opentelemetry-propagator-b3/src/opentelemetry/propagators/b3/version.py index 8c35630f0e..e8b404f050 100644 --- a/propagator/opentelemetry-propagator-b3/src/opentelemetry/propagators/b3/version.py +++ b/propagator/opentelemetry-propagator-b3/src/opentelemetry/propagators/b3/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "1.24.0.dev" +__version__ = "1.25.0.dev" diff --git a/propagator/opentelemetry-propagator-jaeger/src/opentelemetry/propagators/jaeger/version.py b/propagator/opentelemetry-propagator-jaeger/src/opentelemetry/propagators/jaeger/version.py index 8c35630f0e..e8b404f050 100644 --- a/propagator/opentelemetry-propagator-jaeger/src/opentelemetry/propagators/jaeger/version.py +++ b/propagator/opentelemetry-propagator-jaeger/src/opentelemetry/propagators/jaeger/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "1.24.0.dev" +__version__ = "1.25.0.dev" diff --git a/scripts/public_symbols_checker.py b/scripts/public_symbols_checker.py index 05b7ad4abb..c8bf7fd22e 100644 --- a/scripts/public_symbols_checker.py +++ b/scripts/public_symbols_checker.py @@ -123,11 +123,11 @@ def remove_common_symbols(): del removed_symbols[file_path] -if added_symbols or removed_symbols: +# If a symbol is added and removed in the same commit, we consider it as not +# added or removed. +remove_common_symbols() - # If a symbol is added and removed in the same commit, we consider it - # as not added or removed. - remove_common_symbols() +if added_symbols or removed_symbols: print("The code in this branch adds the following public symbols:") print() for file_path_, symbols_ in added_symbols.items(): diff --git a/shim/opentelemetry-opencensus-shim/src/opentelemetry/shim/opencensus/version.py b/shim/opentelemetry-opencensus-shim/src/opentelemetry/shim/opencensus/version.py index 2b23bc4994..ff4933b20b 100644 --- a/shim/opentelemetry-opencensus-shim/src/opentelemetry/shim/opencensus/version.py +++ b/shim/opentelemetry-opencensus-shim/src/opentelemetry/shim/opencensus/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.45b0.dev" +__version__ = "0.46b0.dev" diff --git a/shim/opentelemetry-opentracing-shim/src/opentelemetry/shim/opentracing_shim/version.py b/shim/opentelemetry-opentracing-shim/src/opentelemetry/shim/opentracing_shim/version.py index 2b23bc4994..ff4933b20b 100644 --- a/shim/opentelemetry-opentracing-shim/src/opentelemetry/shim/opentracing_shim/version.py +++ b/shim/opentelemetry-opentracing-shim/src/opentelemetry/shim/opentracing_shim/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.45b0.dev" +__version__ = "0.46b0.dev" diff --git a/tests/opentelemetry-test-utils/pyproject.toml b/tests/opentelemetry-test-utils/pyproject.toml index 9d68cb6708..e4547b6e34 100644 --- a/tests/opentelemetry-test-utils/pyproject.toml +++ b/tests/opentelemetry-test-utils/pyproject.toml @@ -24,8 +24,8 @@ classifiers = [ ] dependencies = [ "asgiref ~= 3.0", - "opentelemetry-api == 1.24.0.dev", - "opentelemetry-sdk == 1.24.0.dev", + "opentelemetry-api == 1.25.0.dev", + "opentelemetry-sdk == 1.25.0.dev", ] [project.urls] diff --git a/tests/opentelemetry-test-utils/src/opentelemetry/test/version.py b/tests/opentelemetry-test-utils/src/opentelemetry/test/version.py index ef9e7fdbaf..e38c2cb2e4 100644 --- a/tests/opentelemetry-test-utils/src/opentelemetry/test/version.py +++ b/tests/opentelemetry-test-utils/src/opentelemetry/test/version.py @@ -1 +1 @@ -__version__ = "0.45b0.dev" +__version__ = "0.46b0.dev"