Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package 
python-opentelemetry-exporter-otlp-proto-grpc for openSUSE:Factory checked in 
at 2026-06-27 18:04:41
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing 
/work/SRC/openSUSE:Factory/python-opentelemetry-exporter-otlp-proto-grpc (Old)
 and      
/work/SRC/openSUSE:Factory/.python-opentelemetry-exporter-otlp-proto-grpc.new.11887
 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-opentelemetry-exporter-otlp-proto-grpc"

Sat Jun 27 18:04:41 2026 rev:15 rq:1361871 version:1.42.1

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/python-opentelemetry-exporter-otlp-proto-grpc/python-opentelemetry-exporter-otlp-proto-grpc.changes
      2026-04-28 11:57:03.967240125 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-opentelemetry-exporter-otlp-proto-grpc.new.11887/python-opentelemetry-exporter-otlp-proto-grpc.changes
   2026-06-27 18:05:48.527388355 +0200
@@ -1,0 +2,119 @@
+Sat Jun 20 16:00:16 UTC 2026 - Dirk Müller <[email protected]>
+
+- update to 1.42.1:
+  * This is a patch release on the previous 1.42.0/0.63b0
+    release, fixing the issue(s) below.
+  * ### Fixed
+  * Preserve the random trace ID flag when creating child spans
+    instead of always setting the random trace id bit depending
+    on the available trace id generator.
+- update to 1.42.0:
+  * ### Added
+  * `opentelemetry-api`, `opentelemetry-sdk`: add support for
+    'random-trace-id' flags in W3C traceparent header trace
+    flags. Implementations of `IdGenerator` that do randomly
+    generate the 56 least significant bits, should also implement
+    a `is_trace_id_random` methods that returns `True`.
+  * logs: add exception support to Logger emit and LogRecord
+    attributes
+  * `opentelemetry-exporter-otlp-proto-grpc`: make retryable gRPC
+    error codes configurable for gRPC exporters
+  * `opentelemetry-sdk`: Add
+    `create_logger_provider`/`configure_logger_provider` to
+    declarative file configuration, enabling LoggerProvider
+    instantiation from config files without reading env vars
+  * `opentelemetry-exporter-otlp-json-common`: add
+    'opentelemetry-exporter-otlp-json-common' package for OTLP
+    JSON exporters
+  * `opentelemetry-sdk`: Add `service` resource detector support
+    to declarative file configuration via
+    `detection_development.detectors[].service`
+  * `opentelemetry-docker-tests`: add docker-tests coverage of
+    `opentelemetry-exporter-otlp-proto-grpc` and `opentelemetry-
+    exporter-otlp-proto-http` metrics export
+  * Add `registry` keyword argument to `PrometheusMetricReader`
+    to allow passing a custom Prometheus registry
+  * Add WeaverLiveCheck test util
+  * `opentelemetry-sdk`: add `load_entry_point` shared utility to
+    declarative file configuration for loading plugins via entry
+    points; refactor propagator loading to use it
+  * `opentelemetry-sdk`: add sampler plugin loading to
+    declarative file configuration via the
+    `opentelemetry_sampler` entry point group, matching the
+    spec's PluginComponentProvider mechanism
+  * `opentelemetry-sdk`: add propagator plugin loading to
+    declarative file configuration via the
+    `opentelemetry_propagator` entry point group, matching the
+    spec's PluginComponentProvider mechanism
+  * `opentelemetry-sdk`: add exporter plugin loading to
+    declarative file configuration for all three signals (traces,
+    metrics, logs) via the `opentelemetry_*_exporter` entry point
+    groups, matching the spec's PluginComponentProvider mechanism
+  * `opentelemetry-sdk`: add generic resource detector plugin
+    loading to declarative file configuration via the
+    `opentelemetry_resource_detector` entry point group, matching
+    the spec's PluginComponentProvider mechanism
+  * `opentelemetry-sdk`: add `additional_properties` support to
+    generated config models via custom `datamodel-codegen`
+    template, enabling plugin/custom component names to flow
+    through typed dataclasses
+  * Add ability to selectively enable exporting of SDK internal
+    metrics with the `OTEL_PYTHON_SDK_INTERNAL_METRICS_ENABLED`
+    environment variable.
+  * ### Changed
+  * `opentelemetry-semantic-conventions`: use `X | Y` union
+    annotation
+  * `opentelemetry-api`: update `EnvironmentGetter` and
+    `EnvironmentSetter` to use normalized environment variable
+    names
+  * Apply fixes for `UP` ruff rule
+  * `opentelemetry-sdk`: only load entrypoints for resource
+    detectors if they are configured via
+    `OTEL_EXPERIMENTAL_RESOURCE_DETECTORS`
+  * ci: wait for tracecontext server readiness instead of a fixed
+    sleep in `scripts/tracecontext-integration-test.sh`
+  * Switch to SPDX license headers and add CI enforcement
+  * `opentelemetry-semantic-conventions`: Bump semantic
+    conventions to 1.41.1, this changes the metrics name of
+    `K8S_CONTAINER_CPU_LIMIT_UTILIZATION` and
+    `K8S_CONTAINER_CPU_REQUEST_UTILIZATION`.
+  * ### Removed
+  * `opentelemetry-api`: remove third-party importlib-metadata in
+    favor of standard library since Python >= 3.10 is now
+    required
+  * Drop Python 3.9 support
+  * ### Fixed
+  * `opentelemetry-sdk`: Allow declarative OTLP HTTP exporters to
+    map `compression: deflate` instead of rejecting it as
+    unsupported.
+  * Fix incorrect code example in `create_tracer()` docstring
+  * `opentelemetry-sdk`: Fix `ProcessResourceDetector` to use
+    `sys.orig_argv` so that `process.command`,
+    `process.command_line`, and `process.command_args` reflect
+    the original invocation for `python -m ` runs (where
+    `sys.argv[0]` is rewritten to the module path)
+  * `opentelemetry-sdk`: fix YAML structure injection via
+    environment variable substitution in declarative file
+    configuration; values containing newlines are now emitted as
+    quoted YAML scalars per spec requirement
+  * `opentelemetry-sdk`: Fix mutable attributes reference in
+    metrics, attributes passed to instrument `add`/`record` are
+    now copied so that subsequent mutations do not affect
+    recorded data points
+  * `opentelemetry-sdk`: make resource detector ordering
+    deterministic
+  * Fix incorrect type annotation on `detectors` parameter of
+    `get_aggregated_resources`
+  * `opentelemetry-api`: Enforce W3C Baggage size limits on
+    outbound propagation in `W3CBaggagePropagator.inject()`.
+    Previously only inbound extraction enforced limits; now
+    inject also caps entries at 180, individual pairs at 4096
+    bytes, and total header at 8192 bytes per the W3C Baggage
+    spec. The extract path max_pairs limit now counts all size-
+    valid entries rather than only successfully parsed ones.
+  * `opentelemetry-sdk`: fix multi-processor `force_flush`
+    skipping remaining processors when one returns `None`
+  * `opentelemetry-test-utils`: fix weaver live check hanging
+    when weaver log output fills the pipe buffer
+
+-------------------------------------------------------------------

Old:
----
  opentelemetry_exporter_otlp_proto_grpc-1.41.1.tar.gz

New:
----
  opentelemetry_exporter_otlp_proto_grpc-1.42.1.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-opentelemetry-exporter-otlp-proto-grpc.spec ++++++
--- /var/tmp/diff_new_pack.BwN9cc/_old  2026-06-27 18:05:49.399417588 +0200
+++ /var/tmp/diff_new_pack.BwN9cc/_new  2026-06-27 18:05:49.403417722 +0200
@@ -18,7 +18,7 @@
 
 %{?sle15_python_module_pythons}
 Name:           python-opentelemetry-exporter-otlp-proto-grpc
-Version:        1.41.1
+Version:        1.42.1
 Release:        0
 Summary:        OpenTelemetry Collector Protobuf over gRPC Exporter
 License:        Apache-2.0

++++++ opentelemetry_exporter_otlp_proto_grpc-1.41.1.tar.gz -> 
opentelemetry_exporter_otlp_proto_grpc-1.42.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/opentelemetry_exporter_otlp_proto_grpc-1.41.1/PKG-INFO 
new/opentelemetry_exporter_otlp_proto_grpc-1.42.1/PKG-INFO
--- old/opentelemetry_exporter_otlp_proto_grpc-1.41.1/PKG-INFO  2020-02-02 
01:00:00.000000000 +0100
+++ new/opentelemetry_exporter_otlp_proto_grpc-1.42.1/PKG-INFO  2020-02-02 
01:00:00.000000000 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 2.4
 Name: opentelemetry-exporter-otlp-proto-grpc
