From 8fbf27a742a44ba901941101767c0a0bf4e252e8 Mon Sep 17 00:00:00 2001 From: Matt Shirley Date: Thu, 23 Apr 2026 14:53:03 -0500 Subject: [PATCH 1/6] add basic before_request callback --- servicex_app/servicex_app/__init__.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/servicex_app/servicex_app/__init__.py b/servicex_app/servicex_app/__init__.py index 5a49a647c..1665a0581 100644 --- a/servicex_app/servicex_app/__init__.py +++ b/servicex_app/servicex_app/__init__.py @@ -35,7 +35,7 @@ import base64 import click import logstash -from flask import Flask +from flask import Flask, current_app, request from flask.cli import AppGroup from flask_bootstrap import Bootstrap5 from flask_cors import CORS @@ -387,4 +387,10 @@ def inject_modules(): create_kibana_link=create_kibana_link, ) + @app.before_request + def log_client_version(): + client_version = request.headers.get("X-ServiceX-Client-Version") + if client_version: + current_app.logger.debug(f"Client version: {client_version}") + return app From e40c2963be0f47f3b46cc3aad405afcb1d76c891 Mon Sep 17 00:00:00 2001 From: Matt Shirley Date: Wed, 29 Apr 2026 15:16:09 -0500 Subject: [PATCH 2/6] add testing --- servicex_app/servicex_app_test/test_app_init.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/servicex_app/servicex_app_test/test_app_init.py b/servicex_app/servicex_app_test/test_app_init.py index c93b37be3..a1ab910a4 100644 --- a/servicex_app/servicex_app_test/test_app_init.py +++ b/servicex_app/servicex_app_test/test_app_init.py @@ -2,6 +2,7 @@ import pytest import servicex_app +from servicex_app_test.resource_test_base import ResourceTestBase class TestAppInit: @@ -29,3 +30,17 @@ def test_app_init_without_allowed_prefixes(self, monkeypatch): monkeypatch.delenv("ALLOWED_IMAGE_PREFIXES", raising=False) with pytest.raises(ValueError, match="must be configured"): servicex_app.create_app() + + +class TestLogClientVersion(ResourceTestBase): + def test_logs_client_version_when_header_present(self, mocker): + client = self._test_client() + mock_debug = mocker.patch.object(client.application.logger, "debug") + client.get("/", headers={"X-ServiceX-Client-Version": "3.0.1"}) + mock_debug.assert_called_once_with("Client version: 3.0.1") + + def test_no_log_when_header_absent(self, mocker): + client = self._test_client() + mock_debug = mocker.patch.object(client.application.logger, "debug") + client.get("/") + mock_debug.assert_not_called() From 4c8cbba07c9d2f580966f8d21b64dcdc1bb8349f Mon Sep 17 00:00:00 2001 From: Matt Shirley Date: Thu, 7 May 2026 17:57:38 -0500 Subject: [PATCH 3/6] move client version logging to transformation submission --- servicex_app/servicex_app/__init__.py | 8 +---- .../resources/transformation/submit.py | 12 +++++++ .../resources/transformation/test_submit.py | 32 +++++++++++++++++++ .../servicex_app_test/test_app_init.py | 15 --------- 4 files changed, 45 insertions(+), 22 deletions(-) diff --git a/servicex_app/servicex_app/__init__.py b/servicex_app/servicex_app/__init__.py index 1665a0581..5a49a647c 100644 --- a/servicex_app/servicex_app/__init__.py +++ b/servicex_app/servicex_app/__init__.py @@ -35,7 +35,7 @@ import base64 import click import logstash -from flask import Flask, current_app, request +from flask import Flask from flask.cli import AppGroup from flask_bootstrap import Bootstrap5 from flask_cors import CORS @@ -387,10 +387,4 @@ def inject_modules(): create_kibana_link=create_kibana_link, ) - @app.before_request - def log_client_version(): - client_version = request.headers.get("X-ServiceX-Client-Version") - if client_version: - current_app.logger.debug(f"Client version: {client_version}") - return app diff --git a/servicex_app/servicex_app/resources/transformation/submit.py b/servicex_app/servicex_app/resources/transformation/submit.py index 2aaccb172..6153b83f6 100644 --- a/servicex_app/servicex_app/resources/transformation/submit.py +++ b/servicex_app/servicex_app/resources/transformation/submit.py @@ -97,6 +97,13 @@ def make_api( location="json", help="Static list of Root Files. Provide this or Dataset Identifier.", ) + cls.parser.add_argument( + "client-version", + type=str, + default="unknown", + location="json", + help="The client-version submitting the transformation." + ) cls.parser.add_argument("selection", help="Query string") cls.parser.add_argument("codegen") cls.parser.add_argument("tree-name") @@ -186,6 +193,7 @@ def post(self): did = args.get("did") file_list = args.get("file-list") user_codegen_name = args.get("codegen") + client_version = args.get("client-version") code_gen_image_name = config["CODE_GEN_IMAGES"].get(user_codegen_name, None) namespace = config["TRANSFORMER_NAMESPACE"] @@ -316,6 +324,10 @@ def post(self): current_app.logger.info( "Transformation request submitted!", extra={"request_id": request_id} ) + current_app.logger.info( + f"Transformation submitted with client version: {client_version}", + extra={"request_id": request_id} + ) return {"request_id": str(request_id)} except Exception as eek: current_app.logger.exception( diff --git a/servicex_app/servicex_app_test/resources/transformation/test_submit.py b/servicex_app/servicex_app_test/resources/transformation/test_submit.py index 28b0f999b..08ee40643 100644 --- a/servicex_app/servicex_app_test/resources/transformation/test_submit.py +++ b/servicex_app/servicex_app_test/resources/transformation/test_submit.py @@ -635,6 +635,38 @@ def _side_effect(selection_string, request_id, namespace, user_codegen_name): assert saved_obj assert saved_obj.image == image + def test_submit_transformation_logs_client_version( + self, mocker, mock_dataset_manager_from_did, mock_codegen + ): + client = self._test_client(code_gen_service=mock_codegen) + mock_info = mocker.patch.object(client.application.logger, "info") + with client.application.app_context(): + request = self._generate_transformation_request(**{"client-version": "3.0.1"}) + response = client.post( + "/servicex/transformation", json=request, headers=self.fake_header() + ) + assert response.status_code == 200 + request_id = response.json["request_id"] + mock_info.assert_any_call( + "Client version: 3.0.1", extra={"request_id": request_id} + ) + + def test_submit_transformation_logs_unknown_client_version( + self, mocker, mock_dataset_manager_from_did, mock_codegen + ): + client = self._test_client(code_gen_service=mock_codegen) + mock_info = mocker.patch.object(client.application.logger, "info") + with client.application.app_context(): + request = self._generate_transformation_request() + response = client.post( + "/servicex/transformation", json=request, headers=self.fake_header() + ) + assert response.status_code == 200 + request_id = response.json["request_id"] + mock_info.assert_any_call( + "Client version: unknown", extra={"request_id": request_id} + ) + class TestValidateCustomDockerImage: """Tests for the validate_custom_docker_image function""" diff --git a/servicex_app/servicex_app_test/test_app_init.py b/servicex_app/servicex_app_test/test_app_init.py index a1ab910a4..c93b37be3 100644 --- a/servicex_app/servicex_app_test/test_app_init.py +++ b/servicex_app/servicex_app_test/test_app_init.py @@ -2,7 +2,6 @@ import pytest import servicex_app -from servicex_app_test.resource_test_base import ResourceTestBase class TestAppInit: @@ -30,17 +29,3 @@ def test_app_init_without_allowed_prefixes(self, monkeypatch): monkeypatch.delenv("ALLOWED_IMAGE_PREFIXES", raising=False) with pytest.raises(ValueError, match="must be configured"): servicex_app.create_app() - - -class TestLogClientVersion(ResourceTestBase): - def test_logs_client_version_when_header_present(self, mocker): - client = self._test_client() - mock_debug = mocker.patch.object(client.application.logger, "debug") - client.get("/", headers={"X-ServiceX-Client-Version": "3.0.1"}) - mock_debug.assert_called_once_with("Client version: 3.0.1") - - def test_no_log_when_header_absent(self, mocker): - client = self._test_client() - mock_debug = mocker.patch.object(client.application.logger, "debug") - client.get("/") - mock_debug.assert_not_called() From 5aa470f8a90de3e3dde044b40a23bc4cb3439b57 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 7 May 2026 22:58:27 +0000 Subject: [PATCH 4/6] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- servicex_app/servicex_app/resources/transformation/submit.py | 4 ++-- .../servicex_app_test/resources/transformation/test_submit.py | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/servicex_app/servicex_app/resources/transformation/submit.py b/servicex_app/servicex_app/resources/transformation/submit.py index 6153b83f6..5399dd4e8 100644 --- a/servicex_app/servicex_app/resources/transformation/submit.py +++ b/servicex_app/servicex_app/resources/transformation/submit.py @@ -102,7 +102,7 @@ def make_api( type=str, default="unknown", location="json", - help="The client-version submitting the transformation." + help="The client-version submitting the transformation.", ) cls.parser.add_argument("selection", help="Query string") cls.parser.add_argument("codegen") @@ -326,7 +326,7 @@ def post(self): ) current_app.logger.info( f"Transformation submitted with client version: {client_version}", - extra={"request_id": request_id} + extra={"request_id": request_id}, ) return {"request_id": str(request_id)} except Exception as eek: diff --git a/servicex_app/servicex_app_test/resources/transformation/test_submit.py b/servicex_app/servicex_app_test/resources/transformation/test_submit.py index 08ee40643..40b20e0d8 100644 --- a/servicex_app/servicex_app_test/resources/transformation/test_submit.py +++ b/servicex_app/servicex_app_test/resources/transformation/test_submit.py @@ -641,7 +641,9 @@ def test_submit_transformation_logs_client_version( client = self._test_client(code_gen_service=mock_codegen) mock_info = mocker.patch.object(client.application.logger, "info") with client.application.app_context(): - request = self._generate_transformation_request(**{"client-version": "3.0.1"}) + request = self._generate_transformation_request( + **{"client-version": "3.0.1"} + ) response = client.post( "/servicex/transformation", json=request, headers=self.fake_header() ) From 5608b259b974c668a253f6c3d71944c3fba8025a Mon Sep 17 00:00:00 2001 From: Matt Shirley Date: Thu, 7 May 2026 18:04:25 -0500 Subject: [PATCH 5/6] update test text --- .../servicex_app_test/resources/transformation/test_submit.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/servicex_app/servicex_app_test/resources/transformation/test_submit.py b/servicex_app/servicex_app_test/resources/transformation/test_submit.py index 08ee40643..412a6acdd 100644 --- a/servicex_app/servicex_app_test/resources/transformation/test_submit.py +++ b/servicex_app/servicex_app_test/resources/transformation/test_submit.py @@ -648,7 +648,7 @@ def test_submit_transformation_logs_client_version( assert response.status_code == 200 request_id = response.json["request_id"] mock_info.assert_any_call( - "Client version: 3.0.1", extra={"request_id": request_id} + "Transformation submitted with client version: 3.0.1", extra={"request_id": request_id} ) def test_submit_transformation_logs_unknown_client_version( @@ -664,7 +664,7 @@ def test_submit_transformation_logs_unknown_client_version( assert response.status_code == 200 request_id = response.json["request_id"] mock_info.assert_any_call( - "Client version: unknown", extra={"request_id": request_id} + "Transformation submitted with client version: unknown", extra={"request_id": request_id} ) From 1f5c675b26d4b359fa2aeb9a8c644cd8e8e466c0 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 7 May 2026 23:04:51 +0000 Subject: [PATCH 6/6] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- .../resources/transformation/test_submit.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/servicex_app/servicex_app_test/resources/transformation/test_submit.py b/servicex_app/servicex_app_test/resources/transformation/test_submit.py index 95d3b8d93..f20ad43d3 100644 --- a/servicex_app/servicex_app_test/resources/transformation/test_submit.py +++ b/servicex_app/servicex_app_test/resources/transformation/test_submit.py @@ -650,7 +650,8 @@ def test_submit_transformation_logs_client_version( assert response.status_code == 200 request_id = response.json["request_id"] mock_info.assert_any_call( - "Transformation submitted with client version: 3.0.1", extra={"request_id": request_id} + "Transformation submitted with client version: 3.0.1", + extra={"request_id": request_id}, ) def test_submit_transformation_logs_unknown_client_version( @@ -666,7 +667,8 @@ def test_submit_transformation_logs_unknown_client_version( assert response.status_code == 200 request_id = response.json["request_id"] mock_info.assert_any_call( - "Transformation submitted with client version: unknown", extra={"request_id": request_id} + "Transformation submitted with client version: unknown", + extra={"request_id": request_id}, )