Skip to content

Commit badcb13

Browse files
authored
Merge branch 'main' into dev
2 parents 750180c + ea36c5d commit badcb13

File tree

37 files changed

+1102
-65
lines changed

37 files changed

+1102
-65
lines changed

Diff for: CHANGELOG.md

+11-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## Unreleased
99

10-
- Make log sdk add `exception.message` to logRecord for exceptions whose argument
10+
- Implementation of Events API
11+
([#4054](https://github.com/open-telemetry/opentelemetry-python/pull/4054))
12+
- Make log sdk add `exception.message` to logRecord for exceptions whose argument
1113
is an exception not a string message
1214
([#4122](https://github.com/open-telemetry/opentelemetry-python/pull/4122))
1315
- Fix use of `link.attributes.dropped`, which may not exist
@@ -25,8 +27,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2527
([#4103](https://github.com/open-telemetry/opentelemetry-python/pull/4103))
2628
- Update semantic conventions to version 1.27.0
2729
([#4104](https://github.com/open-telemetry/opentelemetry-python/pull/4104))
30+
2831
- Add support to type bytes for OTLP AnyValue
2932
([#4128](https://github.com/open-telemetry/opentelemetry-python/pull/4128))
33+
- Export ExponentialHistogram and ExponentialHistogramDataPoint
34+
([#4134](https://github.com/open-telemetry/opentelemetry-python/pull/4134))
35+
- Implement Client Key and Certificate File Support for All OTLP Exporters
36+
([#4116](https://github.com/open-telemetry/opentelemetry-python/pull/4116))
37+
- Remove `_start_time_unix_nano` attribute from `_ViewInstrumentMatch` in favor
38+
of using `time_ns()` at the moment when the aggregation object is created
39+
([#4137](https://github.com/open-telemetry/opentelemetry-python/pull/4137))
3040

3141
## Version 1.26.0/0.47b0 (2024-07-25)
3242

Diff for: CONTRIBUTING.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ CONTRIB_REPO_SHA=dde62cebffe519c35875af6d06fae053b3be65ec tox
122122
```
123123

124124
The continuation integration overrides that environment variable with as per the configuration
125-
[here](https://github.com/open-telemetry/opentelemetry-python/blob/main/.github/workflows/test.yml#L13).
125+
[here](https://github.com/open-telemetry/opentelemetry-python/blob/main/.github/workflows/test_0.yml#L14).
126126

127127
### Benchmarks
128128

@@ -195,9 +195,9 @@ opened in the Contrib repo with changes to make the packages compatible.
195195

196196
Follow these steps:
197197
1. Open Core repo PR (Contrib Tests will fail)
198-
2. Open Contrib repo PR and modify its `CORE_REPO_SHA` in `.github/workflows/test.yml`
198+
2. Open Contrib repo PR and modify its `CORE_REPO_SHA` in `.github/workflows/test_x.yml`
199199
to equal the commit SHA of the Core repo PR to pass tests
200-
3. Modify the Core repo PR `CONTRIB_REPO_SHA` in `.github/workflows/test.yml` to
200+
3. Modify the Core repo PR `CONTRIB_REPO_SHA` in `.github/workflows/test_x.yml` to
201201
equal the commit SHA of the Contrib repo PR to pass Contrib repo tests (a sanity
202202
check for the Maintainers & Approvers)
203203
4. Merge the Contrib repo

Diff for: README.md

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# OpenTelemetry Python
22
[![Slack](https://img.shields.io/badge/slack-@cncf/otel/python-brightgreen.svg?logo=slack)](https://cloud-native.slack.com/archives/C01PD4HUVBL)
3-
[![Build Status](https://github.com/open-telemetry/opentelemetry-python/actions/workflows/test.yml/badge.svg?branch=main)](https://github.com/open-telemetry/opentelemetry-python/actions)
3+
[![Build Status 0](https://github.com/open-telemetry/opentelemetry-python/actions/workflows/test_0.yml/badge.svg?branch=main)](https://github.com/open-telemetry/opentelemetry-python/actions/workflows/test_0.yml)
4+
[![Build Status 1](https://github.com/open-telemetry/opentelemetry-python/actions/workflows/test_1.yml/badge.svg?branch=main)](https://github.com/open-telemetry/opentelemetry-python/actions/workflows/test_1.yml)
45
[![Minimum Python Version](https://img.shields.io/badge/python-3.8+-blue.svg)](https://www.python.org/downloads/)
56
[![Release](https://img.shields.io/github/v/release/open-telemetry/opentelemetry-python?include_prereleases&style=)](https://github.com/open-telemetry/opentelemetry-python/releases/)
67
[![Read the Docs](https://readthedocs.org/projects/opentelemetry-python/badge/?version=latest)](https://opentelemetry-python.readthedocs.io/en/latest/)
@@ -96,12 +97,10 @@ Meeting notes are available as a public [Google doc](https://docs.google.com/doc
9697

9798
Approvers ([@open-telemetry/python-approvers](https://github.com/orgs/open-telemetry/teams/python-approvers)):
9899

99-
- [Aaron Abbott](https://github.com/aabmass), Google
100100
- [Emídio Neto](https://github.com/emdneto), Zenvia
101101
- [Jeremy Voss](https://github.com/jeremydvoss), Microsoft
102102
- [Owais Lone](https://github.com/owais), Splunk
103103
- [Pablo Collins](https://github.com/pmcollins), Splunk
104-
- [Riccardo Magliocchetti](https://github.com/xrmx), Elastic
105104
- [Shalev Roda](https://github.com/shalevr), Cisco
106105
- [Srikanth Chekuri](https://github.com/srikanthccv), signoz.io
107106
- [Tammy Baylis](https://github.com/tammy-baylis-swi), SolarWinds
@@ -122,8 +121,10 @@ Emeritus Approvers
122121

123122
Maintainers ([@open-telemetry/python-maintainers](https://github.com/orgs/open-telemetry/teams/python-maintainers)):
124123

124+
- [Aaron Abbott](https://github.com/aabmass), Google
125125
- [Diego Hurtado](https://github.com/ocelotl), Lightstep
126126
- [Leighton Chen](https://github.com/lzchen), Microsoft
127+
- [Riccardo Magliocchetti](https://github.com/xrmx), Elastic
127128

128129
Emeritus Maintainers:
129130

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

+6-1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@
3434

3535
from opentelemetry.sdk.environment_variables import (
3636
OTEL_EXPORTER_OTLP_LOGS_CERTIFICATE,
37+
OTEL_EXPORTER_OTLP_LOGS_CLIENT_CERTIFICATE,
38+
OTEL_EXPORTER_OTLP_LOGS_CLIENT_KEY,
3739
OTEL_EXPORTER_OTLP_LOGS_COMPRESSION,
3840
OTEL_EXPORTER_OTLP_LOGS_ENDPOINT,
3941
OTEL_EXPORTER_OTLP_LOGS_HEADERS,
@@ -71,7 +73,10 @@ def __init__(
7173
and environ.get(OTEL_EXPORTER_OTLP_LOGS_CERTIFICATE) is not None
7274
):
7375
credentials = _get_credentials(
74-
credentials, OTEL_EXPORTER_OTLP_LOGS_CERTIFICATE
76+
credentials,
77+
OTEL_EXPORTER_OTLP_LOGS_CERTIFICATE,
78+
OTEL_EXPORTER_OTLP_LOGS_CLIENT_KEY,
79+
OTEL_EXPORTER_OTLP_LOGS_CLIENT_CERTIFICATE,
7580
)
7681

7782
environ_timeout = environ.get(OTEL_EXPORTER_OTLP_LOGS_TIMEOUT)

Diff for: exporter/opentelemetry-exporter-otlp-proto-grpc/src/opentelemetry/exporter/otlp/proto/grpc/exporter.py

+49-11
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@
6161
)
6262
from opentelemetry.proto.resource.v1.resource_pb2 import Resource # noqa: F401
6363
from opentelemetry.sdk.environment_variables import (
64+
OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE,
65+
OTEL_EXPORTER_OTLP_CLIENT_KEY,
6466
OTEL_EXPORTER_OTLP_CERTIFICATE,
6567
OTEL_EXPORTER_OTLP_COMPRESSION,
6668
OTEL_EXPORTER_OTLP_ENDPOINT,
@@ -118,22 +120,55 @@ def get_resource_data(
118120
return _get_resource_data(sdk_resource_scope_data, resource_class, name)
119121

120122

121-
def _load_credential_from_file(filepath) -> ChannelCredentials:
123+
def _read_file(file_path: str) -> Optional[bytes]:
122124
try:
123-
with open(filepath, "rb") as creds_file:
124-
credential = creds_file.read()
125-
return ssl_channel_credentials(credential)
126-
except FileNotFoundError:
127-
logger.exception("Failed to read credential file")
125+
with open(file_path, "rb") as file:
126+
return file.read()
127+
except FileNotFoundError as e:
128+
logger.exception(
129+
f"Failed to read file: {e.filename}. Please check if the file exists and is accessible."
130+
)
128131
return None
129132

130133

131-
def _get_credentials(creds, environ_key):
134+
def _load_credentials(
135+
certificate_file: Optional[str],
136+
client_key_file: Optional[str],
137+
client_certificate_file: Optional[str],
138+
) -> Optional[ChannelCredentials]:
139+
root_certificates = (
140+
_read_file(certificate_file) if certificate_file else None
141+
)
142+
private_key = _read_file(client_key_file) if client_key_file else None
143+
certificate_chain = (
144+
_read_file(client_certificate_file)
145+
if client_certificate_file
146+
else None
147+
)
148+
149+
return ssl_channel_credentials(
150+
root_certificates=root_certificates,
151+
private_key=private_key,
152+
certificate_chain=certificate_chain,
153+
)
154+
155+
156+
def _get_credentials(
157+
creds: Optional[ChannelCredentials],
158+
certificate_file_env_key: str,
159+
client_key_file_env_key: str,
160+
client_certificate_file_env_key: str,
161+
) -> ChannelCredentials:
132162
if creds is not None:
133163
return creds
134-
creds_env = environ.get(environ_key)
135-
if creds_env:
136-
return _load_credential_from_file(creds_env)
164+
165+
certificate_file = environ.get(certificate_file_env_key)
166+
if certificate_file:
167+
client_key_file = environ.get(client_key_file_env_key)
168+
client_certificate_file = environ.get(client_certificate_file_env_key)
169+
return _load_credentials(
170+
certificate_file, client_key_file, client_certificate_file
171+
)
137172
return ssl_channel_credentials()
138173

139174

@@ -214,7 +249,10 @@ def __init__(
214249
)
215250
else:
216251
credentials = _get_credentials(
217-
credentials, OTEL_EXPORTER_OTLP_CERTIFICATE
252+
credentials,
253+
OTEL_EXPORTER_OTLP_CERTIFICATE,
254+
OTEL_EXPORTER_OTLP_CLIENT_KEY,
255+
OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE,
218256
)
219257
self._client = self._stub(
220258
secure_channel(

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

+6-1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@
4242
from opentelemetry.proto.metrics.v1 import metrics_pb2 as pb2 # noqa: F401
4343
from opentelemetry.sdk.environment_variables import (
4444
OTEL_EXPORTER_OTLP_METRICS_CERTIFICATE,
45+
OTEL_EXPORTER_OTLP_METRICS_CLIENT_CERTIFICATE,
46+
OTEL_EXPORTER_OTLP_METRICS_CLIENT_KEY,
4547
OTEL_EXPORTER_OTLP_METRICS_COMPRESSION,
4648
OTEL_EXPORTER_OTLP_METRICS_ENDPOINT,
4749
OTEL_EXPORTER_OTLP_METRICS_HEADERS,
@@ -113,7 +115,10 @@ def __init__(
113115
and environ.get(OTEL_EXPORTER_OTLP_METRICS_CERTIFICATE) is not None
114116
):
115117
credentials = _get_credentials(
116-
credentials, OTEL_EXPORTER_OTLP_METRICS_CERTIFICATE
118+
credentials,
119+
OTEL_EXPORTER_OTLP_METRICS_CERTIFICATE,
120+
OTEL_EXPORTER_OTLP_METRICS_CLIENT_KEY,
121+
OTEL_EXPORTER_OTLP_METRICS_CLIENT_CERTIFICATE,
117122
)
118123

119124
environ_timeout = environ.get(OTEL_EXPORTER_OTLP_METRICS_TIMEOUT)

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

+6-1
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@
4848
)
4949
from opentelemetry.proto.trace.v1.trace_pb2 import Status # noqa: F401
5050
from opentelemetry.sdk.environment_variables import (
51+
OTEL_EXPORTER_OTLP_TRACES_CLIENT_CERTIFICATE,
52+
OTEL_EXPORTER_OTLP_TRACES_CLIENT_KEY,
5153
OTEL_EXPORTER_OTLP_TRACES_CERTIFICATE,
5254
OTEL_EXPORTER_OTLP_TRACES_COMPRESSION,
5355
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT,
@@ -105,7 +107,10 @@ def __init__(
105107
and environ.get(OTEL_EXPORTER_OTLP_TRACES_CERTIFICATE) is not None
106108
):
107109
credentials = _get_credentials(
108-
credentials, OTEL_EXPORTER_OTLP_TRACES_CERTIFICATE
110+
credentials,
111+
OTEL_EXPORTER_OTLP_TRACES_CERTIFICATE,
112+
OTEL_EXPORTER_OTLP_TRACES_CLIENT_KEY,
113+
OTEL_EXPORTER_OTLP_TRACES_CLIENT_CERTIFICATE,
109114
)
110115

111116
environ_timeout = environ.get(OTEL_EXPORTER_OTLP_TRACES_TIMEOUT)

Diff for: exporter/opentelemetry-exporter-otlp-proto-grpc/tests/fixtures/test-client-cert.pem

Whitespace-only changes.

Diff for: exporter/opentelemetry-exporter-otlp-proto-grpc/tests/fixtures/test-client-key.pem

Whitespace-only changes.

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

+64-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15+
# pylint: disable=too-many-lines
16+
1517
import time
1618
from concurrent.futures import ThreadPoolExecutor
1719
from os.path import dirname
@@ -53,6 +55,8 @@
5355
from opentelemetry.sdk._logs.export import LogExportResult
5456
from opentelemetry.sdk.environment_variables import (
5557
OTEL_EXPORTER_OTLP_LOGS_CERTIFICATE,
58+
OTEL_EXPORTER_OTLP_LOGS_CLIENT_CERTIFICATE,
59+
OTEL_EXPORTER_OTLP_LOGS_CLIENT_KEY,
5660
OTEL_EXPORTER_OTLP_LOGS_COMPRESSION,
5761
OTEL_EXPORTER_OTLP_LOGS_ENDPOINT,
5862
OTEL_EXPORTER_OTLP_LOGS_HEADERS,
@@ -206,12 +210,40 @@ def test_exporting(self):
206210
# pylint: disable=protected-access
207211
self.assertEqual(self.exporter._exporting, "logs")
208212

213+
@patch.dict(
214+
"os.environ",
215+
{
216+
OTEL_EXPORTER_OTLP_LOGS_ENDPOINT: "logs:4317",
217+
OTEL_EXPORTER_OTLP_LOGS_HEADERS: " key1=value1,KEY2 = VALUE=2",
218+
OTEL_EXPORTER_OTLP_LOGS_TIMEOUT: "10",
219+
OTEL_EXPORTER_OTLP_LOGS_COMPRESSION: "gzip",
220+
},
221+
)
222+
@patch(
223+
"opentelemetry.exporter.otlp.proto.grpc.exporter.OTLPExporterMixin.__init__"
224+
)
225+
def test_env_variables(self, mock_exporter_mixin):
226+
OTLPLogExporter()
227+
228+
self.assertTrue(len(mock_exporter_mixin.call_args_list) == 1)
229+
_, kwargs = mock_exporter_mixin.call_args_list[0]
230+
self.assertEqual(kwargs["endpoint"], "logs:4317")
231+
self.assertEqual(kwargs["headers"], " key1=value1,KEY2 = VALUE=2")
232+
self.assertEqual(kwargs["timeout"], 10)
233+
self.assertEqual(kwargs["compression"], Compression.Gzip)
234+
self.assertIsNone(kwargs["credentials"])
235+
236+
# Create a new test method specifically for client certificates
209237
@patch.dict(
210238
"os.environ",
211239
{
212240
OTEL_EXPORTER_OTLP_LOGS_ENDPOINT: "logs:4317",
213241
OTEL_EXPORTER_OTLP_LOGS_CERTIFICATE: THIS_DIR
214242
+ "/../fixtures/test.cert",
243+
OTEL_EXPORTER_OTLP_LOGS_CLIENT_CERTIFICATE: THIS_DIR
244+
+ "/../fixtures/test-client-cert.pem",
245+
OTEL_EXPORTER_OTLP_LOGS_CLIENT_KEY: THIS_DIR
246+
+ "/../fixtures/test-client-key.pem",
215247
OTEL_EXPORTER_OTLP_LOGS_HEADERS: " key1=value1,KEY2 = VALUE=2",
216248
OTEL_EXPORTER_OTLP_LOGS_TIMEOUT: "10",
217249
OTEL_EXPORTER_OTLP_LOGS_COMPRESSION: "gzip",
@@ -220,7 +252,7 @@ def test_exporting(self):
220252
@patch(
221253
"opentelemetry.exporter.otlp.proto.grpc.exporter.OTLPExporterMixin.__init__"
222254
)
223-
def test_env_variables(self, mock_exporter_mixin):
255+
def test_env_variables_with_client_certificates(self, mock_exporter_mixin):
224256
OTLPLogExporter()
225257

226258
self.assertTrue(len(mock_exporter_mixin.call_args_list) == 1)
@@ -232,6 +264,37 @@ def test_env_variables(self, mock_exporter_mixin):
232264
self.assertIsNotNone(kwargs["credentials"])
233265
self.assertIsInstance(kwargs["credentials"], ChannelCredentials)
234266

267+
@patch.dict(
268+
"os.environ",
269+
{
270+
OTEL_EXPORTER_OTLP_LOGS_ENDPOINT: "logs:4317",
271+
OTEL_EXPORTER_OTLP_LOGS_CERTIFICATE: THIS_DIR
272+
+ "/../fixtures/test.cert",
273+
OTEL_EXPORTER_OTLP_LOGS_HEADERS: " key1=value1,KEY2 = VALUE=2",
274+
OTEL_EXPORTER_OTLP_LOGS_TIMEOUT: "10",
275+
OTEL_EXPORTER_OTLP_LOGS_COMPRESSION: "gzip",
276+
},
277+
)
278+
@patch(
279+
"opentelemetry.exporter.otlp.proto.grpc.exporter.OTLPExporterMixin.__init__"
280+
)
281+
@patch("logging.Logger.error")
282+
def test_env_variables_with_only_certificate(
283+
self, mock_logger_error, mock_exporter_mixin
284+
):
285+
OTLPLogExporter()
286+
287+
self.assertTrue(len(mock_exporter_mixin.call_args_list) == 1)
288+
_, kwargs = mock_exporter_mixin.call_args_list[0]
289+
self.assertEqual(kwargs["endpoint"], "logs:4317")
290+
self.assertEqual(kwargs["headers"], " key1=value1,KEY2 = VALUE=2")
291+
self.assertEqual(kwargs["timeout"], 10)
292+
self.assertEqual(kwargs["compression"], Compression.Gzip)
293+
self.assertIsNotNone(kwargs["credentials"])
294+
self.assertIsInstance(kwargs["credentials"], ChannelCredentials)
295+
296+
mock_logger_error.assert_not_called()
297+
235298
@patch(
236299
"opentelemetry.exporter.otlp.proto.grpc.exporter.ssl_channel_credentials"
237300
)

0 commit comments

Comments
 (0)