-Version: 1.41.1
+Version: 1.42.1
 Summary: OpenTelemetry Collector Protobuf over gRPC Exporter
 Project-URL: Homepage, 
https://github.com/open-telemetry/opentelemetry-python/tree/main/exporter/opentelemetry-exporter-otlp-proto-grpc
 Project-URL: Repository, https://github.com/open-telemetry/opentelemetry-python
@@ -13,21 +13,20 @@
 Classifier: Intended Audience :: Developers
 Classifier: Programming Language :: Python
 Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.9
 Classifier: Programming Language :: Python :: 3.10
 Classifier: Programming Language :: Python :: 3.11
 Classifier: Programming Language :: Python :: 3.12
 Classifier: Programming Language :: Python :: 3.13
 Classifier: Programming Language :: Python :: 3.14
-Requires-Python: >=3.9
+Requires-Python: >=3.10
 Requires-Dist: googleapis-common-protos~=1.57
 Requires-Dist: grpcio<2.0.0,>=1.63.2; python_version < '3.13'
 Requires-Dist: grpcio<2.0.0,>=1.66.2; python_version == '3.13'
 Requires-Dist: grpcio<2.0.0,>=1.75.1; python_version >= '3.14'
 Requires-Dist: opentelemetry-api~=1.15
-Requires-Dist: opentelemetry-exporter-otlp-proto-common==1.41.1
-Requires-Dist: opentelemetry-proto==1.41.1
-Requires-Dist: opentelemetry-sdk~=1.41.1
+Requires-Dist: opentelemetry-exporter-otlp-proto-common==1.42.1
+Requires-Dist: opentelemetry-proto==1.42.1
+Requires-Dist: opentelemetry-sdk~=1.42.1
 Requires-Dist: typing-extensions>=4.6.0
 Provides-Extra: gcp-auth
 Requires-Dist: opentelemetry-exporter-credential-provider-gcp>=0.59b0; extra 
== 'gcp-auth'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/opentelemetry_exporter_otlp_proto_grpc-1.41.1/pyproject.toml 
new/opentelemetry_exporter_otlp_proto_grpc-1.42.1/pyproject.toml
--- old/opentelemetry_exporter_otlp_proto_grpc-1.41.1/pyproject.toml    
2020-02-02 01:00:00.000000000 +0100
+++ new/opentelemetry_exporter_otlp_proto_grpc-1.42.1/pyproject.toml    
2020-02-02 01:00:00.000000000 +0100
@@ -8,7 +8,7 @@
 description = "OpenTelemetry Collector Protobuf over gRPC Exporter"
 readme = "README.rst"
 license = "Apache-2.0"
-requires-python = ">=3.9"
+requires-python = ">=3.10"
 authors = [
   { name = "OpenTelemetry Authors", email = 
"[email protected]" },
 ]
@@ -19,7 +19,6 @@
   "Intended Audience :: Developers",
   "Programming Language :: Python",
   "Programming Language :: Python :: 3",
-  "Programming Language :: Python :: 3.9",
   "Programming Language :: Python :: 3.10",
   "Programming Language :: Python :: 3.11",
   "Programming Language :: Python :: 3.12",
@@ -32,9 +31,9 @@
   "grpcio >= 1.66.2, < 2.0.0; python_version == '3.13'",
   "grpcio >= 1.75.1, < 2.0.0; python_version >= '3.14'",
   "opentelemetry-api ~= 1.15",
-  "opentelemetry-proto == 1.41.1",
-  "opentelemetry-sdk ~= 1.41.1",
-  "opentelemetry-exporter-otlp-proto-common == 1.41.1",
+  "opentelemetry-proto == 1.42.1",
+  "opentelemetry-sdk ~= 1.42.1",
+  "opentelemetry-exporter-otlp-proto-common == 1.42.1",
   "typing-extensions >= 4.6.0",
 ]
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/opentelemetry_exporter_otlp_proto_grpc-1.41.1/src/opentelemetry/exporter/otlp/proto/grpc/__init__.py
 
new/opentelemetry_exporter_otlp_proto_grpc-1.42.1/src/opentelemetry/exporter/otlp/proto/grpc/__init__.py
--- 
old/opentelemetry_exporter_otlp_proto_grpc-1.41.1/src/opentelemetry/exporter/otlp/proto/grpc/__init__.py
    2020-02-02 01:00:00.000000000 +0100
+++ 
new/opentelemetry_exporter_otlp_proto_grpc-1.42.1/src/opentelemetry/exporter/otlp/proto/grpc/__init__.py
    2020-02-02 01:00:00.000000000 +0100
@@ -1,16 +1,5 @@
 # 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.
+# SPDX-License-Identifier: Apache-2.0
 
 
 """
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/opentelemetry_exporter_otlp_proto_grpc-1.41.1/src/opentelemetry/exporter/otlp/proto/grpc/_log_exporter/__init__.py
 
new/opentelemetry_exporter_otlp_proto_grpc-1.42.1/src/opentelemetry/exporter/otlp/proto/grpc/_log_exporter/__init__.py
--- 
old/opentelemetry_exporter_otlp_proto_grpc-1.41.1/src/opentelemetry/exporter/otlp/proto/grpc/_log_exporter/__init__.py
      2020-02-02 01:00:00.000000000 +0100
+++ 
new/opentelemetry_exporter_otlp_proto_grpc-1.42.1/src/opentelemetry/exporter/otlp/proto/grpc/_log_exporter/__init__.py
      2020-02-02 01:00:00.000000000 +0100
@@ -1,27 +1,19 @@
 # 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.
+# SPDX-License-Identifier: Apache-2.0
 
+from collections.abc import Iterable, Sequence
+from collections.abc import Sequence as TypingSequence
 from os import environ
-from typing import Dict, Literal, Optional, Sequence, Tuple, Union
-from typing import Sequence as TypingSequence
+from typing import Literal
 
-from grpc import ChannelCredentials, Compression
+from grpc import ChannelCredentials, Compression, StatusCode
 from opentelemetry.exporter.otlp.proto.common._log_encoder import encode_logs
 from opentelemetry.exporter.otlp.proto.grpc.exporter import (
     OTLPExporterMixin,
     _get_credentials,
     environ_to_compression,
 )
+from opentelemetry.metrics import MeterProvider
 from opentelemetry.proto.collector.logs.v1.logs_service_pb2 import (
     ExportLogsServiceRequest,
 )
@@ -44,6 +36,9 @@
     OTEL_EXPORTER_OTLP_LOGS_INSECURE,
     OTEL_EXPORTER_OTLP_LOGS_TIMEOUT,
 )
+from opentelemetry.semconv._incubating.attributes.otel_attributes import (
+    OtelComponentTypeValues,
+)
 
 
 class OTLPLogExporter(
@@ -57,15 +52,19 @@
 ):
     def __init__(
         self,
-        endpoint: Optional[str] = None,
-        insecure: Optional[bool] = None,
-        credentials: Optional[ChannelCredentials] = None,
-        headers: Optional[
-            Union[TypingSequence[Tuple[str, str]], Dict[str, str], str]
-        ] = None,
-        timeout: Optional[float] = None,
-        compression: Optional[Compression] = None,
-        channel_options: Optional[Tuple[Tuple[str, str]]] = None,
+        endpoint: str | None = None,
+        insecure: bool | None = None,
+        credentials: ChannelCredentials | None = None,
+        headers: TypingSequence[tuple[str, str]]
+        | dict[str, str]
+        | str
+        | None = None,
+        timeout: float | None = None,
+        compression: Compression | None = None,
+        channel_options: tuple[tuple[str, str]] | None = None,
+        retryable_error_codes: Iterable[StatusCode] | None = None,
+        *,
+        meter_provider: MeterProvider | None = None,
     ):
         insecure_logs = environ.get(OTEL_EXPORTER_OTLP_LOGS_INSECURE)
         if insecure is None and insecure_logs is not None:
@@ -105,6 +104,10 @@
             stub=LogsServiceStub,
             result=LogRecordExportResult,
             channel_options=channel_options,
+            retryable_error_codes=retryable_error_codes,
+            component_type=OtelComponentTypeValues.OTLP_GRPC_LOG_EXPORTER,
+            signal="logs",
+            meter_provider=meter_provider,
         )
 
     def _translate_data(
@@ -112,6 +115,9 @@
     ) -> ExportLogsServiceRequest:
         return encode_logs(data)
 
+    def _count_data(self, data: Sequence[ReadableLogRecord]):
+        return len(data)
+
     def export(  # type: ignore [reportIncompatibleMethodOverride]
         self,
         batch: Sequence[ReadableLogRecord],
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/opentelemetry_exporter_otlp_proto_grpc-1.41.1/src/opentelemetry/exporter/otlp/proto/grpc/exporter.py
 
new/opentelemetry_exporter_otlp_proto_grpc-1.42.1/src/opentelemetry/exporter/otlp/proto/grpc/exporter.py
--- 
old/opentelemetry_exporter_otlp_proto_grpc-1.41.1/src/opentelemetry/exporter/otlp/proto/grpc/exporter.py
    2020-02-02 01:00:00.000000000 +0100
+++ 
new/opentelemetry_exporter_otlp_proto_grpc-1.42.1/src/opentelemetry/exporter/otlp/proto/grpc/exporter.py
    2020-02-02 01:00:00.000000000 +0100
@@ -1,16 +1,5 @@
 # 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.
+# SPDX-License-Identifier: Apache-2.0
 
 """OTLP Exporter
 
