diff --git a/sdk/core/azure-core-tracing-opentelemetry/dev_requirements.txt b/sdk/core/azure-core-tracing-opentelemetry/dev_requirements.txt index 601603578f00..29d610b6098d 100644 --- a/sdk/core/azure-core-tracing-opentelemetry/dev_requirements.txt +++ b/sdk/core/azure-core-tracing-opentelemetry/dev_requirements.txt @@ -4,3 +4,4 @@ opentelemetry-sdk<2.0.0,>=1.12.0 opentelemetry-instrumentation-requests>=0.32b0 requests +azure-storage-blob diff --git a/sdk/core/azure-core-tracing-opentelemetry/test-resources.bicep b/sdk/core/azure-core-tracing-opentelemetry/test-resources.bicep new file mode 100644 index 000000000000..2a8f89b9c6dd --- /dev/null +++ b/sdk/core/azure-core-tracing-opentelemetry/test-resources.bicep @@ -0,0 +1,28 @@ +@description('The base resource name.') +param baseName string = resourceGroup().name + +@description('Which Azure Region to deploy the resource to. Defaults to the resource group location.') +param location string = resourceGroup().location + +@description('The client OID to grant access to test resources.') +param testApplicationOid string + +resource storageAccount 'Microsoft.Storage/storageAccounts@2022-09-01' = { + name: '${baseName}storage' + location: location + kind: 'StorageV2' + sku: { + name: 'Standard_LRS' + } + properties: { + accessTier: 'Hot' + } +} + +var name = storageAccount.name +var key = storageAccount.listKeys().keys[0].value +var connectionString = 'DefaultEndpointsProtocol=https;AccountName=${name};AccountKey=${key}' + +output AZURE_STORAGE_ACCOUNT_NAME string = name +output AZURE_STORAGE_ACCOUNT_KEY string = key +output AZURE_STORAGE_CONNECTION_STRING string = connectionString diff --git a/sdk/core/azure-core-tracing-opentelemetry/tests.yml b/sdk/core/azure-core-tracing-opentelemetry/tests.yml new file mode 100644 index 000000000000..83bdffe60ccd --- /dev/null +++ b/sdk/core/azure-core-tracing-opentelemetry/tests.yml @@ -0,0 +1,12 @@ +trigger: none + +stages: + - template: /eng/pipelines/templates/stages/archetype-sdk-tests.yml + parameters: + ServiceDirectory: core + BuildTargetingString: 'azure-core-tracing-opentelemetry' + EnvVars: + AZURE_SKIP_LIVE_RECORDING: 'true' + AZURE_TEST_RUN_LIVE: 'true' + TestResourceDirectories: + - core/azure-core-tracing-opentelemetry/ diff --git a/sdk/core/azure-core-tracing-opentelemetry/tests/conftest.py b/sdk/core/azure-core-tracing-opentelemetry/tests/conftest.py index 76fd93701855..d8c7ae758e6e 100644 --- a/sdk/core/azure-core-tracing-opentelemetry/tests/conftest.py +++ b/sdk/core/azure-core-tracing-opentelemetry/tests/conftest.py @@ -2,6 +2,8 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. # ------------------------------------ +import os + from opentelemetry import trace from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export.in_memory_span_exporter import InMemorySpanExporter @@ -27,3 +29,12 @@ def tracer(): def exporter(): span_exporter.clear() return span_exporter + + +@pytest.fixture(scope="session") +def config(): + return { + "storage_account_name": os.environ["AZURE_STORAGE_ACCOUNT_NAME"], + "storage_account_key": os.environ["AZURE_STORAGE_ACCOUNT_KEY"], + "storage_connection_string": os.environ["AZURE_STORAGE_CONNECTION_STRING"], + } diff --git a/sdk/core/azure-core-tracing-opentelemetry/tests/test_storage_live.py b/sdk/core/azure-core-tracing-opentelemetry/tests/test_storage_live.py new file mode 100644 index 000000000000..ea5deb7293fa --- /dev/null +++ b/sdk/core/azure-core-tracing-opentelemetry/tests/test_storage_live.py @@ -0,0 +1,34 @@ +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ +import pytest + +from azure.storage.blob import BlobServiceClient +from opentelemetry.trace import SpanKind +from opentelemetry.sdk.trace import ReadableSpan + + +class TestStorageTracing: + @pytest.mark.live_test_only + def test_blob_service_client_tracing(self, config, exporter, tracer): + connection_string = config["storage_connection_string"] + client = BlobServiceClient.from_connection_string(connection_string) + + with tracer.start_as_current_span(name="root") as parent: + client.get_service_properties() + + spans = exporter.get_finished_spans() + + # We expect 3 spans, one for the root span, one for the method call, and one for the HTTP request. + assert len(spans) == 3 + span_names_list = [span.name for span in spans] + assert span_names_list == ["/", "BlobServiceClient.get_service_properties", "root"] + + http_span: ReadableSpan = spans[0] + assert http_span.kind == SpanKind.CLIENT + assert http_span.parent.span_id == spans[1].context.span_id + + method_span: ReadableSpan = spans[1] + assert method_span.kind == SpanKind.INTERNAL + assert method_span.parent.span_id == spans[2].context.span_id