diff --git a/sdk/monitor/azure-monitor-query/README.md b/sdk/monitor/azure-monitor-query/README.md
index bed71fe2b210..59145934b64c 100644
--- a/sdk/monitor/azure-monitor-query/README.md
+++ b/sdk/monitor/azure-monitor-query/README.md
@@ -1,3 +1,287 @@
# Azure Monitor Query client library for Python
-TODO
+Azure Monitor helps you maximize the availability and performance of your applications and services. It delivers a comprehensive solution for collecting, analyzing, and acting on telemetry from your cloud and on-premises environments.
+
+All data collected by Azure Monitor fits into one of two fundamental types, metrics and logs. Metrics are numerical values that describe some aspect of a system at a particular point in time. They are lightweight and capable of supporting near real-time scenarios. Logs contain different kinds of data organized into records with different sets of properties for each type. Telemetry such as events and traces are stored as logs in addition to performance data so that it can all be combined for analysis.
+
+[Source code][python-query-src] | [Package (PyPI)][python-query-pypi] | [API reference documentation][python-query-ref-docs] | [Product documentation][python-query-product-docs] | [Samples][python-query-samples] | [Changelog][python-query-changelog]
+
+## Getting started
+
+### Prerequisites
+* Python 2.7, or 3.6 or later is required to use this package.
+* You must have an [Azure subscription][azure_subscription].
+
+
+### Install the package
+Install the Azure Monitor Query client library for Python with [pip][pip]:
+
+```bash
+pip install azure-monitor-query --pre
+```
+
+### Authenticate the client
+A **token credential** is necessary to instantiate both the LogsClient and the MetricsClient object.
+
+```Python
+from azure.monitor.query import LogsClient
+from azure.identity import ClientSecretCredential
+
+
+credential = ClientSecretCredential(
+ client_id = os.environ['AZURE_CLIENT_ID'],
+ client_secret = os.environ['AZURE_CLIENT_SECRET'],
+ tenant_id = os.environ['AZURE_TENANT_ID']
+ )
+
+client = LogsClient(credential)
+```
+
+```Python
+from azure.monitor.query import MetricsClient
+from azure.identity import ClientSecretCredential
+
+
+credential = ClientSecretCredential(
+ client_id = os.environ['AZURE_CLIENT_ID'],
+ client_secret = os.environ['AZURE_CLIENT_SECRET'],
+ tenant_id = os.environ['AZURE_TENANT_ID']
+ )
+
+client = MetricsClient(credential)
+```
+
+## Key concepts
+
+### Logs
+
+Azure Monitor Logs is a feature of Azure Monitor that collects and organizes log and performance data from monitored
+resources. Data from different sources such as platform logs from Azure services, log and performance data from virtual
+machines agents, and usage and performance data from applications can be consolidated into a single workspace so they
+can be analyzed together using a sophisticated query language that's capable of quickly analyzing millions of records.
+You may perform a simple query that just retrieves a specific set of records or perform sophisticated data analysis to
+identify critical patterns in your monitoring data.
+
+#### Log Analytics workspaces
+
+Data collected by Azure Monitor Logs is stored in one or more Log Analytics workspaces. The workspace defines the
+geographic location of the data, access rights defining which users can access data, and configuration settings such as
+the pricing tier and data retention.
+
+You must create at least one workspace to use Azure Monitor Logs. A single workspace may be sufficient for all of your
+monitoring data, or may choose to create multiple workspaces depending on your requirements. For example, you might have
+one workspace for your production data and another for testing.
+
+#### Log queries
+
+Data is retrieved from a Log Analytics workspace using a log query which is a read-only request to process data and
+return results. Log queries are written
+in [Kusto Query Language (KQL)](https://docs.microsoft.com/azure/data-explorer/kusto/query/), which is the same query
+language used by Azure Data Explorer. You can write log queries in Log Analytics to interactively analyze their results,
+use them in alert rules to be proactively notified of issues, or include their results in workbooks or dashboards.
+Insights include prebuilt queries to support their views and workbooks.
+
+### Metrics
+
+Azure Monitor Metrics is a feature of Azure Monitor that collects numeric data from monitored resources into a time
+series database. Metrics are numerical values that are collected at regular intervals and describe some aspect of a
+system at a particular time. Metrics in Azure Monitor are lightweight and capable of supporting near real-time scenarios
+making them particularly useful for alerting and fast detection of issues. You can analyze them interactively with
+metrics explorer, be proactively notified with an alert when a value crosses a threshold, or visualize them in a
+workbook or dashboard.
+
+#### Metrics data structure
+
+Data collected by Azure Monitor Metrics is stored in a time-series database which is optimized for analyzing
+time-stamped data. Each set of metric values is a time series with the following properties:
+
+- The time the value was collected
+- The resource the value is associated with
+- A namespace that acts like a category for the metric
+- A metric name
+- The value itself
+- Some metrics may have multiple dimensions as described in Multi-dimensional metrics. Custom metrics can have up to 10
+ dimensions.
+
+
+## Examples
+
+### Get logs for a query
+
+```Python
+import os
+import pandas as pd
+from azure.monitor.query import LogsClient
+from azure.identity import ClientSecretCredential
+
+
+credential = ClientSecretCredential(
+ client_id = os.environ['AZURE_CLIENT_ID'],
+ client_secret = os.environ['AZURE_CLIENT_SECRET'],
+ tenant_id = os.environ['AZURE_TENANT_ID']
+ )
+
+client = LogsClient(credential)
+
+# Response time trend
+# request duration over the last 12 hours.
+query = """AppRequests |
+where TimeGenerated > ago(12h) |
+summarize avgRequestDuration=avg(DurationMs) by bin(TimeGenerated, 10m), _ResourceId"""
+
+# returns LogsQueryResults
+response = client.query(os.environ['LOG_WORKSPACE_ID'], query)
+
+if not response.tables:
+ print("No results for the query")
+
+for table in response.tables:
+ df = pd.DataFrame(table.rows, columns=[col.name for col in table.columns])
+ print(df)
+```
+
+### Get Logs for multiple queries
+
+```Python
+import os
+import pandas as pd
+from azure.monitor.query import LogsClient, LogsQueryRequest
+from azure.identity import ClientSecretCredential
+
+
+credential = ClientSecretCredential(
+ client_id = os.environ['AZURE_CLIENT_ID'],
+ client_secret = os.environ['AZURE_CLIENT_SECRET'],
+ tenant_id = os.environ['AZURE_TENANT_ID']
+ )
+
+client = LogsClient(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']
+ ),
+]
+response = client.batch_query(requests)
+
+for response in response.responses:
+ body = response.body
+ if not body.tables:
+ print("Something is wrong")
+ else:
+ for table in body.tables:
+ df = pd.DataFrame(table.rows, columns=[col.name for col in table.columns])
+ print(df)
+```
+
+### Get logs with server timeout
+
+```Python
+import os
+import pandas as pd
+from azure.monitor.query import LogsClient
+from azure.identity import ClientSecretCredential
+
+
+credential = ClientSecretCredential(
+ client_id = os.environ['AZURE_CLIENT_ID'],
+ client_secret = os.environ['AZURE_CLIENT_SECRET'],
+ tenant_id = os.environ['AZURE_TENANT_ID']
+ )
+
+client = LogsClient(credential)
+
+response = client.query(
+ os.environ['LOG_WORKSPACE_ID'],
+ "Perf | summarize count() by bin(TimeGenerated, 4h) | render barchart title='24H Perf events'",
+ server_timeout=10,
+ )
+
+for table in response.tables:
+ df = pd.DataFrame(table.rows, columns=[col.name for col in table.columns])
+ print(df)
+```
+
+### Get Metrics
+
+```Python
+import os
+from azure.monitor.query import MetricsClient
+from azure.identity import ClientSecretCredential
+
+
+credential = ClientSecretCredential(
+ client_id = os.environ['AZURE_CLIENT_ID'],
+ client_secret = os.environ['AZURE_CLIENT_SECRET'],
+ tenant_id = os.environ['AZURE_TENANT_ID']
+ )
+
+client = MetricsClient(credential)
+response = client.query(os.environ['METRICS_RESOURCE_URI'], metricnames=["Microsoft.CognitiveServices/accounts"])
+```
+
+## Troubleshooting
+
+- Enable `azure.monitor.query` logger to collect traces from the library.
+
+### General
+Monitor Query client library will raise exceptions defined in [Azure Core][azure_core_exceptions].
+
+### Logging
+This library uses the standard
+[logging][python_logging] library for logging.
+Basic information about HTTP sessions (URLs, headers, etc.) is logged at INFO
+level.
+
+### Optional Configuration
+
+Optional keyword arguments can be passed in at the client and per-operation level.
+The azure-core [reference documentation][azure_core_ref_docs]
+describes available configurations for retries, logging, transport protocols, and more.
+
+## Next steps
+
+### Additional documentation
+
+For more extensive documentation on Azure Monitor Query, see the [Monitor Query documentation][python-query-product-docs] on docs.microsoft.com.
+
+## Contributing
+This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit [cla.microsoft.com][cla].
+
+When you submit a pull request, a CLA-bot will automatically determine whether you need to provide a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions provided by the bot. You will only need to do this once across all repos using our CLA.
+
+This project has adopted the [Microsoft Open Source Code of Conduct][code_of_conduct]. For more information see the [Code of Conduct FAQ][coc_faq] or contact [opencode@microsoft.com][coc_contact] with any additional questions or comments.
+
+
+
+[azure_cli_link]: https://pypi.org/project/azure-cli/
+[python-query-src]: https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/monitor/azure-monitor-query/
+[python-query-pypi]: https://pypi.org/project/azure-monitor-query
+[python-query-product-docs]: https://docs.microsoft.com/azure/monitor/query/overview
+[python-query-ref-docs]: https://azuresdkdocs.blob.core.windows.net/$web/python/azure-monitor-query/latest/index.html
+[publisher-service-doc]: https://docs.microsoft.com/azure/monitor/query/concepts
+[python-query-samples]: https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/monitor/azure-monitor-query/samples
+[python-query-changelog]: https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/monitor/azure-monitor-query/CHANGELOG.md
+[pip]: https://pypi.org/project/pip/
+
+[azure_core_exceptions]: https://aka.ms/azsdk/python/core/docs#module-azure.core.exceptions
+[python_logging]: https://docs.python.org/3/library/logging.html
+[azure_core_ref_docs]: https://aka.ms/azsdk/python/core/docs
+[azure_subscription]: https://azure.microsoft.com/free/
+
+[cla]: https://cla.microsoft.com
+[code_of_conduct]: https://opensource.microsoft.com/codeofconduct/
+[coc_faq]: https://opensource.microsoft.com/codeofconduct/faq/
+[coc_contact]: mailto:opencode@microsoft.com
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 3a37076d8594..fd4ee12f604b 100644
--- a/sdk/monitor/azure-monitor-query/azure/monitor/query/_helpers.py
+++ b/sdk/monitor/azure-monitor-query/azure/monitor/query/_helpers.py
@@ -5,8 +5,13 @@
# license information.
# --------------------------------------------------------------------------
+from typing import Dict, Any, TYPE_CHECKING
+from azure.core.exceptions import HttpResponseError
from azure.core.pipeline.policies import BearerTokenCredentialPolicy
+if TYPE_CHECKING:
+ from azure.core.credentials import TokenCredential
+
def get_authentication_policy(
credential, # type: TokenCredential
):
@@ -20,3 +25,7 @@ def get_authentication_policy(
return BearerTokenCredentialPolicy(credential, "https://api.loganalytics.io/.default")
raise TypeError("Unsupported credential")
+
+def process_error(exception):
+ raise_error = HttpResponseError
+ raise raise_error(message=exception.message, response=exception.response)
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 be4987621936..cab13e7789a6 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
@@ -5,12 +5,15 @@
# license information.
# --------------------------------------------------------------------------
+from http.client import HTTPResponse
+from time import time
from typing import TYPE_CHECKING, Any, Union, Sequence, Dict
+from azure.core.exceptions import HttpResponseError
from ._generated._monitor_query_client import MonitorQueryClient
from ._generated.models import BatchRequest
-from ._helpers import get_authentication_policy
+from ._helpers import get_authentication_policy, process_error
from ._models import LogsQueryResults, LogsQueryRequest, LogsQueryBody
if TYPE_CHECKING:
@@ -23,13 +26,18 @@ class LogsClient(object):
:param credential: The credential to authenticate the client
:type credential: ~azure.core.credentials.TokenCredential
+ :keyword endpoint: The endpoint to connect to. Defaults to 'https://api.loganalytics.io/v1'.
+ :paramtype endpoint: str
"""
def __init__(self, credential, **kwargs):
# type: (TokenCredential, Any) -> None
+
+ self._endpoint = kwargs.pop('endpoint', 'https://api.loganalytics.io/v1')
self._client = MonitorQueryClient(
credential=credential,
authentication_policy=get_authentication_policy(credential),
+ base_url=self._endpoint,
**kwargs
)
self._query_op = self._client.query
@@ -55,6 +63,14 @@ def query(self, workspace_id, query, **kwargs):
:keyword bool include_render: In the query language, it is possible to specify different render options.
By default, the API does not return information regarding the type of visualization to show.
If your client requires this information, specify the preference
+ :keyword workspaces: A list of workspaces that are included in the query.
+ :paramtype workspaces: list[str]
+ :keyword qualified_names: A list of qualified workspace names that are included in the query.
+ :paramtype qualified_names: list[str]
+ :keyword workspace_ids: A list of workspace IDs that are included in the query.
+ :paramtype workspace_ids: list[str]
+ :keyword azure_resource_ids: A list of Azure resource IDs that are included in the query.
+ :paramtype azure_resource_ids: list[str]
:return: QueryResults, or the result of cls(response)
:rtype: ~azure.monitor.query.LogsQueryResults
:raises: ~azure.core.exceptions.HttpResponseError
@@ -62,26 +78,35 @@ def query(self, workspace_id, query, **kwargs):
timespan = kwargs.pop("timespan", None)
include_statistics = kwargs.pop("include_statistics", False)
include_render = kwargs.pop("include_render", False)
- timeout = kwargs.pop("server_timeout", None)
+ server_timeout = kwargs.pop("server_timeout", None)
prefer = ""
- if timeout:
- prefer += "wait=" + str(timeout)
+ if server_timeout:
+ prefer += "wait=" + str(server_timeout)
if include_statistics:
- prefer += " include-statistics=true"
+ if len(prefer) > 0:
+ prefer += ";"
+ prefer += "include-statistics=true"
if include_render:
- prefer += " include-render=true"
+ if len(prefer) > 0:
+ prefer += ";"
+ prefer += "include-render=true"
+
+ body = LogsQueryBody(
+ query=query,
+ timespan=timespan,
+ **kwargs
+ )
- if prefer:
- kwargs.setdefault("prefer", prefer)
+ try:
return self._query_op.execute(
- workspace_id,
- LogsQueryBody(query, workspace_ids=[workspace_id]),
+ workspace_id=workspace_id,
+ body=body,
+ prefer=prefer,
**kwargs
)
-
- kwargs.setdefault("timespan", timespan)
- return self._query_op.get(workspace_id, query, **kwargs)
+ except HttpResponseError as e:
+ process_error(e)
def batch_query(self, queries, **kwargs):
# type: (Union[Sequence[Dict], Sequence[LogsQueryRequest]], Any) -> LogsBatchResponse
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 c1257154fa91..438cff553d55 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
@@ -39,7 +39,7 @@ def __init__(self, credential, **kwargs):
self._namespace_op = self._client.metric_namespaces
self._definitions_op = self._client.metric_definitions
- def query(self, resource_uri, metricnames, **kwargs):
+ async def query(self, resource_uri, metricnames, **kwargs):
# type: (str, list, Any) -> MetricsResult
"""Lists the metric values for a resource.
@@ -82,9 +82,9 @@ def query(self, resource_uri, metricnames, **kwargs):
:raises: ~azure.core.exceptions.HttpResponseError
"""
kwargs.setdefault("metricnames", ",".join(metricnames))
- return self._metrics_op.list(resource_uri, connection_verify=False, **kwargs)
+ return await self._metrics_op.list(resource_uri, connection_verify=False, **kwargs)
- def list_metric_namespaces(self, resource_uri, **kwargs):
+ async def list_metric_namespaces(self, resource_uri, **kwargs):
# type: (str, Any) -> ItemPaged[MetricNamespace]
"""Lists the metric namespaces for the resource.
@@ -97,9 +97,9 @@ def list_metric_namespaces(self, resource_uri, **kwargs):
:rtype: ~azure.core.paging.ItemPaged[~azure.monitor.query.MetricNamespace]
:raises: ~azure.core.exceptions.HttpResponseError
"""
- return self._namespace_op.list(resource_uri, **kwargs)
+ return await self._namespace_op.list(resource_uri, **kwargs)
- def list_metric_definitions(self, resource_uri, **kwargs):
+ async def list_metric_definitions(self, resource_uri, **kwargs):
# type: (str, Any) -> ItemPaged[MetricDefinition]
"""Lists the metric definitions for the resource.
@@ -111,18 +111,15 @@ def list_metric_definitions(self, resource_uri, **kwargs):
:rtype: ~azure.core.paging.ItemPaged[~azure.monitor.query.MetricDefinition]
:raises: ~azure.core.exceptions.HttpResponseError
"""
- return self._namespace_op.list(resource_uri, **kwargs)
+ return await self._namespace_op.list(resource_uri, **kwargs)
- def close(self):
- # type: () -> None
- """Close the :class:`~azure.monitor.query.MetricsClient` session."""
- return self._client.close()
-
- def __enter__(self):
- # type: () -> MetricsClient
- self._client.__enter__() # pylint:disable=no-member
+ async def __aenter__(self) -> "MetricsClient":
+ await self._client.__aenter__()
return self
- def __exit__(self, *args):
- # type: (*Any) -> None
- self._client.__exit__(*args) # pylint:disable=no-member
+ async def __aexit__(self, *args: "Any") -> None:
+ await self._client.__aexit__(*args)
+
+ async def close(self) -> None:
+ """Close the :class:`~azure.monitor.query.aio.MetricsClient` session."""
+ await self._client.__aexit__()
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 690b1c6c9278..a0f657ff1b4a 100644
--- a/sdk/monitor/azure-monitor-query/azure/monitor/query/_models.py
+++ b/sdk/monitor/azure-monitor-query/azure/monitor/query/_models.py
@@ -6,7 +6,7 @@
# --------------------------------------------------------------------------
import uuid
-from typing import Any
+from typing import Any, Optional, Dict
from ._generated.models import (
QueryResults as InternalQueryResults,
@@ -152,24 +152,29 @@ class LogsQueryRequest(InternalLogQueryRequest):
Variables are only populated by the server, and will be ignored when sending a request.
+ :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 workspace: Workspace Id to be included in the query.
+ :type workspace: str
:keyword request_id: The error details.
:paramtype request_id: str
:keyword headers: Dictionary of :code:``.
:paramtype headers: dict[str, str]
- :keyword body: The Analytics query. Learn more about the `Analytics query syntax
- `_.
- :paramtype body: ~monitor_query_client.models.QueryBody
- :keyword workspace: Workspace Id to be included in the query.
- :paramtype workspace: str
"""
- def __init__(self, **kwargs):
- # type: (Any) -> None
+ def __init__(self, query, workspace, timespan=None, **kwargs):
+ # type: (str, str, Optional[str], Any) -> None
super(LogsQueryRequest, self).__init__(**kwargs)
- self.id = kwargs.get("id", uuid.uuid4())
- self.headers = kwargs.get("headers", {"Content-Type": "application/json"})
- self.body = kwargs.get("body", None)
- self.workspace = kwargs.get("workspace", None)
+ self.id = kwargs.get("request_id", uuid.uuid4())
+ self.headers = kwargs.get("headers", None)
+ self.body = {
+ "query": query, "timespan": timespan
+ }
+ self.workspace = workspace
class LogsQueryBody(InternalQueryBody):
@@ -194,11 +199,11 @@ class LogsQueryBody(InternalQueryBody):
:paramtype azure_resource_ids: list[str]
"""
- def __init__(self, query, **kwargs):
- # type: (str, Any) -> None
- super(LogsQueryBody, self).__init__(**kwargs)
+ def __init__(self, query, timespan=None, **kwargs):
+ # type: (str, Optional[str], Any) -> None
kwargs.setdefault("query", query)
- self.timespan = kwargs.get("timespan", None)
+ kwargs.setdefault("timespan", timespan)
+ super(LogsQueryBody, self).__init__(**kwargs)
self.workspaces = kwargs.get("workspaces", None)
self.qualified_names = kwargs.get("qualified_names", None)
self.workspace_ids = kwargs.get("workspace_ids", None)
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
new file mode 100644
index 000000000000..6c76710ba777
--- /dev/null
+++ b/sdk/monitor/azure-monitor-query/azure/monitor/query/aio/__init__.py
@@ -0,0 +1,13 @@
+# coding=utf-8
+# --------------------------------------------------------------------------
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License. See License.txt in the project root for license information.
+# --------------------------------------------------------------------------
+
+from ._log_query_client_async import LogsClient
+from ._metrics_query_client_async import MetricsClient
+
+__all__ = [
+ "LogsClient",
+ "MetricsClient"
+]
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
new file mode 100644
index 000000000000..efefef975c0d
--- /dev/null
+++ b/sdk/monitor/azure-monitor-query/azure/monitor/query/aio/_log_query_client_async.py
@@ -0,0 +1,137 @@
+#
+# -------------------------------------------------------------------------
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License. See License.txt in the project root for
+# license information.
+# --------------------------------------------------------------------------
+
+from typing import TYPE_CHECKING, Any, Union, Sequence, Dict
+from azure.core.exceptions import HttpResponseError
+
+from .._generated.aio._monitor_query_client import MonitorQueryClient
+
+from .._generated.models import BatchRequest
+from .._helpers import get_authentication_policy, process_error
+from .._models import LogsQueryResults, LogsQueryRequest, LogsQueryBody
+
+if TYPE_CHECKING:
+ from azure.core.credentials import TokenCredential
+ from .._models import LogsBatchResponse
+
+
+class LogsClient(object):
+ """LogsClient
+
+ :param credential: The credential to authenticate the client
+ :type credential: ~azure.core.credentials.TokenCredential
+ :keyword endpoint: The endpoint to connect to. Defaults to 'https://api.loganalytics.io/v1'.
+ :paramtype endpoint: str
+ """
+
+ def __init__(self, credential: TokenCredential, **kwargs: Any) -> None:
+ self._endpoint = kwargs.pop('endpoint', 'https://api.loganalytics.io/v1')
+ self._client = MonitorQueryClient(
+ credential=credential,
+ authentication_policy=get_authentication_policy(credential),
+ base_url=self._endpoint,
+ **kwargs
+ )
+ self._query_op = self._client.query
+
+ async def query(self, workspace_id: str, query: str, **kwargs: Any) -> LogsQueryResults:
+ """Execute an Analytics query.
+
+ Executes an Analytics query for data.
+
+ :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
+ :keyword ~datetime.timedelta timespan: Optional. The timespan over which to query data. This is an ISO8601 time
+ period value. This timespan is applied in addition to any that are specified in the query
+ expression.
+ :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.
+ :keyword bool include_render: In the query language, it is possible to specify different render options.
+ By default, the API does not return information regarding the type of visualization to show.
+ If your client requires this information, specify the preference
+ :keyword workspaces: A list of workspaces that are included in the query.
+ :paramtype workspaces: list[str]
+ :keyword qualified_names: A list of qualified workspace names that are included in the query.
+ :paramtype qualified_names: list[str]
+ :keyword workspace_ids: A list of workspace IDs that are included in the query.
+ :paramtype workspace_ids: list[str]
+ :keyword azure_resource_ids: A list of Azure resource IDs that are included in the query.
+ :paramtype azure_resource_ids: list[str]
+ :return: QueryResults, or the result of cls(response)
+ :rtype: ~azure.monitor.query.LogsQueryResults
+ :raises: ~azure.core.exceptions.HttpResponseError
+ """
+ timespan = kwargs.pop("timespan", None)
+ include_statistics = kwargs.pop("include_statistics", False)
+ include_render = kwargs.pop("include_render", False)
+ server_timeout = kwargs.pop("server_timeout", None)
+
+ prefer = ""
+ if server_timeout:
+ prefer += "wait=" + str(server_timeout)
+ if include_statistics:
+ if len(prefer) > 0:
+ prefer += ";"
+ prefer += "include-statistics=true"
+ if include_render:
+ if len(prefer) > 0:
+ prefer += ";"
+ prefer += "include-render=true"
+
+ body = LogsQueryBody(
+ query=query,
+ timespan=timespan,
+ **kwargs
+ )
+
+ try:
+ return await self._query_op.execute(
+ workspace_id=workspace_id,
+ body=body,
+ prefer=prefer,
+ **kwargs
+ )
+ except HttpResponseError as e:
+ process_error(e)
+
+ async def batch_query(
+ self,
+ queries: Union[Sequence[Dict], Sequence[LogsQueryRequest]],
+ **kwargs: Any
+ ) -> LogsBatchResponse:
+ """Execute an Analytics query.
+
+ Executes an Analytics query for data.
+
+ :param queries: The list of queries that should be processed
+ :type queries: list[dict] or list[~azure.monitor.query.LogsQueryRequest]
+ :return: BatchResponse, or the result of cls(response)
+ :rtype: ~azure.monitor.query.LogsBatchResponse
+ :raises: ~azure.core.exceptions.HttpResponseError
+ """
+ try:
+ queries = [LogsQueryRequest(**q) for q in queries]
+ except (KeyError, TypeError):
+ pass
+ batch = BatchRequest(requests=queries)
+ return await self._query_op.batch(batch, **kwargs)
+
+ async def __aenter__(self) -> "LogsClient":
+ await self._client.__aenter__()
+ return self
+
+ async def __aexit__(self, *args: "Any") -> None:
+ await self._client.__aexit__(*args)
+
+ async def close(self) -> None:
+ """Close the :class:`~azure.monitor.query.aio.LogsClient` session."""
+ await self._client.__aexit__()
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
new file mode 100644
index 000000000000..c1257154fa91
--- /dev/null
+++ b/sdk/monitor/azure-monitor-query/azure/monitor/query/aio/_metrics_query_client_async.py
@@ -0,0 +1,128 @@
+#
+# -------------------------------------------------------------------------
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License. See License.txt in the project root for
+# license information.
+# --------------------------------------------------------------------------
+
+# pylint: disable=anomalous-backslash-in-string
+
+from typing import TYPE_CHECKING, Any, Union
+
+from ._generated._monitor_query_client import (
+ MonitorQueryClient,
+)
+
+from ._helpers import get_authentication_policy
+
+if TYPE_CHECKING:
+ from azure.core.credentials import TokenCredential
+ from azure.core.paging import ItemPaged
+ from ._models import MetricsResult, MetricNamespace, MetricDefinition
+
+
+class MetricsClient(object):
+ """MetricsClient
+
+ :param credential: The credential to authenticate the client
+ :type credential: ~azure.core.credentials.TokenCredential
+ """
+
+ def __init__(self, credential, **kwargs):
+ # type: (TokenCredential, Any) -> None
+ self._client = MonitorQueryClient(
+ credential=credential,
+ authentication_policy=get_authentication_policy(credential),
+ **kwargs
+ )
+ self._metrics_op = self._client.metrics
+ self._namespace_op = self._client.metric_namespaces
+ self._definitions_op = self._client.metric_definitions
+
+ def query(self, resource_uri, metricnames, **kwargs):
+ # type: (str, list, Any) -> MetricsResult
+ """Lists the metric values for a resource.
+
+ :param resource_uri: The identifier of the resource.
+ :type resource_uri: str
+ :param metricnames: The names of the metrics to retrieve.
+ :type metricnames: list
+ :keyword timespan: The timespan of the query. It is a string with the following format
+ 'startDateTime_ISO/endDateTime_ISO'.
+ :paramtype timespan: str
+ :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.
+ :paramtype aggregation: str
+ :keyword top: The maximum number of records to retrieve.
+ Valid only if $filter is specified.
+ Defaults to 10.
+ :paramtype top: int
+ :keyword orderby: The aggregation to use for sorting results and the direction of the sort.
+ Only one order can be specified.
+ Examples: sum asc.
+ :paramtype orderby: str
+ :keyword filter: The **$filter** is used to reduce the set of metric data
+ returned.:code:`
`Example::code:`
`Metric contains metadata A, B and C.:code:`
`-
+ Return all time series of C where A = a1 and B = b1 or b2:code:`
`\ **$filter=A eq ‘a1’ and
+ B eq ‘b1’ or B eq ‘b2’ and C eq ‘*’**\ :code:`
`- Invalid variant::code:`
`\ **$filter=A
+ eq ‘a1’ and B eq ‘b1’ and C eq ‘*’ or B = ‘b2’**\ :code:`
`This is invalid because the
+ logical or operator cannot separate two different metadata names.:code:`
`- Return all time
+ series where A = a1, B = b1 and C = c1::code:`
`\ **$filter=A eq ‘a1’ and B eq ‘b1’ and C eq
+ ‘c1’**\ :code:`
`- Return all time series where A = a1:code:`
`\ **$filter=A eq ‘a1’ and
+ B eq ‘\ *’ and C eq ‘*\ ’**.
+ :paramtype filter: str
+ :keyword result_type: Reduces the set of data collected. The syntax allowed depends on the
+ operation. See the operation's description for details.
+ :paramtype result_type: str or ~monitor_query_client.models.ResultType
+ :keyword metricnamespace: Metric namespace to query metric definitions for.
+ :paramtype metricnamespace: str
+ :return: Response, or the result of cls(response)
+ :rtype: ~azure.monitor.query.MetricsResult
+ :raises: ~azure.core.exceptions.HttpResponseError
+ """
+ kwargs.setdefault("metricnames", ",".join(metricnames))
+ return self._metrics_op.list(resource_uri, connection_verify=False, **kwargs)
+
+ def list_metric_namespaces(self, resource_uri, **kwargs):
+ # type: (str, Any) -> ItemPaged[MetricNamespace]
+ """Lists the metric namespaces for the resource.
+
+ :param resource_uri: The identifier of the resource.
+ :type resource_uri: str
+ :keyword start_time: The ISO 8601 conform Date start time from which to query for metric
+ namespaces.
+ :paramtype start_time: str
+ :return: An iterator like instance of either MetricNamespaceCollection or the result of cls(response)
+ :rtype: ~azure.core.paging.ItemPaged[~azure.monitor.query.MetricNamespace]
+ :raises: ~azure.core.exceptions.HttpResponseError
+ """
+ return self._namespace_op.list(resource_uri, **kwargs)
+
+ def list_metric_definitions(self, resource_uri, **kwargs):
+ # type: (str, Any) -> ItemPaged[MetricDefinition]
+ """Lists the metric definitions for the resource.
+
+ :param resource_uri: The identifier of the resource.
+ :type resource_uri: str
+ :keyword metricnamespace: Metric namespace to query metric definitions for.
+ :paramtype metricnamespace: str
+ :return: An iterator like instance of either MetricDefinitionCollection or the result of cls(response)
+ :rtype: ~azure.core.paging.ItemPaged[~azure.monitor.query.MetricDefinition]
+ :raises: ~azure.core.exceptions.HttpResponseError
+ """
+ return self._namespace_op.list(resource_uri, **kwargs)
+
+ def close(self):
+ # type: () -> None
+ """Close the :class:`~azure.monitor.query.MetricsClient` session."""
+ return self._client.close()
+
+ def __enter__(self):
+ # type: () -> MetricsClient
+ self._client.__enter__() # pylint:disable=no-member
+ return self
+
+ def __exit__(self, *args):
+ # type: (*Any) -> None
+ self._client.__exit__(*args) # pylint:disable=no-member
diff --git a/sdk/monitor/azure-monitor-query/samples/sample_batch_query_build.py b/sdk/monitor/azure-monitor-query/samples/sample_batch_query_build.py
index 8fa6dc190848..4189aaaa96b8 100644
--- a/sdk/monitor/azure-monitor-query/samples/sample_batch_query_build.py
+++ b/sdk/monitor/azure-monitor-query/samples/sample_batch_query_build.py
@@ -2,7 +2,8 @@
# Licensed under the MIT License.
import os
-from azure.monitor.query import LogsClient, LogQueryRequest
+import pandas as pd
+from azure.monitor.query import LogsClient, LogsQueryRequest
from azure.identity import ClientSecretCredential
@@ -15,21 +16,29 @@
client = LogsClient(credential)
requests = [
- LogQueryRequest(
- body= {
- "query": "AzureActivity | summarize count()",
- "timespan": "PT1H"
- },
+ LogsQueryRequest(
+ query="AzureActivity | summarize count()",
+ timespan="PT1H",
workspace= os.environ['LOG_WORKSPACE_ID']
),
- LogQueryRequest(
- body= {
- "query": "AzureActivity | summarize count()",
- "timespan": "PT1H"
- },
+ 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']
),
]
response = client.batch_query(requests)
-print(response)
+for response in response.responses:
+ body = response.body
+ if not body.tables:
+ print("Something is wrong")
+ else:
+ for table in body.tables:
+ df = pd.DataFrame(table.rows, columns=[col.name for col in table.columns])
+ print(df)
\ No newline at end of file
diff --git a/sdk/monitor/azure-monitor-query/samples/sample_server_timeout.py b/sdk/monitor/azure-monitor-query/samples/sample_server_timeout.py
index bd087523e5a8..d2d4b26e9ee6 100644
--- a/sdk/monitor/azure-monitor-query/samples/sample_server_timeout.py
+++ b/sdk/monitor/azure-monitor-query/samples/sample_server_timeout.py
@@ -2,6 +2,7 @@
# Licensed under the MIT License.
import os
+import pandas as pd
from datetime import timedelta
from azure.monitor.query import LogsClient
from azure.identity import ClientSecretCredential
@@ -17,8 +18,12 @@
response = client.query(
os.environ['LOG_WORKSPACE_ID'],
- "AppRequests | take 1",
- timeout=100,
+ "Perf | summarize count() by bin(TimeGenerated, 4h) | render barchart title='24H Perf events'",
+ server_timeout=10,
+ include_statistics=True,
+ include_render=True
)
-print(response)
\ No newline at end of file
+for table in response.tables:
+ df = pd.DataFrame(table.rows, columns=[col.name for col in table.columns])
+ print(df)
\ No newline at end of file