From fd58fdc33e98ebe98c80ca3ff67fb5e93d8b066d Mon Sep 17 00:00:00 2001 From: "gcf-owl-bot[bot]" <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Date: Thu, 5 Sep 2024 09:39:02 -0400 Subject: [PATCH 1/4] chore(python): update unittest workflow template (#939) Source-Link: https://github.com/googleapis/synthtool/commit/e6f91eb4db419b02af74197905b99fa00a6030c0 Post-Processor: gcr.io/cloud-devrel-public-resources/owlbot-python:latest@sha256:365d92ef2206cfad00a8c5955c36789d0de124e2b6d92a72dd0486315a0f2e57 Co-authored-by: Owl Bot --- .github/.OwlBot.lock.yaml | 4 ++-- .kokoro/docker/docs/Dockerfile | 9 ++++----- .kokoro/publish-docs.sh | 20 ++++++++++---------- 3 files changed, 16 insertions(+), 17 deletions(-) diff --git a/.github/.OwlBot.lock.yaml b/.github/.OwlBot.lock.yaml index f30cb3775..f8bd8149f 100644 --- a/.github/.OwlBot.lock.yaml +++ b/.github/.OwlBot.lock.yaml @@ -13,5 +13,5 @@ # limitations under the License. docker: image: gcr.io/cloud-devrel-public-resources/owlbot-python:latest - digest: sha256:52210e0e0559f5ea8c52be148b33504022e1faef4e95fbe4b32d68022af2fa7e -# created: 2024-07-08T19:25:35.862283192Z + digest: sha256:365d92ef2206cfad00a8c5955c36789d0de124e2b6d92a72dd0486315a0f2e57 +# created: 2024-09-04T14:50:52.658171431Z diff --git a/.kokoro/docker/docs/Dockerfile b/.kokoro/docker/docs/Dockerfile index 5205308b3..e5410e296 100644 --- a/.kokoro/docker/docs/Dockerfile +++ b/.kokoro/docker/docs/Dockerfile @@ -72,19 +72,18 @@ RUN tar -xvf Python-3.10.14.tgz RUN ./Python-3.10.14/configure --enable-optimizations RUN make altinstall -RUN python3.10 -m venv /venv -ENV PATH /venv/bin:$PATH +ENV PATH /usr/local/bin/python3.10:$PATH ###################### Install pip RUN wget -O /tmp/get-pip.py 'https://bootstrap.pypa.io/get-pip.py' \ - && python3 /tmp/get-pip.py \ + && python3.10 /tmp/get-pip.py \ && rm /tmp/get-pip.py # Test pip -RUN python3 -m pip +RUN python3.10 -m pip # Install build requirements COPY requirements.txt /requirements.txt -RUN python3 -m pip install --require-hashes -r requirements.txt +RUN python3.10 -m pip install --require-hashes -r requirements.txt CMD ["python3.10"] diff --git a/.kokoro/publish-docs.sh b/.kokoro/publish-docs.sh index 38f083f05..233205d58 100755 --- a/.kokoro/publish-docs.sh +++ b/.kokoro/publish-docs.sh @@ -21,18 +21,18 @@ export PYTHONUNBUFFERED=1 export PATH="${HOME}/.local/bin:${PATH}" # Install nox -python3 -m pip install --require-hashes -r .kokoro/requirements.txt -python3 -m nox --version +python3.10 -m pip install --require-hashes -r .kokoro/requirements.txt +python3.10 -m nox --version # build docs nox -s docs # create metadata -python3 -m docuploader create-metadata \ +python3.10 -m docuploader create-metadata \ --name=$(jq --raw-output '.name // empty' .repo-metadata.json) \ - --version=$(python3 setup.py --version) \ + --version=$(python3.10 setup.py --version) \ --language=$(jq --raw-output '.language // empty' .repo-metadata.json) \ - --distribution-name=$(python3 setup.py --name) \ + --distribution-name=$(python3.10 setup.py --name) \ --product-page=$(jq --raw-output '.product_documentation // empty' .repo-metadata.json) \ --github-repository=$(jq --raw-output '.repo // empty' .repo-metadata.json) \ --issue-tracker=$(jq --raw-output '.issue_tracker // empty' .repo-metadata.json) @@ -40,18 +40,18 @@ python3 -m docuploader create-metadata \ cat docs.metadata # upload docs -python3 -m docuploader upload docs/_build/html --metadata-file docs.metadata --staging-bucket "${STAGING_BUCKET}" +python3.10 -m docuploader upload docs/_build/html --metadata-file docs.metadata --staging-bucket "${STAGING_BUCKET}" # docfx yaml files nox -s docfx # create metadata. -python3 -m docuploader create-metadata \ +python3.10 -m docuploader create-metadata \ --name=$(jq --raw-output '.name // empty' .repo-metadata.json) \ - --version=$(python3 setup.py --version) \ + --version=$(python3.10 setup.py --version) \ --language=$(jq --raw-output '.language // empty' .repo-metadata.json) \ - --distribution-name=$(python3 setup.py --name) \ + --distribution-name=$(python3.10 setup.py --name) \ --product-page=$(jq --raw-output '.product_documentation // empty' .repo-metadata.json) \ --github-repository=$(jq --raw-output '.repo // empty' .repo-metadata.json) \ --issue-tracker=$(jq --raw-output '.issue_tracker // empty' .repo-metadata.json) @@ -59,4 +59,4 @@ python3 -m docuploader create-metadata \ cat docs.metadata # upload docs -python3 -m docuploader upload docs/_build/html/docfx_yaml --metadata-file docs.metadata --destination-prefix docfx --staging-bucket "${V2_STAGING_BUCKET}" +python3.10 -m docuploader upload docs/_build/html/docfx_yaml --metadata-file docs.metadata --destination-prefix docfx --staging-bucket "${V2_STAGING_BUCKET}" From 6c753c211b8125075c8a7caff472799ce9263c95 Mon Sep 17 00:00:00 2001 From: "gcf-owl-bot[bot]" <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Date: Tue, 17 Sep 2024 11:10:48 -0400 Subject: [PATCH 2/4] build(python): release script update (#940) Source-Link: https://github.com/googleapis/synthtool/commit/71a72973dddbc66ea64073b53eda49f0d22e0942 Post-Processor: gcr.io/cloud-devrel-public-resources/owlbot-python:latest@sha256:e8dcfd7cbfd8beac3a3ff8d3f3185287ea0625d859168cc80faccfc9a7a00455 Co-authored-by: Owl Bot --- .github/.OwlBot.lock.yaml | 4 ++-- .kokoro/release.sh | 2 +- .kokoro/release/common.cfg | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/.OwlBot.lock.yaml b/.github/.OwlBot.lock.yaml index f8bd8149f..597e0c326 100644 --- a/.github/.OwlBot.lock.yaml +++ b/.github/.OwlBot.lock.yaml @@ -13,5 +13,5 @@ # limitations under the License. docker: image: gcr.io/cloud-devrel-public-resources/owlbot-python:latest - digest: sha256:365d92ef2206cfad00a8c5955c36789d0de124e2b6d92a72dd0486315a0f2e57 -# created: 2024-09-04T14:50:52.658171431Z + digest: sha256:e8dcfd7cbfd8beac3a3ff8d3f3185287ea0625d859168cc80faccfc9a7a00455 +# created: 2024-09-16T21:04:09.091105552Z diff --git a/.kokoro/release.sh b/.kokoro/release.sh index 8941eaef6..782a65bc5 100755 --- a/.kokoro/release.sh +++ b/.kokoro/release.sh @@ -23,7 +23,7 @@ python3 -m releasetool publish-reporter-script > /tmp/publisher-script; source / export PYTHONUNBUFFERED=1 # Move into the package, build the distribution and upload. -TWINE_PASSWORD=$(cat "${KOKORO_KEYSTORE_DIR}/73713_google-cloud-pypi-token-keystore-1") +TWINE_PASSWORD=$(cat "${KOKORO_KEYSTORE_DIR}/73713_google-cloud-pypi-token-keystore-2") cd github/python-logging python3 setup.py sdist bdist_wheel twine upload --username __token__ --password "${TWINE_PASSWORD}" dist/* diff --git a/.kokoro/release/common.cfg b/.kokoro/release/common.cfg index 4dc3167a5..1669dffb9 100644 --- a/.kokoro/release/common.cfg +++ b/.kokoro/release/common.cfg @@ -28,7 +28,7 @@ before_action { fetch_keystore { keystore_resource { keystore_config_id: 73713 - keyname: "google-cloud-pypi-token-keystore-1" + keyname: "google-cloud-pypi-token-keystore-2" } } } From 1f2b190c0d1a7125d9412c157915d0011cdd4c47 Mon Sep 17 00:00:00 2001 From: Kevin Zheng <147537668+gkevinzheng@users.noreply.github.com> Date: Tue, 15 Oct 2024 12:32:13 -0400 Subject: [PATCH 3/4] fix: 16-bit hexadecimal formatting for XCTC span IDs (#946) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: 16-bit hexadecimal formatting for XCTC span IDs * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md * addressed nit * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md * Fixed test + docstring --------- Co-authored-by: Owl Bot --- google/cloud/logging_v2/handlers/_helpers.py | 24 ++++++++- tests/unit/handlers/test__helpers.py | 51 ++++++++++++++------ tests/unit/handlers/test_handlers.py | 7 +-- tests/unit/handlers/test_structured_log.py | 7 +-- 4 files changed, 67 insertions(+), 22 deletions(-) diff --git a/google/cloud/logging_v2/handlers/_helpers.py b/google/cloud/logging_v2/handlers/_helpers.py index 98bf0cd29..ff5838e05 100644 --- a/google/cloud/logging_v2/handlers/_helpers.py +++ b/google/cloud/logging_v2/handlers/_helpers.py @@ -174,13 +174,22 @@ def _parse_xcloud_trace(header): Args: header (str): the string extracted from the X_CLOUD_TRACE header Returns: - Tuple[Optional[dict], Optional[str], bool]: + Tuple[Optional[str], Optional[str], bool]: The trace_id, span_id and trace_sampled extracted from the header Each field will be None if not found. """ trace_id = span_id = None trace_sampled = False - # see https://cloud.google.com/trace/docs/setup for X-Cloud-Trace_Context format + + # As per the format described at https://cloud.google.com/trace/docs/trace-context#legacy-http-header + # "X-Cloud-Trace-Context: TRACE_ID[/SPAN_ID][;o=OPTIONS]" + # for example: + # "X-Cloud-Trace-Context: 105445aa7843bc8bf206b12000100000/1;o=1" + # + # We expect: + # * trace_id (optional, 128-bit hex string): "105445aa7843bc8bf206b12000100000" + # * span_id (optional, 16-bit hex string): "0000000000000001" (needs to be converted into 16 bit hex string) + # * trace_sampled (optional, bool): true if header: try: regex = r"([\w-]+)?(\/?([\w-]+))?(;?o=(\d))?" @@ -188,6 +197,17 @@ def _parse_xcloud_trace(header): trace_id = match.group(1) span_id = match.group(3) trace_sampled = match.group(5) == "1" + + # Convert the span ID to 16-bit hexadecimal instead of decimal + try: + span_id_int = int(span_id) + if span_id_int > 0 and span_id_int < 2**64: + span_id = f"{span_id_int:016x}" + else: + span_id = None + except (ValueError, TypeError): + span_id = None + except IndexError: pass return trace_id, span_id, trace_sampled diff --git a/tests/unit/handlers/test__helpers.py b/tests/unit/handlers/test__helpers.py index b8c8fc99d..d0577cf22 100644 --- a/tests/unit/handlers/test__helpers.py +++ b/tests/unit/handlers/test__helpers.py @@ -25,9 +25,13 @@ _FLASK_TRACE_ID = "flask0id" _FLASK_SPAN_ID = "span0flask" +_FLASK_SPAN_ID_XCTC_DEC = "12345" +_FLASK_SPAN_ID_XCTC_HEX = "3039".zfill(16) _FLASK_HTTP_REQUEST = {"requestUrl": "https://flask.palletsprojects.com/en/1.1.x/"} _DJANGO_TRACE_ID = "django0id" _DJANGO_SPAN_ID = "span0django" +_DJANGO_SPAN_ID_XCTC_DEC = "54321" +_DJANGO_SPAN_ID_XCTC_HEX = "d431".zfill(16) _DJANGO_HTTP_REQUEST = {"requestUrl": "https://www.djangoproject.com/"} @@ -64,8 +68,9 @@ def test_no_context_header(self): def test_xcloud_header(self): flask_trace_header = "X_CLOUD_TRACE_CONTEXT" expected_trace_id = _FLASK_TRACE_ID - expected_span_id = _FLASK_SPAN_ID - flask_trace_id = f"{expected_trace_id}/{expected_span_id};o=1" + input_span_id = _FLASK_SPAN_ID_XCTC_DEC + expected_span_id = _FLASK_SPAN_ID_XCTC_HEX + flask_trace_id = f"{expected_trace_id}/{input_span_id};o=1" app = self.create_app() context = app.test_request_context( @@ -173,9 +178,10 @@ def test_xcloud_header(self): from google.cloud.logging_v2.handlers.middleware import request django_trace_header = "HTTP_X_CLOUD_TRACE_CONTEXT" - expected_span_id = _DJANGO_SPAN_ID + input_span_id = _DJANGO_SPAN_ID_XCTC_DEC + expected_span_id = _DJANGO_SPAN_ID_XCTC_HEX expected_trace_id = _DJANGO_TRACE_ID - django_trace_id = f"{expected_trace_id}/{expected_span_id};o=1" + django_trace_id = f"{expected_trace_id}/{input_span_id};o=1" django_request = RequestFactory().get( "/", **{django_trace_header: django_trace_id} @@ -501,25 +507,40 @@ def test_no_span(self): self.assertEqual(sampled, False) def test_no_trace(self): - header = "/12345" + input_span = "12345" + expected_span = "3039".zfill(16) + header = f"/{input_span}" trace_id, span_id, sampled = self._call_fut(header) self.assertIsNone(trace_id) - self.assertEqual(span_id, "12345") + self.assertEqual(span_id, expected_span) self.assertEqual(sampled, False) def test_with_span(self): expected_trace = "12345" - expected_span = "67890" - header = f"{expected_trace}/{expected_span}" + input_span = "67890" + expected_span = "10932".zfill(16) + header = f"{expected_trace}/{input_span}" trace_id, span_id, sampled = self._call_fut(header) self.assertEqual(trace_id, expected_trace) self.assertEqual(span_id, expected_span) self.assertEqual(sampled, False) + def test_with_span_decimal_not_in_bounds(self): + input_spans = ["0", "9" * 100] + + for input_span in input_spans: + expected_trace = "12345" + header = f"{expected_trace}/{input_span}" + trace_id, span_id, sampled = self._call_fut(header) + self.assertEqual(trace_id, expected_trace) + self.assertIsNone(span_id) + self.assertEqual(sampled, False) + def test_with_extra_characters(self): expected_trace = "12345" - expected_span = "67890" - header = f"{expected_trace}/{expected_span};abc" + input_span = "67890" + expected_span = "10932".zfill(16) + header = f"{expected_trace}/{input_span};abc" trace_id, span_id, sampled = self._call_fut(header) self.assertEqual(trace_id, expected_trace) self.assertEqual(span_id, expected_span) @@ -527,8 +548,9 @@ def test_with_extra_characters(self): def test_with_explicit_no_sampled(self): expected_trace = "12345" - expected_span = "67890" - header = f"{expected_trace}/{expected_span};o=0" + input_span = "67890" + expected_span = "10932".zfill(16) + header = f"{expected_trace}/{input_span};o=0" trace_id, span_id, sampled = self._call_fut(header) self.assertEqual(trace_id, expected_trace) self.assertEqual(span_id, expected_span) @@ -536,8 +558,9 @@ def test_with_explicit_no_sampled(self): def test_with__sampled(self): expected_trace = "12345" - expected_span = "67890" - header = f"{expected_trace}/{expected_span};o=1" + input_span = "67890" + expected_span = "10932".zfill(16) + header = f"{expected_trace}/{input_span};o=1" trace_id, span_id, sampled = self._call_fut(header) self.assertEqual(trace_id, expected_trace) self.assertEqual(span_id, expected_span) diff --git a/tests/unit/handlers/test_handlers.py b/tests/unit/handlers/test_handlers.py index 535c1f4b1..14b2e5cba 100644 --- a/tests/unit/handlers/test_handlers.py +++ b/tests/unit/handlers/test_handlers.py @@ -140,7 +140,7 @@ def test_minimal_record(self): self.assertIsNone(record._labels) self.assertEqual(record._labels_str, "{}") - def test_record_with_request(self): + def test_record_with_xctc_request(self): """ test filter adds http request data when available """ @@ -161,8 +161,9 @@ def test_record_with_request(self): expected_path = "http://testserver/123" expected_agent = "Mozilla/5.0" expected_trace = "123" - expected_span = "456" - combined_trace = f"{expected_trace}/{expected_span};o=1" + input_span = "456" + expected_span = "1c8".zfill(16) + combined_trace = f"{expected_trace}/{input_span};o=1" expected_request = { "requestMethod": "GET", "requestUrl": expected_path, diff --git a/tests/unit/handlers/test_structured_log.py b/tests/unit/handlers/test_structured_log.py index 920ca15ea..908758749 100644 --- a/tests/unit/handlers/test_structured_log.py +++ b/tests/unit/handlers/test_structured_log.py @@ -382,7 +382,7 @@ def test_format_with_arguments(self): result = handler.format(record) self.assertIn(expected_result, result) - def test_format_with_request(self): + def test_format_with_xctc_request(self): import logging import json @@ -393,8 +393,9 @@ def test_format_with_request(self): expected_path = "http://testserver/123" expected_agent = "Mozilla/5.0" expected_trace = "123" - expected_span = "456" - trace_header = f"{expected_trace}/{expected_span};o=1" + input_span = "456" + expected_span = "1c8".zfill(16) + trace_header = f"{expected_trace}/{input_span};o=1" expected_payload = { "logging.googleapis.com/trace": expected_trace, "logging.googleapis.com/spanId": expected_span, From 55d038faae75c11b93be3770879e7dab7aae770a Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Tue, 15 Oct 2024 16:02:37 -0400 Subject: [PATCH 4/4] chore(main): release 3.11.3 (#948) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- .release-please-manifest.json | 2 +- CHANGELOG.md | 7 +++++++ google/cloud/logging/gapic_version.py | 2 +- google/cloud/logging_v2/gapic_version.py | 2 +- .../snippet_metadata_google.logging.v2.json | 2 +- 5 files changed, 11 insertions(+), 4 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 0c91a27a2..a89b34196 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "3.11.2" + ".": "3.11.3" } diff --git a/CHANGELOG.md b/CHANGELOG.md index 67352df90..202cdafa7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,13 @@ [1]: https://pypi.org/project/google-cloud-logging/#history +## [3.11.3](https://github.com/googleapis/python-logging/compare/v3.11.2...v3.11.3) (2024-10-15) + + +### Bug Fixes + +* 16-bit hexadecimal formatting for XCTC span IDs ([#946](https://github.com/googleapis/python-logging/issues/946)) ([1f2b190](https://github.com/googleapis/python-logging/commit/1f2b190c0d1a7125d9412c157915d0011cdd4c47)) + ## [3.11.2](https://github.com/googleapis/python-logging/compare/v3.11.1...v3.11.2) (2024-08-15) diff --git a/google/cloud/logging/gapic_version.py b/google/cloud/logging/gapic_version.py index d60f7f6c0..69b0cd300 100644 --- a/google/cloud/logging/gapic_version.py +++ b/google/cloud/logging/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "3.11.2" # {x-release-please-version} +__version__ = "3.11.3" # {x-release-please-version} diff --git a/google/cloud/logging_v2/gapic_version.py b/google/cloud/logging_v2/gapic_version.py index d60f7f6c0..69b0cd300 100644 --- a/google/cloud/logging_v2/gapic_version.py +++ b/google/cloud/logging_v2/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "3.11.2" # {x-release-please-version} +__version__ = "3.11.3" # {x-release-please-version} diff --git a/samples/generated_samples/snippet_metadata_google.logging.v2.json b/samples/generated_samples/snippet_metadata_google.logging.v2.json index 0f640c540..ca75689b0 100644 --- a/samples/generated_samples/snippet_metadata_google.logging.v2.json +++ b/samples/generated_samples/snippet_metadata_google.logging.v2.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-logging", - "version": "3.11.2" + "version": "3.11.3" }, "snippets": [ {