diff --git a/sdk/monitor/azure-monitor-query/CHANGELOG.md b/sdk/monitor/azure-monitor-query/CHANGELOG.md index 139d49c5e8b2..554e3e691a59 100644 --- a/sdk/monitor/azure-monitor-query/CHANGELOG.md +++ b/sdk/monitor/azure-monitor-query/CHANGELOG.md @@ -4,13 +4,14 @@ ### Features Added -- Added `roll_up_by` keyword argument to `MetricsBatchQueryClient.query_batch` to support rolling up metrics by dimension. ([#33752](https://github.com/Azure/azure-sdk-for-python/pull/33752)) +- Added `roll_up_by` keyword argument to `MetricsClient.query_resources` to support rolling up metrics by dimension. ([#33752](https://github.com/Azure/azure-sdk-for-python/pull/33752)) ### Breaking Changes - The following changes are breaking against the previous preview release (i.e. `1.3.0b2`/`1.3.0b1`): - - Reordered the arguments for the async `MetricsBatchQueryClient` constructor so that `endpoint` is now the first positional argument. ([#33752](https://github.com/Azure/azure-sdk-for-python/pull/33752)) - - Reordered the `metric_names` and `metric_namespace` positional arguments in `MetricsBatchQueryClient.query_batch`. ([#33752](https://github.com/Azure/azure-sdk-for-python/pull/33752)) + - `MetricsBatchQueryClient` has been renamed to `MetricsClient`. ([#33958](https://github.com/Azure/azure-sdk-for-python/pull/33958)) + - Reordered the arguments for the async `MetricsClient` constructor so that `endpoint` is now the first positional argument. ([#33752](https://github.com/Azure/azure-sdk-for-python/pull/33752)) + - Positional arguments in `MetricsClient.query_resources` are now required keyword-only arguments. ([#33958](https://github.com/Azure/azure-sdk-for-python/pull/33958)) ### Bugs Fixed diff --git a/sdk/monitor/azure-monitor-query/README.md b/sdk/monitor/azure-monitor-query/README.md index 21e7b90469fb..275da0c8b242 100644 --- a/sdk/monitor/azure-monitor-query/README.md +++ b/sdk/monitor/azure-monitor-query/README.md @@ -19,7 +19,7 @@ The Azure Monitor Query client library is used to execute read-only queries agai ### Prerequisites -- Python 3.7 or later +- Python 3.8 or later - An [Azure subscription][azure_subscription] - A [TokenCredential](https://learn.microsoft.com/python/api/azure-core/azure.core.credentials.tokencredential?view=azure-python) implementation, such as an [Azure Identity library credential type](https://learn.microsoft.com/python/api/overview/azure/identity-readme?view=azure-python#credential-classes). - To query Logs, you need one of the following things: @@ -37,7 +37,7 @@ pip install azure-monitor-query ### Create the client -An authenticated client is required to query Logs or Metrics. The library includes both synchronous and asynchronous forms of the clients. To authenticate, create an instance of a token credential. Use that instance when creating a `LogsQueryClient`, `MetricsQueryClient`, or `MetricsBatchQueryClient`. The following examples use `DefaultAzureCredential` from the [azure-identity](https://pypi.org/project/azure-identity/) package. +An authenticated client is required to query Logs or Metrics. The library includes both synchronous and asynchronous forms of the clients. To authenticate, create an instance of a token credential. Use that instance when creating a `LogsQueryClient`, `MetricsQueryClient`, or `MetricsClient`. The following examples use `DefaultAzureCredential` from the [azure-identity](https://pypi.org/project/azure-identity/) package. #### Synchronous clients @@ -45,11 +45,12 @@ Consider the following example, which creates synchronous clients for both Logs ```python from azure.identity import DefaultAzureCredential -from azure.monitor.query import LogsQueryClient, MetricsQueryClient +from azure.monitor.query import LogsQueryClient, MetricsQueryClient, MetricsClient credential = DefaultAzureCredential() -logs_client = LogsQueryClient(credential) -metrics_client = MetricsQueryClient(credential) +logs_query_client = LogsQueryClient(credential) +metrics_query_client = MetricsQueryClient(credential) +metrics_client = MetricsClient("https://", credential) ``` #### Asynchronous clients @@ -58,11 +59,13 @@ The asynchronous forms of the query client APIs are found in the `.aio`-suffixed ```python from azure.identity.aio import DefaultAzureCredential -from azure.monitor.query.aio import LogsQueryClient, MetricsQueryClient +from azure.monitor.query.aio import LogsQueryClient, MetricsQueryClient, MetricsClient credential = DefaultAzureCredential() -async_logs_client = LogsQueryClient(credential) -async_metrics_client = MetricsQueryClient(credential) +async_logs_query_client = LogsQueryClient(credential) +async_metrics_query_client = MetricsQueryClient(credential) +async_metrics_client = MetricsClient("https://", credential) +``` ``` #### Configure clients for non-public Azure clouds @@ -70,8 +73,8 @@ async_metrics_client = MetricsQueryClient(credential) By default, `LogsQueryClient` and `MetricsQueryClient` are configured to connect to the public Azure cloud. These can be configured to connect to non-public Azure clouds by passing in the correct `endpoint` argument: For example: ```python -logs_client = LogsQueryClient(credential, endpoint="https://api.loganalytics.azure.cn/v1") -metrics_client = MetricsQueryClient(credential, endpoint="https://management.chinacloudapi.cn") +logs_query_client = LogsQueryClient(credential, endpoint="https://api.loganalytics.azure.cn/v1") +metrics_query_client = MetricsQueryClient(credential, endpoint="https://management.chinacloudapi.cn") ``` **Note**: Currently, `MetricsQueryClient` uses the Azure Resource Manager (ARM) endpoint for querying metrics, so you will need the corresponding management endpoint for your cloud when using this client. This is subject to change in the future. @@ -114,6 +117,7 @@ Each set of metric values is a time series with the following characteristics: - [Metrics query](#metrics-query) - [Handle metrics query response](#handle-metrics-query-response) - [Example of handling response](#example-of-handling-response) +- [Metrics batch query](#metrics-batch-query) ### Logs query @@ -527,7 +531,7 @@ for metric in response.metrics: ### Metrics batch query -A user can also query metrics from multiple resources at once using the `query_batch` method of `MetricsBatchQueryClient`. This uses a different API than the `MetricsQueryClient` and requires that a user pass in a regional endpoint when instantiating the client (for example, "https://westus3.metrics.monitor.azure.com"). +A user can also query metrics from multiple resources at once using the `query_resources` method of `MetricsClient`. This uses a different API than the `MetricsQueryClient` and requires that a user pass in a regional endpoint when instantiating the client (for example, "https://westus3.metrics.monitor.azure.com"). Note, each resource must be in the same region as the endpoint passed in when instantiating the client, and each resource must be in the same Azure subscription. Furthermore, the metric namespace that contains the metrics to be queried must also be passed. A list of metric namespaces can be found [here][metric_namespaces]. @@ -538,19 +542,19 @@ import os from azure.core.exceptions import HttpResponseError from azure.identity import DefaultAzureCredential -from azure.monitor.query import MetricsBatchQueryClient, MetricAggregationType +from azure.monitor.query import MetricsClient, MetricAggregationType credential = DefaultAzureCredential() -client = MetricsBatchQueryClient(endpoint, credential) +client = MetricsClient(endpoint, credential) resource_uris = [ "/subscriptions//resourceGroups//providers//storageAccounts/", "/subscriptions//resourceGroups//providers//storageAccounts/" ] -response = client.query_batch( - resource_uris, +response = client.query_resources( + resource_uris=resource_uris, metric_namespace="Microsoft.Storage/storageAccounts", metric_names=["Ingress"], timespan=timedelta(hours=2), @@ -586,6 +590,7 @@ The following code samples show common scenarios with the Azure Monitor Query cl #### Metrics query samples - [Send a query using MetricsQueryClient](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/monitor/azure-monitor-query/samples/sample_metrics_query.py) ([async sample](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/monitor/azure-monitor-query/samples/async_samples/sample_metrics_query_async.py)) +- [Send a query to multiple resources in a region and subscription using MetricsClient](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/monitor/azure-monitor-query/samples/sample_metrics_query_multiple.py) ([async sample](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/monitor/azure-monitor-query/samples/async_samples/sample_metrics_query_multiple_async.py)) - [Get a list of metric namespaces](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/monitor/azure-monitor-query/samples/sample_metric_namespaces.py) ([async sample](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/monitor/azure-monitor-query/samples/async_samples/sample_metric_namespaces_async.py)) - [Get a list of metric definitions](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/monitor/azure-monitor-query/samples/sample_metric_definitions.py) ([async sample](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/monitor/azure-monitor-query/samples/async_samples/sample_metric_definitions_async.py)) diff --git a/sdk/monitor/azure-monitor-query/assets.json b/sdk/monitor/azure-monitor-query/assets.json index 37bb6a51e5e5..91bc7a37f44c 100644 --- a/sdk/monitor/azure-monitor-query/assets.json +++ b/sdk/monitor/azure-monitor-query/assets.json @@ -2,5 +2,5 @@ "AssetsRepo": "Azure/azure-sdk-assets", "AssetsRepoPrefixPath": "python", "TagPrefix": "python/monitor/azure-monitor-query", - "Tag": "python/monitor/azure-monitor-query_7462cb1df1" + "Tag": "python/monitor/azure-monitor-query_152690fb22" } diff --git a/sdk/monitor/azure-monitor-query/azure/monitor/query/__init__.py b/sdk/monitor/azure-monitor-query/azure/monitor/query/__init__.py index 4098b12132c8..d2601599ac80 100644 --- a/sdk/monitor/azure-monitor-query/azure/monitor/query/__init__.py +++ b/sdk/monitor/azure-monitor-query/azure/monitor/query/__init__.py @@ -6,7 +6,7 @@ from ._logs_query_client import LogsQueryClient from ._metrics_query_client import MetricsQueryClient -from ._metrics_batch_query_client import MetricsBatchQueryClient +from ._metrics_client import MetricsClient from ._enums import ( LogsQueryStatus, @@ -46,7 +46,7 @@ "LogsTableRow", "LogsBatchQuery", "MetricsQueryClient", - "MetricsBatchQueryClient", + "MetricsClient", "MetricNamespace", "MetricNamespaceClassification", "MetricDefinition", diff --git a/sdk/monitor/azure-monitor-query/azure/monitor/query/_metrics_batch_query_client.py b/sdk/monitor/azure-monitor-query/azure/monitor/query/_metrics_client.py similarity index 91% rename from sdk/monitor/azure-monitor-query/azure/monitor/query/_metrics_batch_query_client.py rename to sdk/monitor/azure-monitor-query/azure/monitor/query/_metrics_client.py index 25c7e8be30da..7b0b36d6cb65 100644 --- a/sdk/monitor/azure-monitor-query/azure/monitor/query/_metrics_batch_query_client.py +++ b/sdk/monitor/azure-monitor-query/azure/monitor/query/_metrics_client.py @@ -18,8 +18,8 @@ JSON = MutableMapping[str, Any] # pylint: disable=unsubscriptable-object -class MetricsBatchQueryClient: # pylint: disable=client-accepts-api-version-keyword - """MetricsBatchQueryClient should be used for performing metrics queries on multiple monitored resources in the +class MetricsClient: # pylint: disable=client-accepts-api-version-keyword + """MetricsClient should be used for performing metrics queries on multiple monitored resources in the same region. A credential with authorization at the subscription level is required when using this client. :param str endpoint: The regional endpoint to use, for example @@ -47,12 +47,12 @@ def __init__(self, endpoint: str, credential: TokenCredential, **kwargs: Any) -> self._batch_metrics_op = self._client.metrics_batch @distributed_trace - def query_batch( + def query_resources( self, + *, resource_uris: Sequence[str], - metric_names: Sequence[str], metric_namespace: str, - *, + metric_names: Sequence[str], timespan: Optional[Union[timedelta, Tuple[datetime, timedelta], Tuple[datetime, datetime]]] = None, granularity: Optional[timedelta] = None, aggregations: Optional[Sequence[str]] = None, @@ -64,12 +64,12 @@ def query_batch( ) -> List[MetricsQueryResult]: """Lists the metric values for multiple resources. - :param resource_uris: A list of resource URIs to query metrics for. Required. - :type resource_uris: list[str] - :param metric_names: The names of the metrics (comma separated) to retrieve. Required. - :type metric_names: list[str] - :param metric_namespace: Metric namespace that contains the requested metric names. Required. - :type metric_namespace: str + :keyword resource_uris: A list of resource URIs to query metrics for. Required. + :paramtype resource_uris: list[str] + :keyword metric_namespace: Metric namespace that contains the requested metric names. Required. + :paramtype metric_namespace: str + :keyword metric_names: The names of the metrics (comma separated) to retrieve. Required. + :paramtype metric_names: list[str] :keyword timespan: The timespan for which to query the data. This can be a timedelta, a timedelta and a start datetime, or a start datetime/end datetime. :paramtype timespan: Optional[Union[~datetime.timedelta, tuple[~datetime.datetime, ~datetime.timedelta], @@ -109,7 +109,7 @@ def query_batch( .. admonition:: Example: - .. literalinclude:: ../samples/sample_metrics_batch_query.py + .. literalinclude:: ../samples/sample_metrics_query_multiple.py :start-after: [START send_metrics_batch_query] :end-before: [END send_metrics_batch_query] :language: python @@ -156,7 +156,7 @@ def close(self) -> None: """Close the client session.""" return self._client.close() - def __enter__(self) -> "MetricsBatchQueryClient": + def __enter__(self) -> "MetricsClient": self._client.__enter__() # pylint:disable=no-member return self diff --git a/sdk/monitor/azure-monitor-query/azure/monitor/query/_metrics_query_client.py b/sdk/monitor/azure-monitor-query/azure/monitor/query/_metrics_query_client.py index 8a9fce2bb2a9..7bae95c6863d 100644 --- a/sdk/monitor/azure-monitor-query/azure/monitor/query/_metrics_query_client.py +++ b/sdk/monitor/azure-monitor-query/azure/monitor/query/_metrics_query_client.py @@ -137,7 +137,6 @@ def query_resource( orderby=order_by, filter=filter, metricnamespace=metric_namespace, - connection_verify=False, **kwargs ) return MetricsQueryResult._from_generated(generated) # pylint: disable=protected-access diff --git a/sdk/monitor/azure-monitor-query/azure/monitor/query/aio/__init__.py b/sdk/monitor/azure-monitor-query/azure/monitor/query/aio/__init__.py index 1a25d5b51c8a..0f035c83ddd7 100644 --- a/sdk/monitor/azure-monitor-query/azure/monitor/query/aio/__init__.py +++ b/sdk/monitor/azure-monitor-query/azure/monitor/query/aio/__init__.py @@ -6,6 +6,6 @@ from ._logs_query_client_async import LogsQueryClient from ._metrics_query_client_async import MetricsQueryClient -from ._metrics_batch_query_client_async import MetricsBatchQueryClient +from ._metrics_client_async import MetricsClient -__all__ = ["LogsQueryClient", "MetricsQueryClient", "MetricsBatchQueryClient"] +__all__ = ["LogsQueryClient", "MetricsQueryClient", "MetricsClient"] diff --git a/sdk/monitor/azure-monitor-query/azure/monitor/query/aio/_metrics_batch_query_client_async.py b/sdk/monitor/azure-monitor-query/azure/monitor/query/aio/_metrics_client_async.py similarity index 91% rename from sdk/monitor/azure-monitor-query/azure/monitor/query/aio/_metrics_batch_query_client_async.py rename to sdk/monitor/azure-monitor-query/azure/monitor/query/aio/_metrics_client_async.py index f4a8e452dda7..181b32a9a8f5 100644 --- a/sdk/monitor/azure-monitor-query/azure/monitor/query/aio/_metrics_batch_query_client_async.py +++ b/sdk/monitor/azure-monitor-query/azure/monitor/query/aio/_metrics_client_async.py @@ -19,8 +19,8 @@ JSON = MutableMapping[str, Any] # pylint: disable=unsubscriptable-object -class MetricsBatchQueryClient: # pylint: disable=client-accepts-api-version-keyword - """MetricsBatchQueryClient should be used for performing metrics queries on multiple monitored resources in the +class MetricsClient: # pylint: disable=client-accepts-api-version-keyword + """MetricsClient should be used for performing metrics queries on multiple monitored resources in the same region. A credential with authorization at the subscription level is required when using this client. :param str endpoint: The regional endpoint to use, for example @@ -48,12 +48,12 @@ def __init__(self, endpoint: str, credential: AsyncTokenCredential, **kwargs: An self._batch_metrics_op = self._client.metrics_batch @distributed_trace_async - async def query_batch( + async def query_resources( self, + *, resource_uris: Sequence[str], - metric_names: Sequence[str], metric_namespace: str, - *, + metric_names: Sequence[str], timespan: Optional[Union[timedelta, Tuple[datetime, timedelta], Tuple[datetime, datetime]]] = None, granularity: Optional[timedelta] = None, aggregations: Optional[Sequence[str]] = None, @@ -65,12 +65,12 @@ async def query_batch( ) -> List[MetricsQueryResult]: """Lists the metric values for multiple resources. - :param resource_uris: A list of resource URIs to query metrics for. Required. - :type resource_uris: list[str] - :param metric_names: The names of the metrics (comma separated) to retrieve. Required. - :type metric_names: list[str] - :param metric_namespace: Metric namespace that contains the requested metric names. Required. - :type metric_namespace: str + :keyword resource_uris: A list of resource URIs to query metrics for. Required. + :paramtype resource_uris: list[str] + :keyword metric_namespace: Metric namespace that contains the requested metric names. Required. + :paramtype metric_namespace: str + :keyword metric_names: The names of the metrics (comma separated) to retrieve. Required. + :paramtype metric_names: list[str] :keyword timespan: The timespan for which to query the data. This can be a timedelta, a timedelta and a start datetime, or a start datetime/end datetime. :paramtype timespan: Optional[Union[~datetime.timedelta, tuple[~datetime.datetime, ~datetime.timedelta], @@ -110,7 +110,7 @@ async def query_batch( .. admonition:: Example: - .. literalinclude:: ../samples/async_samples/sample_metrics_batch_query_async.py + .. literalinclude:: ../samples/async_samples/sample_metrics_query_multiple_async.py :start-after: [START send_metrics_batch_query_async] :end-before: [END send_metrics_batch_query_async] :language: python @@ -153,7 +153,7 @@ async def query_batch( for value in generated["values"] ] - async def __aenter__(self) -> "MetricsBatchQueryClient": + async def __aenter__(self) -> "MetricsClient": await self._client.__aenter__() return self diff --git a/sdk/monitor/azure-monitor-query/azure/monitor/query/aio/_metrics_query_client_async.py b/sdk/monitor/azure-monitor-query/azure/monitor/query/aio/_metrics_query_client_async.py index e47380ee96e8..657659065191 100644 --- a/sdk/monitor/azure-monitor-query/azure/monitor/query/aio/_metrics_query_client_async.py +++ b/sdk/monitor/azure-monitor-query/azure/monitor/query/aio/_metrics_query_client_async.py @@ -138,7 +138,6 @@ async def query_resource( orderby=order_by, filter=filter, metricnamespace=metric_namespace, - connection_verify=False, **kwargs ) return MetricsQueryResult._from_generated(generated) # pylint: disable=protected-access diff --git a/sdk/monitor/azure-monitor-query/samples/README.md b/sdk/monitor/azure-monitor-query/samples/README.md index c46021fbd36d..2063ca37031e 100644 --- a/sdk/monitor/azure-monitor-query/samples/README.md +++ b/sdk/monitor/azure-monitor-query/samples/README.md @@ -35,13 +35,13 @@ For examples on authenticating with the Azure Monitor service, see [sample_authe ### Metrics query samples - [Send a query using MetricsQueryClient](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/monitor/azure-monitor-query/samples/sample_metrics_query.py) ([async sample](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/monitor/azure-monitor-query/samples/async_samples/sample_metrics_query_async.py)) -- [Send a batch of queries using MetricBatchQueryClient](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/monitor/azure-monitor-query/samples/sample_metrics_batch_query.py) ([async sample](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/monitor/azure-monitor-query/samples/async_samples/sample_metrics_batch_query_async.py)) +- [Send a query to multiple resources at once using MetricsClient](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/monitor/azure-monitor-query/samples/sample_metrics_query_multiple.py) ([async sample](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/monitor/azure-monitor-query/samples/async_samples/sample_metrics_query_multiple_async.py)) - [Get a list of metric namespaces](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/monitor/azure-monitor-query/samples/sample_metric_namespaces.py) ([async sample](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/monitor/azure-monitor-query/samples/async_samples/sample_metric_namespaces_async.py)) - [Get a list of metric definitions](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/monitor/azure-monitor-query/samples/sample_metric_definitions.py) ([async sample](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/monitor/azure-monitor-query/samples/async_samples/sample_metric_definitions_async.py)) ## Prerequisites -- Python 3.7 or later +- Python 3.8 or later - An [Azure subscription][azure_subscription] - To query Logs, you need an [Azure Log Analytics workspace][azure_monitor_create_using_portal]. - To query Metrics, you need an Azure resource of any kind (Storage Account, Key Vault, Cosmos DB, etc.). diff --git a/sdk/monitor/azure-monitor-query/samples/async_samples/sample_metrics_batch_query_async.py b/sdk/monitor/azure-monitor-query/samples/async_samples/sample_metrics_query_multiple_async.py similarity index 87% rename from sdk/monitor/azure-monitor-query/samples/async_samples/sample_metrics_batch_query_async.py rename to sdk/monitor/azure-monitor-query/samples/async_samples/sample_metrics_query_multiple_async.py index d8b796a35603..5aa96685ae9c 100644 --- a/sdk/monitor/azure-monitor-query/samples/async_samples/sample_metrics_batch_query_async.py +++ b/sdk/monitor/azure-monitor-query/samples/async_samples/sample_metrics_query_multiple_async.py @@ -1,13 +1,13 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. """ -FILE: sample_metrics_batch_query_async.py +FILE: sample_metrics_query_multiple_async.py DESCRIPTION: - This sample demonstrates authenticating the MetricsBatchQueryClient and retrieving the "Ingress" + This sample demonstrates authenticating the MetricsClient and retrieving the "Ingress" metric along with the "Average" aggregation type for multiple resources. The query will execute over a timespan of 2 hours with a granularity of 5 minutes. USAGE: - python sample_metrics_batch_query_async.py + python sample_metrics_query_multiple_async.py 1) AZURE_METRICS_ENDPOINT - The regional metrics endpoint to use (i.e. https://westus3.metrics.monitor.azure.com) This example uses DefaultAzureCredential, which requests a token from Azure Active Directory. @@ -24,14 +24,14 @@ from azure.core.exceptions import HttpResponseError from azure.identity.aio import DefaultAzureCredential from azure.monitor.query import MetricAggregationType -from azure.monitor.query.aio import MetricsBatchQueryClient +from azure.monitor.query.aio import MetricsClient async def query_metrics_batch(): endpoint = os.environ["AZURE_METRICS_ENDPOINT"] credential = DefaultAzureCredential() - client = MetricsBatchQueryClient(endpoint, credential) + client = MetricsClient(endpoint, credential) resource_uris = [ '/subscriptions//resourceGroups//providers/Microsoft.Storage/storageAccounts/', @@ -39,10 +39,10 @@ async def query_metrics_batch(): ] async with client: try: - response = await client.query_batch( + response = await client.query_resources( resource_uris=resource_uris, - metric_names=["Ingress"], metric_namespace="Microsoft.Storage/storageAccounts", + metric_names=["Ingress"], timespan=timedelta(hours=2), granularity=timedelta(minutes=5), aggregations=[MetricAggregationType.AVERAGE], diff --git a/sdk/monitor/azure-monitor-query/samples/sample_metrics_batch_query.py b/sdk/monitor/azure-monitor-query/samples/sample_metrics_query_multiple.py similarity index 84% rename from sdk/monitor/azure-monitor-query/samples/sample_metrics_batch_query.py rename to sdk/monitor/azure-monitor-query/samples/sample_metrics_query_multiple.py index 9a527403a41a..7b5864f79cea 100644 --- a/sdk/monitor/azure-monitor-query/samples/sample_metrics_batch_query.py +++ b/sdk/monitor/azure-monitor-query/samples/sample_metrics_query_multiple.py @@ -1,13 +1,13 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. """ -FILE: sample_metrics_batch_query.py +FILE: sample_metrics_query_multiple.py DESCRIPTION: - This sample demonstrates authenticating the MetricsBatchQueryClient and retrieving the "Ingress" + This sample demonstrates authenticating the MetricsClient and retrieving the "Ingress" metric along with the "Average" aggregation type for multiple resources. The query will execute over a timespan of 2 hours with a granularity of 5 minutes. USAGE: - python sample_metrics_batch_query.py + python sample_metrics_query_multiple.py 1) AZURE_METRICS_ENDPOINT - The regional metrics endpoint to use (i.e. https://westus3.metrics.monitor.azure.com) This example uses DefaultAzureCredential, which requests a token from Azure Active Directory. @@ -22,13 +22,13 @@ from azure.core.exceptions import HttpResponseError from azure.identity import DefaultAzureCredential -from azure.monitor.query import MetricsBatchQueryClient, MetricAggregationType +from azure.monitor.query import MetricsClient, MetricAggregationType endpoint = os.environ["AZURE_METRICS_ENDPOINT"] credential = DefaultAzureCredential() -client = MetricsBatchQueryClient(endpoint, credential) +client = MetricsClient(endpoint, credential) resource_uris = [ '/subscriptions//resourceGroups//providers/Microsoft.Storage/storageAccounts/', @@ -36,10 +36,10 @@ ] try: - response = client.query_batch( - resource_uris, - metric_names=["Ingress"], + response = client.query_resources( + resource_uris=resource_uris, metric_namespace="Microsoft.Storage/storageAccounts", + metric_names=["Ingress"], timespan=timedelta(hours=2), granularity=timedelta(minutes=5), aggregations=[MetricAggregationType.AVERAGE], diff --git a/sdk/monitor/azure-monitor-query/setup.py b/sdk/monitor/azure-monitor-query/setup.py index 1c8b40755194..b478e41d6023 100644 --- a/sdk/monitor/azure-monitor-query/setup.py +++ b/sdk/monitor/azure-monitor-query/setup.py @@ -62,17 +62,17 @@ url='https://github.com/Azure/azure-sdk-for-python', keywords="azure, azure sdk", classifiers=[ - "Development Status :: 4 - Beta", + "Development Status :: 5 - Production/Stable", 'Programming Language :: Python', 'Programming Language :: Python :: 3 :: Only', - 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', 'Programming Language :: Python :: 3.10', 'Programming Language :: Python :: 3.11', + 'Programming Language :: Python :: 3.12', 'License :: OSI Approved :: MIT License', ], - python_requires=">=3.7", + python_requires=">=3.8", zip_safe=False, packages=find_packages(exclude=[ 'tests', diff --git a/sdk/monitor/azure-monitor-query/tests/base_testcase.py b/sdk/monitor/azure-monitor-query/tests/base_testcase.py index 176bad558db6..b926370280f0 100644 --- a/sdk/monitor/azure-monitor-query/tests/base_testcase.py +++ b/sdk/monitor/azure-monitor-query/tests/base_testcase.py @@ -31,7 +31,7 @@ def get_client(self, client_class, credential): return self.create_client_from_credential(client_class, credential, **kwargs) -class AzureMonitorQueryMetricsTestCase(AzureRecordedTestCase): +class MetricsQueryClientTestCase(AzureRecordedTestCase): def get_client(self, client_class, credential): @@ -43,7 +43,7 @@ def get_client(self, client_class, credential): return self.create_client_from_credential(client_class, credential, **kwargs) -class AzureMonitorQueryBatchMetricsTestCase(AzureRecordedTestCase): +class MetricsClientTestCase(AzureRecordedTestCase): def get_client(self, client_class, credential, endpoint = None): diff --git a/sdk/monitor/azure-monitor-query/tests/test_metrics_batch_client.py b/sdk/monitor/azure-monitor-query/tests/test_metrics_batch_client.py deleted file mode 100644 index a0d9b7f80622..000000000000 --- a/sdk/monitor/azure-monitor-query/tests/test_metrics_batch_client.py +++ /dev/null @@ -1,44 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See LICENSE.txt in the project root for -# license information. -# ------------------------------------------------------------------------- -from datetime import timedelta -from azure.monitor.query import MetricsBatchQueryClient, MetricAggregationType - -from base_testcase import AzureMonitorQueryBatchMetricsTestCase - - -METRIC_NAME = "requests/count" -METRIC_RESOURCE_PROVIDER = "Microsoft.Insights/components" - - -class TestMetricsClient(AzureMonitorQueryBatchMetricsTestCase): - - def test_batch_metrics_auth(self, recorded_test, monitor_info): - client = self.get_client(MetricsBatchQueryClient, self.get_credential(MetricsBatchQueryClient)) - responses = client.query_batch( - [monitor_info['metrics_resource_id']], - [METRIC_NAME], - METRIC_RESOURCE_PROVIDER, - aggregations=[MetricAggregationType.COUNT], - ) - assert responses - assert len(responses) == 1 - - def test_batch_metrics_granularity(self, recorded_test, monitor_info): - client = self.get_client(MetricsBatchQueryClient, self.get_credential(MetricsBatchQueryClient)) - responses = client.query_batch( - [monitor_info['metrics_resource_id']], - [METRIC_NAME], - METRIC_RESOURCE_PROVIDER, - granularity=timedelta(minutes=5), - aggregations=[MetricAggregationType.COUNT], - ) - assert responses - for response in responses: - assert response.granularity == timedelta(minutes=5) - metric = response.metrics[METRIC_NAME] - assert metric.timeseries - for t in metric.timeseries: - assert t.metadata_values is not None diff --git a/sdk/monitor/azure-monitor-query/tests/test_metrics_batch_client_async.py b/sdk/monitor/azure-monitor-query/tests/test_metrics_batch_client_async.py deleted file mode 100644 index 047c5739d83a..000000000000 --- a/sdk/monitor/azure-monitor-query/tests/test_metrics_batch_client_async.py +++ /dev/null @@ -1,54 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See LICENSE.txt in the project root for -# license information. -# ------------------------------------------------------------------------- -from datetime import timedelta - -import pytest - -from azure.monitor.query import MetricAggregationType -from azure.monitor.query.aio import MetricsBatchQueryClient - -from base_testcase import AzureMonitorQueryBatchMetricsTestCase - - -METRIC_NAME = "requests/count" -METRIC_RESOURCE_PROVIDER = "Microsoft.Insights/components" - - -class TestMetricsClientAsync(AzureMonitorQueryBatchMetricsTestCase): - - @pytest.mark.asyncio - async def test_batch_metrics_auth(self, recorded_test, monitor_info): - client = self.get_client( - MetricsBatchQueryClient, self.get_credential(MetricsBatchQueryClient, is_async=True)) - async with client: - responses = await client.query_batch( - [monitor_info['metrics_resource_id']], - [METRIC_NAME], - METRIC_RESOURCE_PROVIDER, - aggregations=[MetricAggregationType.COUNT], - ) - assert responses - assert len(responses) == 1 - - @pytest.mark.asyncio - async def test_batch_metrics_granularity(self, recorded_test, monitor_info): - client = self.get_client( - MetricsBatchQueryClient, self.get_credential(MetricsBatchQueryClient, is_async=True)) - async with client: - responses = await client.query_batch( - [monitor_info['metrics_resource_id']], - [METRIC_NAME], - METRIC_RESOURCE_PROVIDER, - granularity=timedelta(minutes=5), - aggregations=[MetricAggregationType.COUNT], - ) - assert responses - for response in responses: - assert response.granularity == timedelta(minutes=5) - metric = response.metrics[METRIC_NAME] - assert metric.timeseries - for t in metric.timeseries: - assert t.metadata_values is not None diff --git a/sdk/monitor/azure-monitor-query/tests/test_metrics_client.py b/sdk/monitor/azure-monitor-query/tests/test_metrics_client.py index 4228fa35348a..ed766e5b039a 100644 --- a/sdk/monitor/azure-monitor-query/tests/test_metrics_client.py +++ b/sdk/monitor/azure-monitor-query/tests/test_metrics_client.py @@ -4,117 +4,43 @@ # license information. # ------------------------------------------------------------------------- from datetime import timedelta -from unittest import mock -from azure.monitor.query import MetricsQueryClient, MetricAggregationType, Metric +from azure.monitor.query import MetricsClient, MetricAggregationType -from base_testcase import AzureMonitorQueryMetricsTestCase +from base_testcase import MetricsClientTestCase METRIC_NAME = "requests/count" METRIC_RESOURCE_PROVIDER = "Microsoft.Insights/components" -class TestMetricsClient(AzureMonitorQueryMetricsTestCase): +class TestMetricsClient(MetricsClientTestCase): - def test_metrics_auth(self, recorded_test, monitor_info): - client = self.get_client(MetricsQueryClient, self.get_credential(MetricsQueryClient)) - response = client.query_resource( - monitor_info['metrics_resource_id'], + def test_batch_metrics_auth(self, recorded_test, monitor_info): + client: MetricsClient = self.get_client(MetricsClient, self.get_credential(MetricsClient)) + responses = client.query_resources( + resource_uris=[monitor_info['metrics_resource_id']], + metric_namespace=METRIC_RESOURCE_PROVIDER, metric_names=[METRIC_NAME], - timespan=timedelta(days=1), - aggregations=[MetricAggregationType.COUNT] - ) - assert response - assert response.metrics - - def test_metrics_granularity(self, recorded_test, monitor_info): - client = self.get_client(MetricsQueryClient, self.get_credential(MetricsQueryClient)) - response = client.query_resource( - monitor_info['metrics_resource_id'], + aggregations=[MetricAggregationType.COUNT], + ) + assert responses + assert len(responses) == 1 + + def test_batch_metrics_granularity(self, recorded_test, monitor_info): + client: MetricsClient = self.get_client(MetricsClient, self.get_credential(MetricsClient)) + responses = client.query_resources( + resource_uris=[monitor_info['metrics_resource_id']], + metric_namespace=METRIC_RESOURCE_PROVIDER, metric_names=[METRIC_NAME], - timespan=timedelta(days=1), granularity=timedelta(minutes=5), - aggregations=[MetricAggregationType.COUNT] - ) - assert response - assert response.granularity == timedelta(minutes=5) - metric = response.metrics[METRIC_NAME] - assert metric.timeseries - for t in metric.timeseries: - assert t.metadata_values is not None - - def test_metrics_filter(self, recorded_test, monitor_info): - client = self.get_client(MetricsQueryClient, self.get_credential(MetricsQueryClient)) - response = client.query_resource( - monitor_info['metrics_resource_id'], - metric_names=[METRIC_NAME], - timespan=timedelta(days=1), - granularity=timedelta(minutes=5), - filter="request/success eq '0'", - aggregations=[MetricAggregationType.COUNT] - ) - assert response - metric = response.metrics[METRIC_NAME] - for t in metric.timeseries: - assert t.metadata_values is not None - - def test_metrics_list(self, recorded_test, monitor_info): - client = self.get_client(MetricsQueryClient, self.get_credential(MetricsQueryClient)) - response = client.query_resource( - monitor_info['metrics_resource_id'], - metric_names=[METRIC_NAME], - timespan=timedelta(days=1), - granularity=timedelta(minutes=5), - aggregations=[MetricAggregationType.COUNT] - ) - assert response - metrics = response.metrics - assert len(metrics) == 1 - assert metrics[0].__class__ == Metric - assert metrics[METRIC_NAME].__class__ == Metric - assert metrics[METRIC_NAME] == metrics[0] - - def test_metrics_list_with_commas(self): - """Commas in metric names should be encoded as %2.""" - - with mock.patch("azure.monitor.query._generated.metrics.operations.MetricsOperations.list") as mock_list: - mock_list.return_value = {"foo": "bar"} - client = self.get_client(MetricsQueryClient, self.get_credential(MetricsQueryClient)) - client.query_resource( - "resource", - metric_names=["metric1,metric2", "foo,test,test"], - timespan=timedelta(days=1), - granularity=timedelta(minutes=5), - aggregations=[MetricAggregationType.COUNT] - ) - - assert "metricnames" in mock_list.call_args[1] - assert mock_list.call_args[1]['metricnames'] == "metric1%2metric2,foo%2test%2test" - - - def test_metrics_namespaces(self, recorded_test, monitor_info): - client = self.get_client(MetricsQueryClient, self.get_credential(MetricsQueryClient)) - - response = client.list_metric_namespaces(monitor_info['metrics_resource_id']) - - assert response is not None - for item in response: - assert item - - def test_metrics_definitions(self, recorded_test, monitor_info): - client = self.get_client(MetricsQueryClient, self.get_credential(MetricsQueryClient)) - response = client.list_metric_definitions( - monitor_info['metrics_resource_id'], namespace=METRIC_RESOURCE_PROVIDER) - - assert response is not None - for item in response: - assert item - - def test_client_different_endpoint(self): - credential = self.get_credential(MetricsQueryClient) - endpoint = "https://management.chinacloudapi.cn" - client = MetricsQueryClient(credential, endpoint=endpoint) - - assert client._endpoint == endpoint - assert f"{endpoint}/.default" in client._client._config.authentication_policy._scopes + aggregations=[MetricAggregationType.COUNT], + ) + assert responses + for response in responses: + assert response.granularity == timedelta(minutes=5) + response.metrics + metric = response.metrics[METRIC_NAME] + assert metric.timeseries + for t in metric.timeseries: + assert t.metadata_values is not None diff --git a/sdk/monitor/azure-monitor-query/tests/test_metrics_client_async.py b/sdk/monitor/azure-monitor-query/tests/test_metrics_client_async.py index 0bdf15b40c91..b9c9a0049816 100644 --- a/sdk/monitor/azure-monitor-query/tests/test_metrics_client_async.py +++ b/sdk/monitor/azure-monitor-query/tests/test_metrics_client_async.py @@ -4,144 +4,51 @@ # license information. # ------------------------------------------------------------------------- from datetime import timedelta -import sys -from unittest import mock import pytest -from azure.monitor.query import MetricAggregationType, Metric -from azure.monitor.query.aio import MetricsQueryClient +from azure.monitor.query import MetricAggregationType +from azure.monitor.query.aio import MetricsClient -from base_testcase import AzureMonitorQueryMetricsTestCase +from base_testcase import MetricsClientTestCase METRIC_NAME = "requests/count" METRIC_RESOURCE_PROVIDER = "Microsoft.Insights/components" -class TestMetricsClientAsync(AzureMonitorQueryMetricsTestCase): +class TestMetricsClientAsync(MetricsClientTestCase): @pytest.mark.asyncio - async def test_metrics_auth(self, recorded_test, monitor_info): - client = self.get_client( - MetricsQueryClient, self.get_credential(MetricsQueryClient, is_async=True)) + async def test_batch_metrics_auth(self, recorded_test, monitor_info): + client: MetricsClient = self.get_client( + MetricsClient, self.get_credential(MetricsClient, is_async=True)) async with client: - response = await client.query_resource( - monitor_info['metrics_resource_id'], + responses = await client.query_resources( + resource_uris=[monitor_info['metrics_resource_id']], + metric_namespace=METRIC_RESOURCE_PROVIDER, metric_names=[METRIC_NAME], - timespan=timedelta(days=1), - aggregations=[MetricAggregationType.COUNT] - ) - assert response - assert response.metrics + aggregations=[MetricAggregationType.COUNT], + ) + assert responses + assert len(responses) == 1 @pytest.mark.asyncio - async def test_metrics_granularity(self, recorded_test, monitor_info): - client = self.get_client( - MetricsQueryClient, self.get_credential(MetricsQueryClient, is_async=True)) + async def test_batch_metrics_granularity(self, recorded_test, monitor_info): + client: MetricsClient = self.get_client( + MetricsClient, self.get_credential(MetricsClient, is_async=True)) async with client: - response = await client.query_resource( - monitor_info['metrics_resource_id'], + responses = await client.query_resources( + resource_uris=[monitor_info['metrics_resource_id']], + metric_namespace=METRIC_RESOURCE_PROVIDER, metric_names=[METRIC_NAME], - timespan=timedelta(days=1), granularity=timedelta(minutes=5), - aggregations=[MetricAggregationType.COUNT] - ) - assert response - assert response.granularity == timedelta(minutes=5) - metric = response.metrics[METRIC_NAME] - assert metric.timeseries - for t in metric.timeseries: - assert t.metadata_values is not None - - @pytest.mark.asyncio - async def test_metrics_filter(self, recorded_test, monitor_info): - client = self.get_client( - MetricsQueryClient, self.get_credential(MetricsQueryClient, is_async=True)) - async with client: - response = await client.query_resource( - monitor_info['metrics_resource_id'], - metric_names=[METRIC_NAME], - timespan=timedelta(days=1), - granularity=timedelta(minutes=5), - filter="request/success eq '0'", - aggregations=[MetricAggregationType.COUNT] - ) - assert response - metric = response.metrics[METRIC_NAME] - for t in metric.timeseries: - assert t.metadata_values is not None - - @pytest.mark.asyncio - async def test_metrics_list(self, recorded_test, monitor_info): - client = self.get_client( - MetricsQueryClient, self.get_credential(MetricsQueryClient, is_async=True)) - async with client: - response = await client.query_resource( - monitor_info['metrics_resource_id'], - metric_names=[METRIC_NAME], - timespan=timedelta(days=1), - granularity=timedelta(minutes=5), - aggregations=[MetricAggregationType.COUNT] - ) - assert response - metrics = response.metrics - assert len(metrics) == 1 - assert metrics[0].__class__ == Metric - assert metrics[METRIC_NAME].__class__ == Metric - assert metrics[METRIC_NAME] == metrics[0] - - @pytest.mark.asyncio - @pytest.mark.skipif(sys.version_info < (3, 8), reason="async mocks work differently in Python <= 3.7") - async def test_metrics_list_with_commas(self): - """Commas in metric names should be encoded as %2.""" - - with mock.patch("azure.monitor.query._generated.metrics.aio.operations.MetricsOperations.list") as mock_list: - mock_list.return_value = {"foo": "bar"} - client = self.get_client( - MetricsQueryClient, self.get_credential(MetricsQueryClient, is_async=True)) - async with client: - await client.query_resource( - "resource", - metric_names=["metric1,metric2", "foo,test,test"], - timespan=timedelta(days=1), - granularity=timedelta(minutes=5), - aggregations=[MetricAggregationType.COUNT] - ) - - assert "metricnames" in mock_list.call_args[1] - assert mock_list.call_args[1]['metricnames'] == "metric1%2metric2,foo%2test%2test" - - @pytest.mark.asyncio - async def test_metrics_namespaces(self, recorded_test, monitor_info): - client = self.get_client( - MetricsQueryClient, self.get_credential(MetricsQueryClient, is_async=True)) - - async with client: - response = client.list_metric_namespaces(monitor_info['metrics_resource_id']) - - assert response is not None - async for item in response: - assert item - - @pytest.mark.asyncio - async def test_metrics_definitions(self, recorded_test, monitor_info): - client = self.get_client( - MetricsQueryClient, self.get_credential(MetricsQueryClient, is_async=True)) - - async with client: - response = client.list_metric_definitions( - monitor_info['metrics_resource_id'], namespace=METRIC_RESOURCE_PROVIDER) - - assert response is not None - async for item in response: - assert item - - @pytest.mark.asyncio - async def test_client_different_endpoint(self): - credential = self.get_credential(MetricsQueryClient) - endpoint = "https://management.chinacloudapi.cn" - client = MetricsQueryClient(credential, endpoint=endpoint) - - assert client._endpoint == endpoint - assert f"{endpoint}/.default" in client._client._config.authentication_policy._scopes + aggregations=[MetricAggregationType.COUNT], + ) + assert responses + for response in responses: + assert response.granularity == timedelta(minutes=5) + metric = response.metrics[METRIC_NAME] + assert metric.timeseries + for t in metric.timeseries: + assert t.metadata_values is not None diff --git a/sdk/monitor/azure-monitor-query/tests/test_metrics_query_client.py b/sdk/monitor/azure-monitor-query/tests/test_metrics_query_client.py new file mode 100644 index 000000000000..bab59b0610bd --- /dev/null +++ b/sdk/monitor/azure-monitor-query/tests/test_metrics_query_client.py @@ -0,0 +1,120 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See LICENSE.txt in the project root for +# license information. +# ------------------------------------------------------------------------- +from datetime import timedelta +from unittest import mock + +from azure.monitor.query import MetricsQueryClient, MetricAggregationType, Metric + +from base_testcase import MetricsQueryClientTestCase + + +METRIC_NAME = "requests/count" +METRIC_RESOURCE_PROVIDER = "Microsoft.Insights/components" + + +class TestMetricsQueryClient(MetricsQueryClientTestCase): + + def test_metrics_auth(self, recorded_test, monitor_info): + client = self.get_client(MetricsQueryClient, self.get_credential(MetricsQueryClient)) + response = client.query_resource( + monitor_info['metrics_resource_id'], + metric_names=[METRIC_NAME], + timespan=timedelta(days=1), + aggregations=[MetricAggregationType.COUNT] + ) + assert response + assert response.metrics + + def test_metrics_granularity(self, recorded_test, monitor_info): + client = self.get_client(MetricsQueryClient, self.get_credential(MetricsQueryClient)) + response = client.query_resource( + monitor_info['metrics_resource_id'], + metric_names=[METRIC_NAME], + timespan=timedelta(days=1), + granularity=timedelta(minutes=5), + aggregations=[MetricAggregationType.COUNT] + ) + assert response + assert response.granularity == timedelta(minutes=5) + metric = response.metrics[METRIC_NAME] + assert metric.timeseries + for t in metric.timeseries: + assert t.metadata_values is not None + + def test_metrics_filter(self, recorded_test, monitor_info): + client = self.get_client(MetricsQueryClient, self.get_credential(MetricsQueryClient)) + response = client.query_resource( + monitor_info['metrics_resource_id'], + metric_names=[METRIC_NAME], + timespan=timedelta(days=1), + granularity=timedelta(minutes=5), + filter="request/success eq '0'", + aggregations=[MetricAggregationType.COUNT] + ) + assert response + metric = response.metrics[METRIC_NAME] + for t in metric.timeseries: + assert t.metadata_values is not None + + def test_metrics_list(self, recorded_test, monitor_info): + client = self.get_client(MetricsQueryClient, self.get_credential(MetricsQueryClient)) + response = client.query_resource( + monitor_info['metrics_resource_id'], + metric_names=[METRIC_NAME], + timespan=timedelta(days=1), + granularity=timedelta(minutes=5), + aggregations=[MetricAggregationType.COUNT] + ) + assert response + metrics = response.metrics + assert len(metrics) == 1 + assert metrics[0].__class__ == Metric + assert metrics[METRIC_NAME].__class__ == Metric + assert metrics[METRIC_NAME] == metrics[0] + + def test_metrics_list_with_commas(self): + """Commas in metric names should be encoded as %2.""" + + with mock.patch("azure.monitor.query._generated.metrics.operations.MetricsOperations.list") as mock_list: + mock_list.return_value = {"foo": "bar"} + client = self.get_client(MetricsQueryClient, self.get_credential(MetricsQueryClient)) + client.query_resource( + "resource", + metric_names=["metric1,metric2", "foo,test,test"], + timespan=timedelta(days=1), + granularity=timedelta(minutes=5), + aggregations=[MetricAggregationType.COUNT] + ) + + assert "metricnames" in mock_list.call_args[1] + assert mock_list.call_args[1]['metricnames'] == "metric1%2metric2,foo%2test%2test" + + + def test_metrics_namespaces(self, recorded_test, monitor_info): + client = self.get_client(MetricsQueryClient, self.get_credential(MetricsQueryClient)) + + response = client.list_metric_namespaces(monitor_info['metrics_resource_id']) + + assert response is not None + for item in response: + assert item + + def test_metrics_definitions(self, recorded_test, monitor_info): + client = self.get_client(MetricsQueryClient, self.get_credential(MetricsQueryClient)) + response = client.list_metric_definitions( + monitor_info['metrics_resource_id'], namespace=METRIC_RESOURCE_PROVIDER) + + assert response is not None + for item in response: + assert item + + def test_client_different_endpoint(self): + credential = self.get_credential(MetricsQueryClient) + endpoint = "https://management.chinacloudapi.cn" + client = MetricsQueryClient(credential, endpoint=endpoint) + + assert client._endpoint == endpoint + assert f"{endpoint}/.default" in client._client._config.authentication_policy._scopes diff --git a/sdk/monitor/azure-monitor-query/tests/test_metrics_query_client_async.py b/sdk/monitor/azure-monitor-query/tests/test_metrics_query_client_async.py new file mode 100644 index 000000000000..6ddab41e322c --- /dev/null +++ b/sdk/monitor/azure-monitor-query/tests/test_metrics_query_client_async.py @@ -0,0 +1,147 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See LICENSE.txt in the project root for +# license information. +# ------------------------------------------------------------------------- +from datetime import timedelta +import sys +from unittest import mock + +import pytest + +from azure.monitor.query import MetricAggregationType, Metric +from azure.monitor.query.aio import MetricsQueryClient + +from base_testcase import MetricsQueryClientTestCase + + +METRIC_NAME = "requests/count" +METRIC_RESOURCE_PROVIDER = "Microsoft.Insights/components" + + +class TestMetricsQueryClientAsync(MetricsQueryClientTestCase): + + @pytest.mark.asyncio + async def test_metrics_auth(self, recorded_test, monitor_info): + client = self.get_client( + MetricsQueryClient, self.get_credential(MetricsQueryClient, is_async=True)) + async with client: + response = await client.query_resource( + monitor_info['metrics_resource_id'], + metric_names=[METRIC_NAME], + timespan=timedelta(days=1), + aggregations=[MetricAggregationType.COUNT] + ) + assert response + assert response.metrics + + @pytest.mark.asyncio + async def test_metrics_granularity(self, recorded_test, monitor_info): + client = self.get_client( + MetricsQueryClient, self.get_credential(MetricsQueryClient, is_async=True)) + async with client: + response = await client.query_resource( + monitor_info['metrics_resource_id'], + metric_names=[METRIC_NAME], + timespan=timedelta(days=1), + granularity=timedelta(minutes=5), + aggregations=[MetricAggregationType.COUNT] + ) + assert response + assert response.granularity == timedelta(minutes=5) + metric = response.metrics[METRIC_NAME] + assert metric.timeseries + for t in metric.timeseries: + assert t.metadata_values is not None + + @pytest.mark.asyncio + async def test_metrics_filter(self, recorded_test, monitor_info): + client = self.get_client( + MetricsQueryClient, self.get_credential(MetricsQueryClient, is_async=True)) + async with client: + response = await client.query_resource( + monitor_info['metrics_resource_id'], + metric_names=[METRIC_NAME], + timespan=timedelta(days=1), + granularity=timedelta(minutes=5), + filter="request/success eq '0'", + aggregations=[MetricAggregationType.COUNT] + ) + assert response + metric = response.metrics[METRIC_NAME] + for t in metric.timeseries: + assert t.metadata_values is not None + + @pytest.mark.asyncio + async def test_metrics_list(self, recorded_test, monitor_info): + client = self.get_client( + MetricsQueryClient, self.get_credential(MetricsQueryClient, is_async=True)) + async with client: + response = await client.query_resource( + monitor_info['metrics_resource_id'], + metric_names=[METRIC_NAME], + timespan=timedelta(days=1), + granularity=timedelta(minutes=5), + aggregations=[MetricAggregationType.COUNT] + ) + assert response + metrics = response.metrics + assert len(metrics) == 1 + assert metrics[0].__class__ == Metric + assert metrics[METRIC_NAME].__class__ == Metric + assert metrics[METRIC_NAME] == metrics[0] + + @pytest.mark.asyncio + @pytest.mark.skipif(sys.version_info < (3, 8), reason="async mocks work differently in Python <= 3.7") + async def test_metrics_list_with_commas(self): + """Commas in metric names should be encoded as %2.""" + + with mock.patch("azure.monitor.query._generated.metrics.aio.operations.MetricsOperations.list") as mock_list: + mock_list.return_value = {"foo": "bar"} + client = self.get_client( + MetricsQueryClient, self.get_credential(MetricsQueryClient, is_async=True)) + async with client: + await client.query_resource( + "resource", + metric_names=["metric1,metric2", "foo,test,test"], + timespan=timedelta(days=1), + granularity=timedelta(minutes=5), + aggregations=[MetricAggregationType.COUNT] + ) + + assert "metricnames" in mock_list.call_args[1] + assert mock_list.call_args[1]['metricnames'] == "metric1%2metric2,foo%2test%2test" + + @pytest.mark.asyncio + async def test_metrics_namespaces(self, recorded_test, monitor_info): + client = self.get_client( + MetricsQueryClient, self.get_credential(MetricsQueryClient, is_async=True)) + + async with client: + response = client.list_metric_namespaces(monitor_info['metrics_resource_id']) + + assert response is not None + async for item in response: + assert item + + @pytest.mark.asyncio + async def test_metrics_definitions(self, recorded_test, monitor_info): + client = self.get_client( + MetricsQueryClient, self.get_credential(MetricsQueryClient, is_async=True)) + + async with client: + response = client.list_metric_definitions( + monitor_info['metrics_resource_id'], namespace=METRIC_RESOURCE_PROVIDER) + + assert response is not None + async for item in response: + assert item + + @pytest.mark.asyncio + async def test_client_different_endpoint(self): + credential = self.get_credential(MetricsQueryClient) + endpoint = "https://management.chinacloudapi.cn" + client = MetricsQueryClient(credential, endpoint=endpoint) + + assert client._endpoint == endpoint + assert f"{endpoint}/.default" in client._client._config.authentication_policy._scopes