@@ -20,28 +9,28 @@
 
 """
 
+import os
 import random
 import threading
 from abc import ABC, abstractmethod
-from collections.abc import Sequence  # noqa: F401
+from collections.abc import (
+    Callable,
+    Iterable,
+    Sequence,  # noqa: F401
+)
+from collections.abc import Sequence as TypingSequence
 from logging import getLogger
 from os import environ
 from time import time
 from typing import (  # noqa: F401
     Any,
-    Callable,
-    Dict,
     Generic,
-    List,
     Literal,
     NewType,
     Optional,
-    Tuple,
-    Type,
     TypeVar,
     Union,
 )
-from typing import Sequence as TypingSequence
 from urllib.parse import urlparse
 
 from google.rpc.error_details_pb2 import RetryInfo
@@ -56,12 +45,16 @@
     secure_channel,
     ssl_channel_credentials,
 )
+from opentelemetry.exporter.otlp.proto.common._exporter_metrics import (
+    create_exporter_metrics,
+)
 from opentelemetry.exporter.otlp.proto.common._internal import (
     _get_resource_data,
 )
 from opentelemetry.exporter.otlp.proto.grpc import (
     _OTLP_GRPC_CHANNEL_OPTIONS,
 )
+from opentelemetry.metrics import MeterProvider
 from opentelemetry.proto.collector.logs.v1.logs_service_pb2 import (
     ExportLogsServiceRequest,
 )
@@ -91,6 +84,7 @@
 from opentelemetry.sdk._shared_internal import DuplicateFilter
 from opentelemetry.sdk.environment_variables import (
     _OTEL_PYTHON_EXPORTER_OTLP_GRPC_CREDENTIAL_PROVIDER,
+    _OTEL_PYTHON_EXPORTER_OTLP_GRPC_RETRYABLE_ERROR_CODES,
     OTEL_EXPORTER_OTLP_CERTIFICATE,
     OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE,
     OTEL_EXPORTER_OTLP_CLIENT_KEY,
@@ -99,11 +93,18 @@
     OTEL_EXPORTER_OTLP_HEADERS,
     OTEL_EXPORTER_OTLP_INSECURE,
     OTEL_EXPORTER_OTLP_TIMEOUT,
+    OTEL_PYTHON_SDK_INTERNAL_METRICS_ENABLED,
 )
 from opentelemetry.sdk.metrics.export import MetricExportResult, MetricsData
 from opentelemetry.sdk.resources import Resource as SDKResource
 from opentelemetry.sdk.trace import ReadableSpan
 from opentelemetry.sdk.trace.export import SpanExportResult
+from opentelemetry.semconv._incubating.attributes.otel_attributes import (
+    OtelComponentTypeValues,
+)
+from opentelemetry.semconv._incubating.attributes.rpc_attributes import (
+    RPC_RESPONSE_STATUS_CODE,
+)
 from opentelemetry.util._importlib_metadata import entry_points
 from opentelemetry.util.re import parse_env_headers
 
@@ -159,7 +160,7 @@
         )
 
 
-def environ_to_compression(environ_key: str) -> Optional[Compression]:
+def environ_to_compression(environ_key: str) -> Compression | None:
     environ_value = (
         environ[environ_key].lower().strip()
         if environ_key in environ
@@ -177,14 +178,14 @@
     "Use one of the encoders from opentelemetry-exporter-otlp-proto-common 
instead. Deprecated since version 1.18.0.",
 )
 def get_resource_data(
-    sdk_resource_scope_data: Dict[SDKResource, ResourceDataT],
+    sdk_resource_scope_data: dict[SDKResource, ResourceDataT],
     resource_class: Callable[..., TypingResourceT],
     name: str,
-) -> List[TypingResourceT]:
+) -> list[TypingResourceT]:
     return _get_resource_data(sdk_resource_scope_data, resource_class, name)
 
 
-def _read_file(file_path: str) -> Optional[bytes]:
+def _read_file(file_path: str) -> bytes | None:
     try:
         with open(file_path, "rb") as file:
             return file.read()
@@ -197,9 +198,9 @@
 
 
 def _load_credentials(
-    certificate_file: Optional[str],
-    client_key_file: Optional[str],
-    client_certificate_file: Optional[str],
+    certificate_file: str | None,
+    client_key_file: str | None,
+    client_certificate_file: str | None,
 ) -> ChannelCredentials:
     root_certificates = (
         _read_file(certificate_file) if certificate_file else None
@@ -219,7 +220,7 @@
 
 
 def _get_credentials(
-    creds: Optional[ChannelCredentials],
+    creds: ChannelCredentials | None,
     credential_entry_point_env_key: str,
     certificate_file_env_key: str,
     client_key_file_env_key: str,
@@ -288,15 +289,21 @@
         self,
         stub: ExportStubT,
         result: ExportResultT,
-        endpoint: Optional[str] = None,
-        insecure: Optional[bool] = None,
-        credentials: Optional[ChannelCredentials] = None,
-        headers: Optional[
-            Union[TypingSequence[Tuple[str, str]], Dict[str, str], str]
-        ] = None,
-        timeout: Optional[float] = None,
-        compression: Optional[Compression] = None,
-        channel_options: Optional[Tuple[Tuple[str, str]]] = None,
+        endpoint: str | None = None,
+        insecure: bool | None = None,
+        credentials: ChannelCredentials | None = None,
+        headers: TypingSequence[tuple[str, str]]
+        | dict[str, str]
+        | str
+        | None = None,
+        timeout: float | None = None,
+        compression: Compression | None = None,
+        channel_options: tuple[tuple[str, str]] | None = None,
+        retryable_error_codes: Iterable[StatusCode] | None = None,
+        *,
+        component_type: OtelComponentTypeValues | None = None,
+        signal: Literal["traces", "metrics", "logs"] = "traces",
+        meter_provider: MeterProvider | None = None,
     ):
         super().__init__()
         self._result = result
@@ -355,6 +362,22 @@
             else compression
         ) or Compression.NoCompression
 
+        self._retryable_error_codes = retryable_error_codes or os.environ.get(
+            _OTEL_PYTHON_EXPORTER_OTLP_GRPC_RETRYABLE_ERROR_CODES
+        )
+        if isinstance(self._retryable_error_codes, str):
+            self._retryable_error_codes = frozenset(
+                StatusCode[code.strip().upper()]
+                for code in self._retryable_error_codes.split(",")
+                if code.strip()
+            )
+        elif self._retryable_error_codes is not None:
+            self._retryable_error_codes = frozenset(
+                self._retryable_error_codes
+            )
+        else:
+            self._retryable_error_codes = _RETRYABLE_ERROR_CODES
+
         self._channel = None
         self._client = None
 
@@ -370,6 +393,20 @@
                 OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE,
             )
 
+        self._component_type = component_type
+        self._signal: Literal["traces", "metrics", "logs"] = signal
+        self._parsed_url = parsed_url
+        self._metrics = create_exporter_metrics(
+            self._component_type,
+            signal,
+            parsed_url,
+            meter_provider,
+            os.environ.get(OTEL_PYTHON_SDK_INTERNAL_METRICS_ENABLED, "")
+            .strip()
+            .lower()
+            == "true",
+        )
+
         self._initialize_channel_and_stub()
 
     def _initialize_channel_and_stub(self):
@@ -402,6 +439,13 @@
     ) -> ExportServiceRequestT:
         pass
 
+    @abstractmethod
+    def _count_data(
+        self,
+        data: SDKDataT,
+    ) -> int:
+        pass
+
     def _export(
         self,
         data: SDKDataT,
@@ -410,80 +454,88 @@
             logger.warning("Exporter already shutdown, ignoring batch")
             return self._result.FAILURE  # type: ignore [reportReturnType]
 
-        # FIXME remove this check if the export type for traces
-        # gets updated to a class that represents the proto
-        # TracesData and use the code below instead.
-        deadline_sec = time() + self._timeout
-        for retry_num in range(_MAX_RETRYS):
-            try:
-                if self._client is None:
-                    return self._result.FAILURE
-                self._client.Export(
-                    request=self._translate_data(data),
-                    metadata=self._headers,
-                    timeout=deadline_sec - time(),
-                )
-                return self._result.SUCCESS  # type: ignore [reportReturnType]
-            except RpcError as error:
-                retry_info_bin = dict(error.trailing_metadata()).get(  # type: 
ignore [reportAttributeAccessIssue]
-                    "google.rpc.retryinfo-bin"  # type: ignore 
[reportArgumentType]
-                )
-                # multiplying by a random number between .8 and 1.2 introduces 
a +/20% jitter to each backoff.
-                backoff_seconds = 2**retry_num * random.uniform(0.8, 1.2)
-                if retry_info_bin is not None:
-                    retry_info = RetryInfo()
-                    retry_info.ParseFromString(retry_info_bin)
-                    backoff_seconds = (
-                        retry_info.retry_delay.seconds
-                        + retry_info.retry_delay.nanos / 1.0e9
+        with self._metrics.export_operation(self._count_data(data)) as result:
+            # FIXME remove this check if the export type for traces
+            # gets updated to a class that represents the proto
+            # TracesData and use the code below instead.
+            deadline_sec = time() + self._timeout
+            for retry_num in range(_MAX_RETRYS):
+                try:
+                    if self._client is None:
+                        return self._result.FAILURE
+                    self._client.Export(
+                        request=self._translate_data(data),
+                        metadata=self._headers,
+                        timeout=deadline_sec - time(),
                     )
-
-                # For UNAVAILABLE errors, reinitialize the channel to force 
reconnection
-                if error.code() == StatusCode.UNAVAILABLE and retry_num == 0:  
# type: ignore
-                    logger.debug(
-                        "Reinitializing gRPC channel for %s exporter due to 
UNAVAILABLE error",
-                        self._exporting,
+                    return self._result.SUCCESS  # type: ignore 
[reportReturnType]
+                except RpcError as error:
+                    retry_info_bin = dict(error.trailing_metadata()).get(  # 
type: ignore [reportAttributeAccessIssue]
+                        "google.rpc.retryinfo-bin"  # type: ignore 
[reportArgumentType]
                     )
-                    try:
-                        if self._channel:
-                            self._channel.close()
-                    except Exception as e:
+                    # multiplying by a random number between .8 and 1.2 
introduces a +/20% jitter to each backoff.
+                    backoff_seconds = 2**retry_num * random.uniform(0.8, 1.2)
+                    if retry_info_bin is not None:
+                        retry_info = RetryInfo()
+                        retry_info.ParseFromString(retry_info_bin)
+                        backoff_seconds = (
+                            retry_info.retry_delay.seconds
+                            + retry_info.retry_delay.nanos / 1.0e9
+                        )
+
+                    # For UNAVAILABLE errors, reinitialize the channel to 
force reconnection
+                    if (
+                        error.code() == StatusCode.UNAVAILABLE
+                        and retry_num == 0
+                    ):  # type: ignore
                         logger.debug(
-                            "Error closing channel for %s exporter to %s: %s",
+                            "Reinitializing gRPC channel for %s exporter due 
to UNAVAILABLE error",
+                            self._exporting,
+                        )
+                        try:
+                            if self._channel:
+                                self._channel.close()
+                        except Exception as e:
+                            logger.debug(
+                                "Error closing channel for %s exporter to %s: 
%s",
+                                self._exporting,
+                                self._endpoint,
+                                str(e),
+                            )
+                        # Enable channel reconnection for subsequent calls
+                        self._initialize_channel_and_stub()
+
+                    if (
+                        error.code() not in self._retryable_error_codes  # 
type: ignore [reportAttributeAccessIssue]
+                        or retry_num + 1 == _MAX_RETRYS
+                        or backoff_seconds > (deadline_sec - time())
+                        or self._shutdown
+                    ):
+                        logger.error(
+                            "Failed to export %s to %s, error code: %s",
                             self._exporting,
                             self._endpoint,
-                            str(e),
+                            error.code(),  # type: ignore 
[reportAttributeAccessIssue]
+                            exc_info=error.code() == StatusCode.UNKNOWN,  # 
type: ignore [reportAttributeAccessIssue]
                         )
-                    # Enable channel reconnection for subsequent calls
-                    self._initialize_channel_and_stub()
-
-                if (
-                    error.code() not in _RETRYABLE_ERROR_CODES  # type: ignore 
[reportAttributeAccessIssue]
-                    or retry_num + 1 == _MAX_RETRYS
-                    or backoff_seconds > (deadline_sec - time())
-                    or self._shutdown
-                ):
-                    logger.error(
-                        "Failed to export %s to %s, error code: %s",
+                        result.error = error
+                        result.error_attrs = {
+                            RPC_RESPONSE_STATUS_CODE: error.code().name
+                        }
+                        return self._result.FAILURE  # type: ignore 
[reportReturnType]
+                    logger.warning(
+                        "Transient error %s encountered while exporting %s to 
%s, retrying in %.2fs.",
+                        error.code(),  # type: ignore 
[reportAttributeAccessIssue]
                         self._exporting,
                         self._endpoint,
-                        error.code(),  # type: ignore 
[reportAttributeAccessIssue]
-                        exc_info=error.code() == StatusCode.UNKNOWN,  # type: 
ignore [reportAttributeAccessIssue]
+                        backoff_seconds,
                     )
-                    return self._result.FAILURE  # type: ignore 
[reportReturnType]
-                logger.warning(
-                    "Transient error %s encountered while exporting %s to %s, 
retrying in %.2fs.",
-                    error.code(),  # type: ignore [reportAttributeAccessIssue]
-                    self._exporting,
-                    self._endpoint,
-                    backoff_seconds,
-                )
-            shutdown = self._shutdown_in_progress.wait(backoff_seconds)
-            if shutdown:
-                logger.warning("Shutdown in progress, aborting retry.")
-                break
-        # Not possible to reach here but the linter is complaining.
-        return self._result.FAILURE  # type: ignore [reportReturnType]
+                shutdown = self._shutdown_in_progress.wait(backoff_seconds)
+                if shutdown:
+                    logger.warning("Shutdown in progress, aborting retry.")
+                    break
+            # Not possible to reach here but the linter is complaining.
+            return self._result.FAILURE  # type: ignore [reportReturnType]
 
     def shutdown(self, timeout_millis: float = 30_000, **kwargs) -> None:
         """
