From 9fca7e1152aaf04f40d12d251b1e027a25d67d2d Mon Sep 17 00:00:00 2001 From: cpiment <10828255+cpiment@users.noreply.github.com> Date: Thu, 5 Sep 2024 14:17:11 +0200 Subject: [PATCH 1/8] Check if body exists before trying to convert it to JSON --- elasticapm/instrumentation/packages/azure.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/elasticapm/instrumentation/packages/azure.py b/elasticapm/instrumentation/packages/azure.py index 4200bb42b..055db3d63 100644 --- a/elasticapm/instrumentation/packages/azure.py +++ b/elasticapm/instrumentation/packages/azure.py @@ -300,9 +300,12 @@ def handle_azuretable(request, hostname, path, query_params, service, service_ty account_name = hostname.split(".")[0] method = request.method body = request.body - try: - body = json.loads(body) - except json.decoder.JSONDecodeError: # str not bytes + if body: + try: + body = json.loads(body) + except json.decoder.JSONDecodeError: # str not bytes + body = {} + else: body = {} # /tablename(PartitionKey='',RowKey='') resource_name = path.split("/", 1)[1] if "/" in path else path From ed59e59229e7f906e8d024d71766e7a2ce94848a Mon Sep 17 00:00:00 2001 From: cpiment <10828255+cpiment@users.noreply.github.com> Date: Fri, 6 Sep 2024 11:30:54 +0200 Subject: [PATCH 2/8] Update in azure-data-tables uses PATCH instead of PUT --- elasticapm/instrumentation/packages/azure.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/elasticapm/instrumentation/packages/azure.py b/elasticapm/instrumentation/packages/azure.py index 055db3d63..934dbb17b 100644 --- a/elasticapm/instrumentation/packages/azure.py +++ b/elasticapm/instrumentation/packages/azure.py @@ -316,7 +316,7 @@ def handle_azuretable(request, hostname, path, query_params, service, service_ty } operation_name = "Unknown" - if method.lower() == "put": + if method.lower() == "put" or method.lower() == "patch": operation_name = "Update" if "properties" in query_params.get("comp", []): operation_name = "SetProperties" From 7ba7899e8ab7c502fc21af2a22a6bedef6e3e2ff Mon Sep 17 00:00:00 2001 From: cpiment <10828255+cpiment@users.noreply.github.com> Date: Fri, 6 Sep 2024 11:31:21 +0200 Subject: [PATCH 3/8] Tests and requirements file for Azure Storage --- .../azurefunctions/azure_functions_tests.py | 2 +- tests/instrumentation/azure_tests.py | 65 +++++++++++++++++++ tests/requirements/reqs-azure-newest.txt | 5 ++ 3 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 tests/requirements/reqs-azure-newest.txt diff --git a/tests/contrib/serverless/azurefunctions/azure_functions_tests.py b/tests/contrib/serverless/azurefunctions/azure_functions_tests.py index c274b92ef..9e1a11906 100644 --- a/tests/contrib/serverless/azurefunctions/azure_functions_tests.py +++ b/tests/contrib/serverless/azurefunctions/azure_functions_tests.py @@ -29,7 +29,7 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import pytest -azure = pytest.importorskip("azure") +azure = pytest.importorskip("azure-functions") import datetime import os diff --git a/tests/instrumentation/azure_tests.py b/tests/instrumentation/azure_tests.py index aeaab03c0..12ce2333d 100644 --- a/tests/instrumentation/azure_tests.py +++ b/tests/instrumentation/azure_tests.py @@ -39,9 +39,11 @@ azureblob = pytest.importorskip("azure.storage.blob") azurequeue = pytest.importorskip("azure.storage.queue") azuretable = pytest.importorskip("azure.cosmosdb.table") +azuredatatable = pytest.importorskip("azure.data.tables") azurefile = pytest.importorskip("azure.storage.fileshare") pytestmark = [pytest.mark.azurestorage] +from azure.data.tables import TableServiceClient as DataTableServiceClient from azure.cosmosdb.table.tableservice import TableService from azure.storage.blob import BlobServiceClient from azure.storage.fileshare import ShareClient @@ -82,6 +84,18 @@ def queue_client(): queue_client.delete_queue() +@pytest.fixture() +def data_table_service(): + table_name = "apmagentpythonci" + str(uuid.uuid4().hex) + data_table_service_client = DataTableServiceClient.from_connection_string(conn_str=CONNECTION_STRING) + data_table_service = data_table_service_client.get_table_client(table_name) + data_table_service.create_table() + data_table_service.table_name = table_name + + yield data_table_service + + data_table_service.delete_table() + @pytest.fixture() def table_service(): table_name = "apmagentpythonci" + str(uuid.uuid4().hex) @@ -182,6 +196,23 @@ def test_queue(instrument, elasticapm_client, queue_client): assert span["action"] == "delete" +def test_data_table_create(instrument, elasticapm_client): + table_name = "apmagentpythonci" + str(uuid.uuid4().hex) + data_table_service_client = DataTableServiceClient.from_connection_string(conn_str=CONNECTION_STRING) + data_table_service = data_table_service_client.get_table_client(table_name) + + elasticapm_client.begin_transaction("transaction.test") + data_table_service.create_table() + data_table_service.delete_table() + elasticapm_client.end_transaction("MyView") + + span = elasticapm_client.events[constants.SPAN][0] + + assert span["name"] == "AzureTable Create {}".format(table_name) + assert span["type"] == "storage" + assert span["subtype"] == "azuretable" + assert span["action"] == "Create" + def test_table_create(instrument, elasticapm_client): table_name = "apmagentpythonci" + str(uuid.uuid4().hex) table_service = TableService(connection_string=CONNECTION_STRING) @@ -198,6 +229,40 @@ def test_table_create(instrument, elasticapm_client): assert span["subtype"] == "azuretable" assert span["action"] == "Create" +def test_data_table(instrument, elasticapm_client, data_table_service): + table_name = data_table_service.table_name + elasticapm_client.begin_transaction("transaction.test") + task = {"PartitionKey": "tasksSeattle", "RowKey": "001", "description": "Take out the trash", "priority": 200} + data_table_service.create_entity(task) + task = {"PartitionKey": "tasksSeattle", "RowKey": "001", "description": "Take out the garbage", "priority": 250} + data_table_service.update_entity(task) + task = data_table_service.get_entity("tasksSeattle", "001") + data_table_service.delete_entity("tasksSeattle", "001") + elasticapm_client.end_transaction("MyView") + + span = elasticapm_client.events[constants.SPAN][0] + assert span["name"] == "AzureTable Insert {}".format(table_name) + assert span["type"] == "storage" + assert span["subtype"] == "azuretable" + assert span["action"] == "Insert" + + span = elasticapm_client.events[constants.SPAN][1] + assert span["name"] == "AzureTable Update {}(PartitionKey='tasksSeattle',RowKey='001')".format(table_name) + assert span["type"] == "storage" + assert span["subtype"] == "azuretable" + assert span["action"] == "Update" + + span = elasticapm_client.events[constants.SPAN][2] + assert span["name"] == "AzureTable Query {}(PartitionKey='tasksSeattle',RowKey='001')".format(table_name) + assert span["type"] == "storage" + assert span["subtype"] == "azuretable" + assert span["action"] == "Query" + + span = elasticapm_client.events[constants.SPAN][3] + assert span["name"] == "AzureTable Delete {}(PartitionKey='tasksSeattle',RowKey='001')".format(table_name) + assert span["type"] == "storage" + assert span["subtype"] == "azuretable" + assert span["action"] == "Delete" def test_table(instrument, elasticapm_client, table_service): table_name = table_service.table_name diff --git a/tests/requirements/reqs-azure-newest.txt b/tests/requirements/reqs-azure-newest.txt new file mode 100644 index 000000000..d21ec1f76 --- /dev/null +++ b/tests/requirements/reqs-azure-newest.txt @@ -0,0 +1,5 @@ +azure-storage-blob +azure-storage-queue +azure-data-tables +azure-storage-file-share +-r reqs-base.txt \ No newline at end of file From 0f49883c3faa0118666d5c4d9d81bdb24105105a Mon Sep 17 00:00:00 2001 From: cpiment <10828255+cpiment@users.noreply.github.com> Date: Fri, 6 Sep 2024 11:45:36 +0200 Subject: [PATCH 4/8] Fixed typo in Azure Functions tests --- .../contrib/serverless/azurefunctions/azure_functions_tests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/contrib/serverless/azurefunctions/azure_functions_tests.py b/tests/contrib/serverless/azurefunctions/azure_functions_tests.py index 9e1a11906..e2abbdcd3 100644 --- a/tests/contrib/serverless/azurefunctions/azure_functions_tests.py +++ b/tests/contrib/serverless/azurefunctions/azure_functions_tests.py @@ -29,7 +29,7 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import pytest -azure = pytest.importorskip("azure-functions") +azure = pytest.importorskip("azure.functions") import datetime import os From b2d648c4f854191945319f16bfb22f5fc80582cb Mon Sep 17 00:00:00 2001 From: Riccardo Magliocchetti Date: Tue, 24 Dec 2024 15:32:14 +0100 Subject: [PATCH 5/8] Apply suggestions from code review --- tests/instrumentation/azure_tests.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/instrumentation/azure_tests.py b/tests/instrumentation/azure_tests.py index 12ce2333d..2650aa5cc 100644 --- a/tests/instrumentation/azure_tests.py +++ b/tests/instrumentation/azure_tests.py @@ -43,8 +43,8 @@ azurefile = pytest.importorskip("azure.storage.fileshare") pytestmark = [pytest.mark.azurestorage] -from azure.data.tables import TableServiceClient as DataTableServiceClient from azure.cosmosdb.table.tableservice import TableService +from azure.data.tables import TableServiceClient as DataTableServiceClient from azure.storage.blob import BlobServiceClient from azure.storage.fileshare import ShareClient from azure.storage.queue import QueueClient @@ -213,6 +213,7 @@ def test_data_table_create(instrument, elasticapm_client): assert span["subtype"] == "azuretable" assert span["action"] == "Create" + def test_table_create(instrument, elasticapm_client): table_name = "apmagentpythonci" + str(uuid.uuid4().hex) table_service = TableService(connection_string=CONNECTION_STRING) @@ -229,6 +230,7 @@ def test_table_create(instrument, elasticapm_client): assert span["subtype"] == "azuretable" assert span["action"] == "Create" + def test_data_table(instrument, elasticapm_client, data_table_service): table_name = data_table_service.table_name elasticapm_client.begin_transaction("transaction.test") @@ -263,6 +265,7 @@ def test_data_table(instrument, elasticapm_client, data_table_service): assert span["type"] == "storage" assert span["subtype"] == "azuretable" assert span["action"] == "Delete" + def test_table(instrument, elasticapm_client, table_service): table_name = table_service.table_name From 38e252bfae335ea8925133c22d48823b8f595984 Mon Sep 17 00:00:00 2001 From: Riccardo Magliocchetti Date: Tue, 24 Dec 2024 15:35:13 +0100 Subject: [PATCH 6/8] Update tests/instrumentation/azure_tests.py --- tests/instrumentation/azure_tests.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/instrumentation/azure_tests.py b/tests/instrumentation/azure_tests.py index 2650aa5cc..1567c5975 100644 --- a/tests/instrumentation/azure_tests.py +++ b/tests/instrumentation/azure_tests.py @@ -265,7 +265,6 @@ def test_data_table(instrument, elasticapm_client, data_table_service): assert span["type"] == "storage" assert span["subtype"] == "azuretable" assert span["action"] == "Delete" - def test_table(instrument, elasticapm_client, table_service): table_name = table_service.table_name From 0c00c9cd1bcd804ba1cd93f5646eb19c5315b28b Mon Sep 17 00:00:00 2001 From: Riccardo Magliocchetti Date: Tue, 24 Dec 2024 17:28:11 +0100 Subject: [PATCH 7/8] Fixup tests --- .ci/.matrix_framework.yml | 1 + .ci/.matrix_framework_full.yml | 1 + tests/instrumentation/azure_tests.py | 2 ++ 3 files changed, 4 insertions(+) diff --git a/.ci/.matrix_framework.yml b/.ci/.matrix_framework.yml index 1ece9a68a..1cd690c39 100644 --- a/.ci/.matrix_framework.yml +++ b/.ci/.matrix_framework.yml @@ -56,3 +56,4 @@ FRAMEWORK: - kafka-python-newest - grpc-newest - azurefunctions-newest + - azure-newest diff --git a/.ci/.matrix_framework_full.yml b/.ci/.matrix_framework_full.yml index b1fbeaa58..cdabff496 100644 --- a/.ci/.matrix_framework_full.yml +++ b/.ci/.matrix_framework_full.yml @@ -91,3 +91,4 @@ FRAMEWORK: - grpc-newest #- grpc-1.24 # This appears to have problems with python>3.6? - azurefunctions-newest + - azure-newest diff --git a/tests/instrumentation/azure_tests.py b/tests/instrumentation/azure_tests.py index 1567c5975..218f30892 100644 --- a/tests/instrumentation/azure_tests.py +++ b/tests/instrumentation/azure_tests.py @@ -96,6 +96,7 @@ def data_table_service(): data_table_service.delete_table() + @pytest.fixture() def table_service(): table_name = "apmagentpythonci" + str(uuid.uuid4().hex) @@ -266,6 +267,7 @@ def test_data_table(instrument, elasticapm_client, data_table_service): assert span["subtype"] == "azuretable" assert span["action"] == "Delete" + def test_table(instrument, elasticapm_client, table_service): table_name = table_service.table_name elasticapm_client.begin_transaction("transaction.test") From efcbced5e3e621ba04c52d680f11ee3f27998547 Mon Sep 17 00:00:00 2001 From: Riccardo Magliocchetti Date: Wed, 9 Jul 2025 15:22:46 +0200 Subject: [PATCH 8/8] Fix requirements --- tests/instrumentation/azure_tests.py | 1 + tests/requirements/reqs-azure-newest.txt | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/instrumentation/azure_tests.py b/tests/instrumentation/azure_tests.py index 218f30892..5662bedfc 100644 --- a/tests/instrumentation/azure_tests.py +++ b/tests/instrumentation/azure_tests.py @@ -43,6 +43,7 @@ azurefile = pytest.importorskip("azure.storage.fileshare") pytestmark = [pytest.mark.azurestorage] + from azure.cosmosdb.table.tableservice import TableService from azure.data.tables import TableServiceClient as DataTableServiceClient from azure.storage.blob import BlobServiceClient diff --git a/tests/requirements/reqs-azure-newest.txt b/tests/requirements/reqs-azure-newest.txt index d21ec1f76..d2bf7d1f0 100644 --- a/tests/requirements/reqs-azure-newest.txt +++ b/tests/requirements/reqs-azure-newest.txt @@ -2,4 +2,5 @@ azure-storage-blob azure-storage-queue azure-data-tables azure-storage-file-share --r reqs-base.txt \ No newline at end of file +azure-cosmosdb-table +-r reqs-base.txt