diff --git a/sdk/monitor/azure-monitor-query/CHANGELOG.md b/sdk/monitor/azure-monitor-query/CHANGELOG.md index 73082cae16b5..c4860b306f48 100644 --- a/sdk/monitor/azure-monitor-query/CHANGELOG.md +++ b/sdk/monitor/azure-monitor-query/CHANGELOG.md @@ -1,3 +1,9 @@ # Release History -## 1.0.0b1 (Unreleased) \ No newline at end of file +## 1.0.0b1 (Unreleased) + + **Features** + - Version (1.0.0b1) is the first preview of our efforts to create a user-friendly and Pythonic client library for Azure Monitor Query. + For more information about this, and preview releases of other Azure SDK libraries, please visit https://azure.github.io/azure-sdk/releases/latest/python.html. + - Added `LogsQueryClient` to query log analytics. + - Implements the `MetricsQueryClient` for querying metrics, listing namespaces and metric definitions. diff --git a/sdk/monitor/azure-monitor-query/azure/monitor/query/_helpers.py b/sdk/monitor/azure-monitor-query/azure/monitor/query/_helpers.py index 8dc7dec0c88a..7ee12be0a0be 100644 --- a/sdk/monitor/azure-monitor-query/azure/monitor/query/_helpers.py +++ b/sdk/monitor/azure-monitor-query/azure/monitor/query/_helpers.py @@ -50,17 +50,19 @@ def order_results(request_order, responses): return ordered def construct_iso8601(start=None, end=None, duration=None): + iso_str = None if start is not None: start = Serializer.serialize_iso(start) if end is not None: end = Serializer.serialize_iso(end) - return start + '/' + end + iso_str = start + '/' + end elif duration is not None: - return start + '/' + duration + iso_str = start + '/' + duration else: raise ValueError("Start time must be provided aling with duration or end time.") elif end is not None: end = Serializer.serialize_iso(end) - return duration + '/' + end + iso_str = duration + '/' + end else: - return duration + iso_str = duration + return iso_str diff --git a/sdk/monitor/azure-monitor-query/azure/monitor/query/_log_query_client.py b/sdk/monitor/azure-monitor-query/azure/monitor/query/_log_query_client.py index 024d3afdfcfa..90995516a64b 100644 --- a/sdk/monitor/azure-monitor-query/azure/monitor/query/_log_query_client.py +++ b/sdk/monitor/azure-monitor-query/azure/monitor/query/_log_query_client.py @@ -39,25 +39,28 @@ def __init__(self, credential, **kwargs): ) self._query_op = self._client.query - def query(self, workspace_id, query, **kwargs): - # type: (str, str, Any) -> LogsQueryResults + def query(self, workspace_id, query, duration=None, **kwargs): + # type: (str, str, str, Any) -> LogsQueryResults """Execute an Analytics query. Executes an Analytics query for data. + **Note**: Although the start_time, end_time, duration are optional parameters, it is highly + recommended to specify the timespan. If not, the entire dataset is queried. + :param workspace_id: ID of the workspace. This is Workspace ID from the Properties blade in the Azure portal. :type workspace_id: str :param query: The Analytics query. Learn more about the `Analytics query syntax `_. :type query: str + :param str duration: The duration for which to query the data. This can also be accompanied + with either start_time or end_time. If start_time or end_time is not provided, the current time is + taken as the end time. This should be provided in a ISO8601 string format like 'PT1H', 'P1Y2M10DT2H30M'. :keyword datetime start_time: The start time from which to query the data. This should be accompanied with either end_time or duration. :keyword datetime end_time: The end time till which to query the data. This should be accompanied with either start_time or duration. - :keyword str duration: The duration for which to query the data. This can also be accompanied - with either start_time or end_time. If start_time or end_time is not provided, the current time is - taken as the end time. This should be provided in a ISO8601 string format like 'PT1H', 'P1Y2M10DT2H30M'. :keyword int server_timeout: the server timeout in seconds. The default timeout is 3 minutes, and the maximum timeout is 10 minutes. :keyword bool include_statistics: To get information about query statistics. @@ -78,7 +81,6 @@ def query(self, workspace_id, query, **kwargs): """ start = kwargs.pop('start_time', None) end = kwargs.pop('end_time', None) - duration = kwargs.pop('duration', None) timespan = construct_iso8601(start, end, duration) include_statistics = kwargs.pop("include_statistics", False) include_render = kwargs.pop("include_render", False) 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 c2ea123955f6..d2560264714e 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 @@ -43,21 +43,24 @@ def __init__(self, credential, **kwargs): self._namespace_op = self._client.metric_namespaces self._definitions_op = self._client.metric_definitions - def query(self, resource_uri, metric_names, **kwargs): - # type: (str, list, Any) -> MetricsResult + def query(self, resource_uri, metric_names, duration=None, **kwargs): + # type: (str, list, str, Any) -> MetricsResult """Lists the metric values for a resource. + **Note**: Although the start_time, end_time, duration are optional parameters, it is highly + recommended to specify the timespan. If not, the entire dataset is queried. + :param resource_uri: The identifier of the resource. :type resource_uri: str :param metric_names: The names of the metrics to retrieve. :type metric_names: list + :param str duration: The duration for which to query the data. This can also be accompanied + with either start_time or end_time. If start_time or end_time is not provided, the current time is + taken as the end time. This should be provided in a ISO8601 string format like 'PT1H', 'P1Y2M10DT2H30M'. :keyword datetime start_time: The start time from which to query the data. This should be accompanied with either end_time or duration. :keyword datetime end_time: The end time till which to query the data. This should be accompanied with either start_time or duration. - :keyword str duration: The duration for which to query the data. This can also be accompanied - with either start_time or end_time. If start_time or end_time is not provided, the current time is - taken as the end time. This should be provided in a ISO8601 string format like 'PT1H', 'P1Y2M10DT2H30M'. :keyword interval: The interval (i.e. timegrain) of the query. :paramtype interval: ~datetime.timedelta :keyword aggregation: The list of aggregation types (comma separated) to retrieve. @@ -91,7 +94,6 @@ def query(self, resource_uri, metric_names, **kwargs): """ start = kwargs.pop('start_time', None) end = kwargs.pop('end_time', None) - duration = kwargs.pop('duration', None) timespan = construct_iso8601(start, end, duration) kwargs.setdefault("metricnames", ",".join(metric_names)) kwargs.setdefault("timespan", timespan) diff --git a/sdk/monitor/azure-monitor-query/azure/monitor/query/_models.py b/sdk/monitor/azure-monitor-query/azure/monitor/query/_models.py index f84a258d2119..cf1e1a90af9c 100644 --- a/sdk/monitor/azure-monitor-query/azure/monitor/query/_models.py +++ b/sdk/monitor/azure-monitor-query/azure/monitor/query/_models.py @@ -8,7 +8,7 @@ import uuid from typing import Any, Optional, List -from ._helpers import order_results +from ._helpers import order_results, construct_iso8601 from ._generated.models import ( Column as InternalColumn, QueryBody as InternalQueryBody, @@ -154,9 +154,13 @@ class LogsQueryRequest(InternalLogQueryRequest): :param query: The Analytics query. Learn more about the `Analytics query syntax `_. :type query: str - :param timespan: The timespan (in ISO8601 duration format) in which to run the query. - If this parameter is not specified, the query will run over all data. - :type timespan: str + :param str duration: The duration for which to query the data. This can also be accompanied + with either start_time or end_time. If start_time or end_time is not provided, the current time is + taken as the end time. This should be provided in a ISO8601 string format like 'PT1H', 'P1Y2M10DT2H30M'. + :keyword datetime start_time: The start time from which to query the data. This should be accompanied + with either end_time or duration. + :keyword datetime end_time: The end time till which to query the data. This should be accompanied + with either start_time or duration. :param workspace: Workspace Id to be included in the query. :type workspace: str :keyword request_id: The error details. @@ -165,9 +169,12 @@ class LogsQueryRequest(InternalLogQueryRequest): :paramtype headers: dict[str, str] """ - def __init__(self, query, workspace, timespan=None, **kwargs): + def __init__(self, query, workspace, duration=None, **kwargs): # type: (str, str, Optional[str], Any) -> None super(LogsQueryRequest, self).__init__(**kwargs) + start = kwargs.pop('start_time', None) + end = kwargs.pop('end_time', None) + timespan = construct_iso8601(start, end, duration) self.id = kwargs.get("request_id", str(uuid.uuid4())) self.headers = kwargs.get("headers", None) self.body = { diff --git a/sdk/monitor/azure-monitor-query/azure/monitor/query/aio/_helpers_asyc.py b/sdk/monitor/azure-monitor-query/azure/monitor/query/aio/_helpers_asyc.py index cb0769376e61..0dc26a8903a4 100644 --- a/sdk/monitor/azure-monitor-query/azure/monitor/query/aio/_helpers_asyc.py +++ b/sdk/monitor/azure-monitor-query/azure/monitor/query/aio/_helpers_asyc.py @@ -34,4 +34,4 @@ def get_metrics_authentication_policy( if hasattr(credential, "get_token"): return AsyncBearerTokenCredentialPolicy(credential, "https://management.azure.com/.default") - raise TypeError("Unsupported credential") \ No newline at end of file + raise TypeError("Unsupported credential") diff --git a/sdk/monitor/azure-monitor-query/azure/monitor/query/aio/_log_query_client_async.py b/sdk/monitor/azure-monitor-query/azure/monitor/query/aio/_log_query_client_async.py index 1eb4cc5229c3..cc743a7f8f5c 100644 --- a/sdk/monitor/azure-monitor-query/azure/monitor/query/aio/_log_query_client_async.py +++ b/sdk/monitor/azure-monitor-query/azure/monitor/query/aio/_log_query_client_async.py @@ -37,24 +37,32 @@ def __init__(self, credential: "AsyncTokenCredential", **kwargs: Any) -> None: ) self._query_op = self._client.query - async def query(self, workspace_id: str, query: str, **kwargs: Any) -> LogsQueryResults: + async def query( + self, + workspace_id: str, + query: str, + duration: str = None, + **kwargs: Any) -> LogsQueryResults: """Execute an Analytics query. Executes an Analytics query for data. + **Note**: Although the start_time, end_time, duration are optional parameters, it is highly + recommended to specify the timespan. If not, the entire dataset is queried. + :param workspace_id: ID of the workspace. This is Workspace ID from the Properties blade in the Azure portal. :type workspace_id: str :param query: The Analytics query. Learn more about the `Analytics query syntax `_. :type query: str + :param str duration: The duration for which to query the data. This can also be accompanied + with either start_time or end_time. If start_time or end_time is not provided, the current time is + taken as the end time. This should be provided in a ISO8601 string format like 'PT1H', 'P1Y2M10DT2H30M'. :keyword datetime start_time: The start time from which to query the data. This should be accompanied with either end_time or duration. :keyword datetime end_time: The end time till which to query the data. This should be accompanied with either start_time or duration. - :keyword str duration: The duration for which to query the data. This can also be accompanied - with either start_time or end_time. If start_time or end_time is not provided, the current time is - taken as the end time. This should be provided in a ISO8601 string format like 'PT1H', 'P1Y2M10DT2H30M'. :keyword int server_timeout: the server timeout. The default timeout is 3 minutes, and the maximum timeout is 10 minutes. :keyword bool include_statistics: To get information about query statistics. @@ -75,7 +83,6 @@ async def query(self, workspace_id: str, query: str, **kwargs: Any) -> LogsQuery """ start = kwargs.pop('start_time', None) end = kwargs.pop('end_time', None) - duration = kwargs.pop('duration', None) timespan = construct_iso8601(start, end, duration) include_statistics = kwargs.pop("include_statistics", False) include_render = kwargs.pop("include_render", False) 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 2189385f4dff..462e66a72ce8 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 @@ -42,20 +42,23 @@ def __init__(self, credential: "AsyncTokenCredential", **kwargs: Any) -> None: self._namespace_op = self._client.metric_namespaces self._definitions_op = self._client.metric_definitions - async def query(self, resource_uri: str, metric_names: List, **kwargs: Any) -> MetricsResult: + async def query(self, resource_uri: str, metric_names: List, duration: str = None, **kwargs: Any) -> MetricsResult: """Lists the metric values for a resource. + **Note**: Although the start_time, end_time, duration are optional parameters, it is highly + recommended to specify the timespan. If not, the entire dataset is queried. + :param resource_uri: The identifier of the resource. :type resource_uri: str :param metric_names: The names of the metrics to retrieve. :type metric_names: list + :param str duration: The duration for which to query the data. This can also be accompanied + with either start_time or end_time. If start_time or end_time is not provided, the current time is + taken as the end time. This should be provided in a ISO8601 string format like 'PT1H', 'P1Y2M10DT2H30M'. :keyword datetime start_time: The start time from which to query the data. This should be accompanied with either end_time or duration. :keyword datetime end_time: The end time till which to query the data. This should be accompanied with either start_time or duration. - :keyword str duration: The duration for which to query the data. This can also be accompanied - with either start_time or end_time. If start_time or end_time is not provided, the current time is - taken as the end time. This should be provided in a ISO8601 string format like 'PT1H', 'P1Y2M10DT2H30M'. :keyword interval: The interval (i.e. timegrain) of the query. :paramtype interval: ~datetime.timedelta :keyword aggregation: The list of aggregation types (comma separated) to retrieve. @@ -89,7 +92,6 @@ async def query(self, resource_uri: str, metric_names: List, **kwargs: Any) -> M """ start = kwargs.pop('start_time', None) end = kwargs.pop('end_time', None) - duration = kwargs.pop('duration', None) timespan = construct_iso8601(start, end, duration) kwargs.setdefault("metricnames", ",".join(metric_names)) kwargs.setdefault("timespan", timespan) diff --git a/sdk/monitor/azure-monitor-query/samples/sample_batch_query.py b/sdk/monitor/azure-monitor-query/samples/sample_batch_query.py index a0ec5658a5a8..fc2f63d68aae 100644 --- a/sdk/monitor/azure-monitor-query/samples/sample_batch_query.py +++ b/sdk/monitor/azure-monitor-query/samples/sample_batch_query.py @@ -1,9 +1,10 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. +from datetime import datetime import os import pandas as pd -from azure.monitor.query import LogsQueryClient +from azure.monitor.query import LogsQueryClient, LogsQueryRequest from azure.identity import ClientSecretCredential @@ -16,37 +17,28 @@ client = LogsQueryClient(credential) requests = [ - { - "id": "1", - "headers": { - "Content-Type": "application/json" - }, - "body": { - "query": "AzureActivity | summarize count()", - "timespan": "PT1H" - }, - "method": "POST", - "path": "/query", - "workspace": os.environ['LOG_WORKSPACE_ID'] - }, - { - "id": "2", - "headers": { - "Content-Type": "application/json" - }, - "body": { - "query": "AzureActivity | summarize count()", - "timespan": "PT1H" - }, - "method": "POST", - "path": "/fakePath", - "workspace": os.environ['LOG_WORKSPACE_ID'] - } + LogsQueryRequest( + query="AzureActivity | summarize count()", + duration="PT1H", + workspace= os.environ['LOG_WORKSPACE_ID'] + ), + LogsQueryRequest( + query= """AppRequests | take 10 | + summarize avgRequestDuration=avg(DurationMs) by bin(TimeGenerated, 10m), _ResourceId""", + duration="PT1H", + start_time=datetime(2021, 6, 2), + workspace= os.environ['LOG_WORKSPACE_ID'] + ), + LogsQueryRequest( + query= "AppRequests | take 2", + workspace= os.environ['LOG_WORKSPACE_ID'] + ), ] response = client.batch_query(requests) for response in response.responses: body = response.body + print(response.id) if not body.tables: print("Something is wrong") else: diff --git a/sdk/monitor/azure-monitor-query/samples/sample_batch_query_build.py b/sdk/monitor/azure-monitor-query/samples/sample_batch_query_serialized.py similarity index 51% rename from sdk/monitor/azure-monitor-query/samples/sample_batch_query_build.py rename to sdk/monitor/azure-monitor-query/samples/sample_batch_query_serialized.py index 4c9a3e6f24c2..a0ec5658a5a8 100644 --- a/sdk/monitor/azure-monitor-query/samples/sample_batch_query_build.py +++ b/sdk/monitor/azure-monitor-query/samples/sample_batch_query_serialized.py @@ -3,7 +3,7 @@ import os import pandas as pd -from azure.monitor.query import LogsQueryClient, LogsQueryRequest +from azure.monitor.query import LogsQueryClient from azure.identity import ClientSecretCredential @@ -16,27 +16,37 @@ client = LogsQueryClient(credential) requests = [ - LogsQueryRequest( - query="AzureActivity | summarize count()", - timespan="PT1H", - workspace= os.environ['LOG_WORKSPACE_ID'] - ), - LogsQueryRequest( - query= """AppRequests | take 10 | - summarize avgRequestDuration=avg(DurationMs) by bin(TimeGenerated, 10m), _ResourceId""", - timespan="PT1H", - workspace= os.environ['LOG_WORKSPACE_ID'] - ), - LogsQueryRequest( - query= "AppRequests | take 2", - workspace= os.environ['LOG_WORKSPACE_ID'] - ), + { + "id": "1", + "headers": { + "Content-Type": "application/json" + }, + "body": { + "query": "AzureActivity | summarize count()", + "timespan": "PT1H" + }, + "method": "POST", + "path": "/query", + "workspace": os.environ['LOG_WORKSPACE_ID'] + }, + { + "id": "2", + "headers": { + "Content-Type": "application/json" + }, + "body": { + "query": "AzureActivity | summarize count()", + "timespan": "PT1H" + }, + "method": "POST", + "path": "/fakePath", + "workspace": os.environ['LOG_WORKSPACE_ID'] + } ] response = client.batch_query(requests) for response in response.responses: body = response.body - print(response.id) if not body.tables: print("Something is wrong") else: diff --git a/sdk/monitor/azure-monitor-query/samples/sample_log_query_client.py b/sdk/monitor/azure-monitor-query/samples/sample_log_query_client.py index 4e34fa83f327..3e20c82ce773 100644 --- a/sdk/monitor/azure-monitor-query/samples/sample_log_query_client.py +++ b/sdk/monitor/azure-monitor-query/samples/sample_log_query_client.py @@ -23,7 +23,7 @@ summarize avgRequestDuration=avg(DurationMs) by bin(TimeGenerated, 10m), _ResourceId""" # returns LogsQueryResults -response = client.query(os.environ['LOG_WORKSPACE_ID'], query) +response = client.query(os.environ['LOG_WORKSPACE_ID'], query, start_time=datetime(2021, 6, 2), end_time=datetime.now()) if not response.tables: print("No results for the query")