@@ -508,3 +560,15 @@
         warning messages.
         """
         pass
+
+    def _set_meter_provider(self, meter_provider: MeterProvider) -> None:
+        self._metrics = create_exporter_metrics(
+            self._component_type,
+            self._signal,
+            self._parsed_url,
+            meter_provider,
+            os.environ.get(OTEL_PYTHON_SDK_INTERNAL_METRICS_ENABLED, "")
+            .strip()
+            .lower()
+            == "true",
+        )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/opentelemetry_exporter_otlp_proto_grpc-1.41.1/src/opentelemetry/exporter/otlp/proto/grpc/metric_exporter/__init__.py
 
new/opentelemetry_exporter_otlp_proto_grpc-1.42.1/src/opentelemetry/exporter/otlp/proto/grpc/metric_exporter/__init__.py
--- 
old/opentelemetry_exporter_otlp_proto_grpc-1.41.1/src/opentelemetry/exporter/otlp/proto/grpc/metric_exporter/__init__.py
    2020-02-02 01:00:00.000000000 +0100
+++ 
new/opentelemetry_exporter_otlp_proto_grpc-1.42.1/src/opentelemetry/exporter/otlp/proto/grpc/metric_exporter/__init__.py
    2020-02-02 01:00:00.000000000 +0100
@@ -1,25 +1,15 @@
 # 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.
+# SPDX-License-Identifier: Apache-2.0
 
 from __future__ import annotations
 
+from collections.abc import Iterable
+from collections.abc import Sequence as TypingSequence
 from dataclasses import replace
 from logging import getLogger
 from os import environ
-from typing import Iterable, List, Tuple, Union
-from typing import Sequence as TypingSequence
 
-from grpc import ChannelCredentials, Compression
+from grpc import ChannelCredentials, Compression, StatusCode
 from opentelemetry.exporter.otlp.proto.common._internal.metrics_encoder import 
(
     OTLPMetricExporterMixin,
 )
@@ -32,6 +22,7 @@
     environ_to_compression,
     get_resource_data,
 )
+from opentelemetry.metrics import MeterProvider
 from opentelemetry.proto.collector.metrics.v1.metrics_service_pb2 import (
     ExportMetricsServiceRequest,
 )
@@ -72,6 +63,9 @@
 from opentelemetry.sdk.metrics.export import (  # noqa: F401
     Histogram as HistogramType,
 )
+from opentelemetry.semconv._incubating.attributes.otel_attributes import (
+    OtelComponentTypeValues,
+)
 
 _logger = getLogger(__name__)
 
@@ -100,7 +94,9 @@
         endpoint: str | None = None,
         insecure: bool | None = None,
         credentials: ChannelCredentials | None = None,
-        headers: Union[TypingSequence[Tuple[str, str]], dict[str, str], str]
+        headers: TypingSequence[tuple[str, str]]
+        | dict[str, str]
+        | str
         | None = None,
         timeout: float | None = None,
         compression: Compression | None = None,
@@ -108,7 +104,10 @@
         | None = None,
         preferred_aggregation: dict[type, Aggregation] | None = None,
         max_export_batch_size: int | None = None,
-        channel_options: Tuple[Tuple[str, str]] | None = None,
+        channel_options: tuple[tuple[str, str]] | None = None,
+        retryable_error_codes: Iterable[StatusCode] | None = None,
+        *,
+        meter_provider: MeterProvider | None = None,
     ):
         insecure_metrics = environ.get(OTEL_EXPORTER_OTLP_METRICS_INSECURE)
         if insecure is None and insecure_metrics is not None:
@@ -153,6 +152,10 @@
             timeout=timeout or environ_timeout,
             compression=compression,
             channel_options=channel_options,
+            retryable_error_codes=retryable_error_codes,
+            component_type=OtelComponentTypeValues.OTLP_GRPC_METRIC_EXPORTER,
+            signal="metrics",
+            meter_provider=meter_provider,
         )
 
         self._max_export_batch_size: int | None = max_export_batch_size
@@ -162,6 +165,16 @@
     ) -> ExportMetricsServiceRequest:
         return encode_metrics(data)
 
+    def _count_data(self, data: MetricsData):
+        num_items = 0
+
+        for resource_metrics in data.resource_metrics:
+            for scope_metrics in resource_metrics.scope_metrics:
+                for metric in scope_metrics.metrics:
+                    num_items += len(metric.data.data_points)
+
+        return num_items
+
     def export(
         self,
         metrics_data: MetricsData,
@@ -187,10 +200,10 @@
     ) -> Iterable[MetricsData]:
         assert self._max_export_batch_size is not None
         batch_size: int = 0
-        split_resource_metrics: List[ResourceMetrics] = []
+        split_resource_metrics: list[ResourceMetrics] = []
 
         for resource_metrics in metrics_data.resource_metrics:
-            split_scope_metrics: List[ScopeMetrics] = []
+            split_scope_metrics: list[ScopeMetrics] = []
             split_resource_metrics.append(
                 replace(
                     resource_metrics,
@@ -198,7 +211,7 @@
                 )
             )
             for scope_metrics in resource_metrics.scope_metrics:
-                split_metrics: List[Metric] = []
+                split_metrics: list[Metric] = []
                 split_scope_metrics.append(
                     replace(
                         scope_metrics,
@@ -206,7 +219,7 @@
                     )
                 )
                 for metric in scope_metrics.metrics:
-                    split_data_points: List[DataPointT] = []
+                    split_data_points: list[DataPointT] = []
                     split_metrics.append(
                         replace(
                             metric,
@@ -268,6 +281,9 @@
     def shutdown(self, timeout_millis: float = 30_000, **kwargs) -> None:
         OTLPExporterMixin.shutdown(self, timeout_millis=timeout_millis)
 
+    def set_meter_provider(self, meter_provider: MeterProvider):
+        return self._set_meter_provider(meter_provider)
+
     @property
     def _exporting(self) -> str:
         return "metrics"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/opentelemetry_exporter_otlp_proto_grpc-1.41.1/src/opentelemetry/exporter/otlp/proto/grpc/trace_exporter/__init__.py
 
new/opentelemetry_exporter_otlp_proto_grpc-1.42.1/src/opentelemetry/exporter/otlp/proto/grpc/trace_exporter/__init__.py
--- 
old/opentelemetry_exporter_otlp_proto_grpc-1.41.1/src/opentelemetry/exporter/otlp/proto/grpc/trace_exporter/__init__.py
     2020-02-02 01:00:00.000000000 +0100
+++ 
new/opentelemetry_exporter_otlp_proto_grpc-1.42.1/src/opentelemetry/exporter/otlp/proto/grpc/trace_exporter/__init__.py
     2020-02-02 01:00:00.000000000 +0100
@@ -1,24 +1,14 @@
 # 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.
+# SPDX-License-Identifier: Apache-2.0
 
 """OTLP Span Exporter"""
 
 import logging
+from collections.abc import Iterable, Sequence
+from collections.abc import Sequence as TypingSequence
 from os import environ
-from typing import Dict, Optional, Sequence, Tuple, Union
-from typing import Sequence as TypingSequence
 
-from grpc import ChannelCredentials, Compression
+from grpc import ChannelCredentials, Compression, StatusCode
 from opentelemetry.exporter.otlp.proto.common.trace_encoder import (
     encode_spans,
 )
@@ -28,6 +18,7 @@
     environ_to_compression,
     get_resource_data,
 )
+from opentelemetry.metrics import MeterProvider
 from opentelemetry.proto.collector.trace.v1.trace_service_pb2 import (
     ExportTraceServiceRequest,
 )
@@ -58,6 +49,9 @@
 )
 from opentelemetry.sdk.trace import ReadableSpan
 from opentelemetry.sdk.trace.export import SpanExporter, SpanExportResult
+from opentelemetry.semconv._incubating.attributes.otel_attributes import (
+    OtelComponentTypeValues,
+)
 
 logger = logging.getLogger(__name__)
 
@@ -86,15 +80,19 @@
 
     def __init__(
         self,
-        endpoint: Optional[str] = None,
-        insecure: Optional[bool] = None,
-        credentials: Optional[ChannelCredentials] = None,
-        headers: Optional[
-            Union[TypingSequence[Tuple[str, str]], Dict[str, str], str]
-        ] = None,
-        timeout: Optional[float] = None,
-        compression: Optional[Compression] = None,
-        channel_options: Optional[Tuple[Tuple[str, str]]] = None,
+        endpoint: str | None = None,
+        insecure: bool | None = None,
+        credentials: ChannelCredentials | None = None,
+        headers: TypingSequence[tuple[str, str]]
+        | dict[str, str]
+        | str
+        | None = None,
+        timeout: float | None = None,
+        compression: Compression | None = None,
+        channel_options: tuple[tuple[str, str]] | None = None,
+        retryable_error_codes: Iterable[StatusCode] | None = None,
+        *,
+        meter_provider: MeterProvider | None = None,
     ):
         insecure_spans = environ.get(OTEL_EXPORTER_OTLP_TRACES_INSECURE)
         if insecure is None and insecure_spans is not None:
@@ -135,6 +133,10 @@
             timeout=timeout or environ_timeout,
             compression=compression,
             channel_options=channel_options,
+            retryable_error_codes=retryable_error_codes,
+            component_type=OtelComponentTypeValues.OTLP_GRPC_SPAN_EXPORTER,
+            signal="traces",
+            meter_provider=meter_provider,
         )
 
     def _translate_data(
@@ -142,6 +144,9 @@
     ) -> ExportTraceServiceRequest:
         return encode_spans(data)
 
+    def _count_data(self, data: Sequence[ReadableSpan]):
+        return len(data)
+
     def export(self, spans: Sequence[ReadableSpan]) -> SpanExportResult:
         return self._export(spans)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/opentelemetry_exporter_otlp_proto_grpc-1.41.1/src/opentelemetry/exporter/otlp/proto/grpc/version/__init__.py
 
new/opentelemetry_exporter_otlp_proto_grpc-1.42.1/src/opentelemetry/exporter/otlp/proto/grpc/version/__init__.py
--- 
old/opentelemetry_exporter_otlp_proto_grpc-1.41.1/src/opentelemetry/exporter/otlp/proto/grpc/version/__init__.py
    2020-02-02 01:00:00.000000000 +0100
+++ 
new/opentelemetry_exporter_otlp_proto_grpc-1.42.1/src/opentelemetry/exporter/otlp/proto/grpc/version/__init__.py
    2020-02-02 01:00:00.000000000 +0100
@@ -1,15 +1,4 @@
 # 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.
+# SPDX-License-Identifier: Apache-2.0
 
-__version__ = "1.41.1"
+__version__ = "1.42.1"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/opentelemetry_exporter_otlp_proto_grpc-1.41.1/tests/logs/test_otlp_logs_exporter.py
 
new/opentelemetry_exporter_otlp_proto_grpc-1.42.1/tests/logs/test_otlp_logs_exporter.py
--- 
old/opentelemetry_exporter_otlp_proto_grpc-1.41.1/tests/logs/test_otlp_logs_exporter.py
     2020-02-02 01:00:00.000000000 +0100
+++ 
new/opentelemetry_exporter_otlp_proto_grpc-1.42.1/tests/logs/test_otlp_logs_exporter.py
     2020-02-02 01:00:00.000000000 +0100
@@ -1,16 +1,5 @@
 # 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.
+# SPDX-License-Identifier: Apache-2.0
 
 # pylint: disable=too-many-lines
 
@@ -402,6 +391,10 @@
             expected, self.exporter._translate_data([self.log_data_1])
         )
 
+    def test_count_log_data(self):
+        # pylint: disable=protected-access
+        self.assertEqual(1, self.exporter._count_data([self.log_data_1]))
+
     def test_translate_multiple_logs(self):
         expected = ExportLogsServiceRequest(
             resource_logs=[
@@ -539,3 +532,12 @@
                 [self.log_data_1, self.log_data_2, self.log_data_3]
             ),
         )
+
+    def test_count_multiple_logs(self):
+        self.assertEqual(
+            3,
+            # pylint: disable=protected-access
+            self.exporter._count_data(
+                [self.log_data_1, self.log_data_2, self.log_data_3]
+            ),
+        )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/opentelemetry_exporter_otlp_proto_grpc-1.41.1/tests/test_otlp_exporter_mixin.py
 
new/opentelemetry_exporter_otlp_proto_grpc-1.42.1/tests/test_otlp_exporter_mixin.py
--- 
old/opentelemetry_exporter_otlp_proto_grpc-1.41.1/tests/test_otlp_exporter_mixin.py
 2020-02-02 01:00:00.000000000 +0100
+++ 
new/opentelemetry_exporter_otlp_proto_grpc-1.42.1/tests/test_otlp_exporter_mixin.py
 2020-02-02 01:00:00.000000000 +0100
@@ -1,26 +1,16 @@
 # 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.
+# SPDX-License-Identifier: Apache-2.0
 
 import threading
 import time
 import unittest
+from collections.abc import Sequence
 from concurrent.futures import (  # pylint: disable=no-name-in-module
     ThreadPoolExecutor,
 )
 from logging import WARNING, getLogger
 from platform import system
-from typing import Any, Optional, Sequence
+from typing import Any
 from unittest import TestCase
 from unittest.mock import Mock, patch
 
@@ -37,6 +27,7 @@
     encode_spans,
 )
 from opentelemetry.exporter.otlp.proto.grpc.exporter import (  # noqa: F401
+    _RETRYABLE_ERROR_CODES,
     InvalidCompressionValueException,
     OTLPExporterMixin,
     environ_to_compression,
@@ -54,12 +45,18 @@
 from opentelemetry.sdk.environment_variables import (
     _OTEL_PYTHON_EXPORTER_OTLP_GRPC_CREDENTIAL_PROVIDER,
     OTEL_EXPORTER_OTLP_COMPRESSION,
+    OTEL_PYTHON_SDK_INTERNAL_METRICS_ENABLED,
 )
+from opentelemetry.sdk.metrics import MeterProvider
+from opentelemetry.sdk.metrics.export import InMemoryMetricReader
 from opentelemetry.sdk.trace import ReadableSpan, _Span
 from opentelemetry.sdk.trace.export import (
     SpanExporter,
     SpanExportResult,
 )
+from opentelemetry.semconv._incubating.attributes.otel_attributes import (
+    OtelComponentTypeValues,
+)
 from opentelemetry.test.mock_test_classes import IterEntryPoint
 
 logger = getLogger(__name__)
@@ -78,13 +75,23 @@
     ],
 ):
     def __init__(self, **kwargs):
-        super().__init__(TraceServiceStub, SpanExportResult, **kwargs)
+        super().__init__(
+            TraceServiceStub,
+            SpanExportResult,
+            component_type=OtelComponentTypeValues.OTLP_GRPC_SPAN_EXPORTER,
+            signal="traces",
+            meter_provider=kwargs.pop("meter_provider", None),
+            **kwargs,
+        )
 
     def _translate_data(
         self, data: Sequence[ReadableSpan]
     ) -> ExportTraceServiceRequest:
         return encode_spans(data)
 
+    def _count_data(self, data: Sequence[ReadableSpan]) -> int:
+        return len(data)
+
     def export(self, spans: Sequence[ReadableSpan]) -> SpanExportResult:
         return self._export(spans)
 
@@ -100,8 +107,8 @@
     def __init__(
         self,
         export_result: StatusCode,
-        optional_retry_nanos: Optional[int] = None,
-        optional_export_sleep: Optional[float] = None,
+        optional_retry_nanos: int | None = None,
+        optional_export_sleep: float | None = None,
     ):
         self.export_result = export_result
         self.optional_export_sleep = optional_export_sleep
@@ -149,11 +156,12 @@
             # an argument that has a member that points to the thread.
             del self._target, self._args, self._kwargs  # type: ignore
 
-    def join(self, timeout: Optional[float] = None) -> Any:
+    def join(self, timeout: float | None = None) -> Any:
         super().join(timeout=timeout)
         return self._return
 
 
+# pylint: disable-next=too-many-public-methods
 class TestOTLPExporterMixin(TestCase):
     def setUp(self):
         self.server = server(ThreadPoolExecutor(max_workers=10))
@@ -161,7 +169,14 @@
         self.server.add_insecure_port("127.0.0.1:4317")
 
         self.server.start()
-        self.exporter = OTLPSpanExporterForTesting(insecure=True)
+
+        self.metric_reader = InMemoryMetricReader()
+        self.meter_provider = MeterProvider(
+            metric_readers=[self.metric_reader]
+        )
+        self.exporter = OTLPSpanExporterForTesting(
+            insecure=True, meter_provider=self.meter_provider
+        )
         self.span = _Span(
             "a",
             context=Mock(
@@ -364,18 +379,44 @@
             ),
         )
 
+    @patch.dict(
+        "os.environ", {OTEL_PYTHON_SDK_INTERNAL_METRICS_ENABLED: " true "}
+    )
     def test_shutdown(self):
         add_TraceServiceServicer_to_server(
             TraceServiceServicerWithExportParams(StatusCode.OK),
             self.server,
         )
+        exporter = OTLPSpanExporterForTesting(
+            insecure=True, meter_provider=self.meter_provider
+        )
         self.assertEqual(
-            self.exporter.export([self.span]), SpanExportResult.SUCCESS
+            exporter.export([self.span]), SpanExportResult.SUCCESS
         )
-        self.exporter.shutdown()
+        metrics_data = self.metric_reader.get_metrics_data()
+        scope_metrics = metrics_data.resource_metrics[0].scope_metrics[0]
+        self.assertEqual(scope_metrics.scope.name, "opentelemetry-sdk")
+        metrics = sorted(scope_metrics.metrics, key=lambda m: m.name)
+        self.assertEqual(len(metrics), 3)
+        self.assertEqual(
+            metrics[0].name, "otel.sdk.exporter.operation.duration"
+        )
+        self.assert_standard_metric_attrs(
+            metrics[0].data.data_points[0].attributes
+        )
+        self.assertEqual(metrics[1].name, "otel.sdk.exporter.span.exported")
+        self.assert_standard_metric_attrs(
+            metrics[1].data.data_points[0].attributes
+        )
+        self.assertEqual(metrics[2].name, "otel.sdk.exporter.span.inflight")
+        self.assert_standard_metric_attrs(
+            metrics[2].data.data_points[0].attributes
+        )
+
+        exporter.shutdown()
         with self.assertLogs(level=WARNING) as warning:
             self.assertEqual(
-                self.exporter.export([self.span]), SpanExportResult.FAILURE
+                exporter.export([self.span]), SpanExportResult.FAILURE
             )
             self.assertEqual(
                 warning.records[0].message,
@@ -437,6 +478,9 @@
         system() == "Windows",
         "For gRPC + windows there's some added delay in the RPCs which breaks 
the assertion over amount of time passed.",
     )
+    @patch.dict(
+        "os.environ", {OTEL_PYTHON_SDK_INTERNAL_METRICS_ENABLED: "true"}
+    )
     def test_retry_info_is_respected(self):
         mock_trace_service = TraceServiceServicerWithExportParams(
             StatusCode.UNAVAILABLE,
@@ -446,7 +490,9 @@
             mock_trace_service,
             self.server,
         )
-        exporter = OTLPSpanExporterForTesting(insecure=True, timeout=10)
+        exporter = OTLPSpanExporterForTesting(
+            insecure=True, timeout=10, meter_provider=self.meter_provider
+        )
         before = time.time()
         self.assertEqual(
             exporter.export([self.span]),
@@ -457,6 +503,51 @@
         # 1 second plus wiggle room so the test passes consistently.
         self.assertAlmostEqual(after - before, 1, 1)
 
+        metrics_data = self.metric_reader.get_metrics_data()
+        scope_metrics = metrics_data.resource_metrics[0].scope_metrics[0]
+        self.assertEqual(scope_metrics.scope.name, "opentelemetry-sdk")
+        metrics = sorted(scope_metrics.metrics, key=lambda m: m.name)
+        self.assertEqual(len(metrics), 3)
+        self.assertEqual(
+            metrics[0].name, "otel.sdk.exporter.operation.duration"
+        )
+        self.assert_standard_metric_attrs(
+            metrics[0].data.data_points[0].attributes
+        )
+        self.assertEqual(
+            metrics[0].data.data_points[0].attributes["error.type"],
+            "_InactiveRpcError",
+        )
+        self.assertEqual(
+            metrics[0]
+            .data.data_points[0]
+            .attributes["rpc.response.status_code"],
+            "UNAVAILABLE",
+        )
+        self.assertEqual(metrics[1].name, "otel.sdk.exporter.span.exported")
+        self.assert_standard_metric_attrs(
+            metrics[1].data.data_points[0].attributes
+        )
+        self.assertEqual(
+            metrics[1].data.data_points[0].attributes["error.type"],
+            "_InactiveRpcError",
+        )
+        self.assertNotIn(
+            "rpc.response.status_code",
+            metrics[1].data.data_points[0].attributes,
+        )
+        self.assertEqual(metrics[2].name, "otel.sdk.exporter.span.inflight")
+        self.assert_standard_metric_attrs(
+            metrics[2].data.data_points[0].attributes
+        )
+        self.assertNotIn(
+            "error.type", metrics[2].data.data_points[0].attributes
+        )
+        self.assertNotIn(
+            "rpc.response.status_code",
+            metrics[2].data.data_points[0].attributes,
+        )
+
     @unittest.skipIf(
         system() == "Windows",
         "For gRPC + windows there's some added delay in the RPCs which breaks 
the assertion over amount of time passed.",
@@ -532,7 +623,13 @@
             (),
         )
 
+    @patch.dict(
+        "os.environ", {OTEL_PYTHON_SDK_INTERNAL_METRICS_ENABLED: "true"}
+    )
     def test_permanent_failure(self):
+        exporter = OTLPSpanExporterForTesting(
+            insecure=True, meter_provider=self.meter_provider
+        )
         with self.assertLogs(level=WARNING) as warning:
             add_TraceServiceServicer_to_server(
                 TraceServiceServicerWithExportParams(
@@ -541,13 +638,58 @@
                 self.server,
             )
             self.assertEqual(
-                self.exporter.export([self.span]), SpanExportResult.FAILURE
+                exporter.export([self.span]), SpanExportResult.FAILURE
             )
             self.assertEqual(
                 warning.records[-1].message,
                 "Failed to export traces to localhost:4317, error code: 
StatusCode.ALREADY_EXISTS",
             )
 
+        metrics_data = self.metric_reader.get_metrics_data()
+        scope_metrics = metrics_data.resource_metrics[0].scope_metrics[0]
+        self.assertEqual(scope_metrics.scope.name, "opentelemetry-sdk")
+        metrics = sorted(scope_metrics.metrics, key=lambda m: m.name)
+        self.assertEqual(len(metrics), 3)
+        self.assertEqual(
+            metrics[0].name, "otel.sdk.exporter.operation.duration"
+        )
+        self.assert_standard_metric_attrs(
+            metrics[0].data.data_points[0].attributes
+        )
+        self.assertEqual(
+            metrics[0].data.data_points[0].attributes["error.type"],
+            "_InactiveRpcError",
+        )
+        self.assertEqual(
+            metrics[0]
+            .data.data_points[0]
+            .attributes["rpc.response.status_code"],
+            "ALREADY_EXISTS",
+        )
+        self.assertEqual(metrics[1].name, "otel.sdk.exporter.span.exported")
+        self.assert_standard_metric_attrs(
+            metrics[1].data.data_points[0].attributes
+        )
+        self.assertEqual(
+            metrics[1].data.data_points[0].attributes["error.type"],
+            "_InactiveRpcError",
+        )
+        self.assertNotIn(
+            "rpc.response.status_code",
+            metrics[1].data.data_points[0].attributes,
+        )
+        self.assertEqual(metrics[2].name, "otel.sdk.exporter.span.inflight")
+        self.assert_standard_metric_attrs(
+            metrics[2].data.data_points[0].attributes
+        )
+        self.assertNotIn(
+            "error.type", metrics[2].data.data_points[0].attributes
+        )
+        self.assertNotIn(
+            "rpc.response.status_code",
+            metrics[2].data.data_points[0].attributes,
+        )
+
     def test_unavailable_reconnects(self):
         """Test that the exporter reconnects on UNAVAILABLE error"""
         add_TraceServiceServicer_to_server(
@@ -570,4 +712,81 @@
         # Since the initial channel was created in setUp (unpatched), this call
         # must be from the reconnection logic.
         self.assertTrue(mock_insecure_channel.called)
-        # Verify that reconnection enabled flag is set
+
+    def test_retryable_error_codes_initialization(self):
+        # pylint: disable=protected-access
+        self.assertEqual(
+            self.exporter._retryable_error_codes, _RETRYABLE_ERROR_CODES
+        )
+        custom_codes = [StatusCode.INTERNAL, StatusCode.UNKNOWN]
+        exporter = OTLPSpanExporterForTesting(
+            insecure=True, retryable_error_codes=custom_codes
+        )
+        self.assertEqual(
+            exporter._retryable_error_codes, frozenset(custom_codes)
+        )
+
+    @patch.dict(
+        "os.environ",
+        {
+            "OTEL_PYTHON_EXPORTER_OTLP_GRPC_RETRYABLE_ERROR_CODES": 
",INTERNAL, unknown,,,dEAdline_Exceeded "
+        },
+    )
+    def test_retryable_error_codes_initialization_from_env(self):
+        expected_codes = frozenset(
+            {
+                StatusCode.INTERNAL,
+                StatusCode.UNKNOWN,
+                StatusCode.DEADLINE_EXCEEDED,
+            }
+        )
+        exporter = OTLPSpanExporterForTesting()
+        # pylint: disable=protected-access
+        self.assertEqual(exporter._retryable_error_codes, expected_codes)
+
+    @unittest.skipIf(
+        system() == "Windows",
+        "For gRPC + windows there's some added delay in the RPCs which breaks 
the assertion over amount of time passed.",
+    )
+    def test_retryable_error_codes_custom(self):
+        # Test that a custom error code is retried if specified
+        custom_codes = [StatusCode.INTERNAL]
+        mock_trace_service = TraceServiceServicerWithExportParams(
+            StatusCode.INTERNAL,
+            optional_retry_nanos=200000000,  # .2 seconds
+        )
+        add_TraceServiceServicer_to_server(
+            mock_trace_service,
+            self.server,
+        )
+        exporter = OTLPSpanExporterForTesting(
+            insecure=True, retryable_error_codes=custom_codes, timeout=10
+        )
+
+        self.assertEqual(
+            exporter.export([self.span]),
+            SpanExportResult.FAILURE,
+        )
+
+        self.assertEqual(mock_trace_service.num_requests, 6)
+
+        # Test that a default retryable code is NOT retried if not in 
custom_codes
+        mock_trace_service.num_requests = 0
+        mock_trace_service.export_result = StatusCode.UNAVAILABLE
+        self.assertEqual(
+            exporter.export([self.span]),
+            SpanExportResult.FAILURE,
+        )
+        self.assertEqual(mock_trace_service.num_requests, 1)
+
+    def assert_standard_metric_attrs(self, attributes):
+        self.assertEqual(
+            attributes["otel.component.type"], "otlp_grpc_span_exporter"
+        )
+        self.assertTrue(
+            attributes["otel.component.name"].startswith(
+                "otlp_grpc_span_exporter/"
+            )
+        )
+        self.assertEqual(attributes["server.address"], "localhost")
+        self.assertEqual(attributes["server.port"], 4317)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/opentelemetry_exporter_otlp_proto_grpc-1.41.1/tests/test_otlp_metrics_exporter.py
 
new/opentelemetry_exporter_otlp_proto_grpc-1.42.1/tests/test_otlp_metrics_exporter.py
--- 
old/opentelemetry_exporter_otlp_proto_grpc-1.41.1/tests/test_otlp_metrics_exporter.py
       2020-02-02 01:00:00.000000000 +0100
+++ 
new/opentelemetry_exporter_otlp_proto_grpc-1.42.1/tests/test_otlp_metrics_exporter.py
       2020-02-02 01:00:00.000000000 +0100
@@ -1,22 +1,10 @@
 # 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.
+# SPDX-License-Identifier: Apache-2.0
 
 # pylint: disable=too-many-lines
 from logging import WARNING
 from os import environ
 from os.path import dirname
-from typing import List
 from unittest import TestCase
 from unittest.mock import patch
 
@@ -345,7 +333,7 @@
             ]
         )
         # WHEN
-        split_metrics_data: List[MetricsData] = list(
+        split_metrics_data: list[MetricsData] = list(
             # pylint: disable=protected-access
             OTLPMetricExporter(max_export_batch_size=2)._split_metrics_data(
                 metrics_data=metrics_data,
@@ -424,7 +412,7 @@
             ]
         )
         # WHEN
-        split_metrics_data: List[MetricsData] = list(
+        split_metrics_data: list[MetricsData] = list(
             # pylint: disable=protected-access
             OTLPMetricExporter(max_export_batch_size=3)._split_metrics_data(
                 metrics_data=metrics_data,
@@ -515,7 +503,7 @@
             ]
         )
         # WHEN
-        split_metrics_data: List[MetricsData] = list(
+        split_metrics_data: list[MetricsData] = list(
             # pylint: disable=protected-access
             OTLPMetricExporter(max_export_batch_size=2)._split_metrics_data(
                 metrics_data=metrics_data,
@@ -590,6 +578,69 @@
             split_metrics_data,
         )
 
+    def test_count_metrics_data(self):
+        # GIVEN
+        metrics_data = MetricsData(
+            resource_metrics=[
+                _resource_metrics(
+                    index=1,
+                    scope_metrics=[
+                        _scope_metrics(
+                            index=1,
+                            metrics=[
+                                _gauge(
+                                    index=1,
+                                    data_points=[
+                                        _number_data_point(11),
+                                    ],
+                                ),
+                                _gauge(
+                                    index=2,
+                                    data_points=[
+                                        _number_data_point(12),
+                                    ],
+                                ),
+                            ],
+                        ),
+                        _scope_metrics(
+                            index=2,
+                            metrics=[
+                                _gauge(
+                                    index=3,
+                                    data_points=[
+                                        _number_data_point(13),
+                                    ],
+                                ),
+                            ],
+                        ),
+                    ],
+                ),
+                _resource_metrics(
+                    index=2,
+                    scope_metrics=[
+                        _scope_metrics(
+                            index=3,
+                            metrics=[
+                                _gauge(
+                                    index=4,
+                                    data_points=[
+                                        _number_data_point(14),
+                                    ],
+                                ),
+                            ],
+                        ),
+                    ],
+                ),
+            ]
+        )
+        # WHEN
+        # pylint: disable=protected-access
+        count = OTLPMetricExporter(max_export_batch_size=2)._count_data(
+            metrics_data,
+        )
+        # THEN
+        self.assertEqual(count, 4)
+
     @patch("opentelemetry.exporter.otlp.proto.grpc.exporter.secure_channel")
     def test_insecure_https_endpoint(self, mock_secure_channel):
         OTLPMetricExporter(endpoint="https://ab.c:123";, insecure=True)
@@ -766,7 +817,7 @@
 
 
 def _resource_metrics(
-    index: int, scope_metrics: List[ScopeMetrics]
+    index: int, scope_metrics: list[ScopeMetrics]
 ) -> ResourceMetrics:
     return ResourceMetrics(
         resource=Resource(
@@ -778,7 +829,7 @@
     )
 
 
-def _scope_metrics(index: int, metrics: List[Metric]) -> ScopeMetrics:
+def _scope_metrics(index: int, metrics: list[Metric]) -> ScopeMetrics:
     return ScopeMetrics(
         scope=InstrumentationScope(name=f"scope_{index}"),
         schema_url=f"scope_url_{index}",
@@ -786,7 +837,7 @@
     )
 
 
-def _gauge(index: int, data_points: List[NumberDataPoint]) -> Metric:
+def _gauge(index: int, data_points: list[NumberDataPoint]) -> Metric:
     return Metric(
         name=f"gauge_{index}",
         description="description",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/opentelemetry_exporter_otlp_proto_grpc-1.41.1/tests/test_otlp_trace_exporter.py
 
new/opentelemetry_exporter_otlp_proto_grpc-1.42.1/tests/test_otlp_trace_exporter.py
--- 
old/opentelemetry_exporter_otlp_proto_grpc-1.41.1/tests/test_otlp_trace_exporter.py
 2020-02-02 01:00:00.000000000 +0100
+++ 
new/opentelemetry_exporter_otlp_proto_grpc-1.42.1/tests/test_otlp_trace_exporter.py
 2020-02-02 01:00:00.000000000 +0100
@@ -1,16 +1,5 @@
 # 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.
+# SPDX-License-Identifier: Apache-2.0
 
 # pylint: disable=too-many-lines
 
@@ -481,6 +470,10 @@
         # pylint: disable=protected-access
         self.assertEqual(expected, self.exporter._translate_data([self.span]))
 
+    def test_count_spans(self):
+        # pylint: disable=protected-access
+        self.assertEqual(1, self.exporter._count_data([self.span]))
+
     def test_translate_spans_multi(self):
         expected = ExportTraceServiceRequest(
             resource_spans=[
@@ -660,6 +653,13 @@
             self.exporter._translate_data([self.span, self.span2, self.span3]),
         )
 
+    def test_count_spans_multi(self):
+        self.assertEqual(
+            # pylint: disable=protected-access
+            3,
+            self.exporter._count_data([self.span, self.span2, self.span3]),
+        )
+
     def _check_translated_status(
         self,
         translated: ExportTraceServiceRequest,

Reply via email to