Skip to content

Commit 883bdae

Browse files
author
Rakshith Bhyravabhotla
authored
Query - samples + README + docstrings (#20869)
* Samples fix * README * docstrings * mypy * lint * test fix * lint
1 parent 559840c commit 883bdae

28 files changed

+671
-427
lines changed

sdk/monitor/azure-monitor-query/README.md

Lines changed: 101 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -106,68 +106,83 @@ The `timespan` parameter specifies the time duration for which to query the data
106106
```python
107107
import os
108108
import pandas as pd
109-
from datetime import datetime
109+
from datetime import datetime, timezone
110110
from azure.monitor.query import LogsQueryClient
111111
from azure.identity import DefaultAzureCredential
112112

113113
credential = DefaultAzureCredential()
114114
client = LogsQueryClient(credential)
115115

116-
# Response time trend
117-
# request duration over the last 12 hours
118-
query = """AppRequests |
119-
summarize avgRequestDuration=avg(DurationMs) by bin(TimeGenerated, 10m), _ResourceId"""
120-
121-
start_time=datetime(2021, 7, 2)
122-
end_time=datetime.now()
123-
124-
# returns LogsQueryResult
125-
response = client.query_workspace(
126-
os.environ['LOG_WORKSPACE_ID'],
127-
query,
128-
timespan=(start_time, end_time)
129-
)
130-
131-
if not response.tables:
132-
print("No results for the query")
133-
134-
for table in response.tables:
135-
df = pd.DataFrame(table.rows, columns=[col.name for col in table.columns])
136-
print(df)
116+
query = """AppRequests | take 5"""
117+
118+
start_time=datetime(2021, 7, 2, tzinfo=timezone.utc)
119+
end_time=datetime(2021, 7, 4, tzinfo=timezone.utc)
120+
121+
try:
122+
response = client.query_workspace(
123+
workspace_id=os.environ['LOG_WORKSPACE_ID'],
124+
query=query,
125+
timespan=(start_time, end_time)
126+
)
127+
if response.status == LogsQueryStatus.PARTIAL:
128+
error = response.partial_error
129+
data = response.partial_data
130+
print(error.message)
131+
elif response.status == LogsQueryStatus.SUCCESS:
132+
data = response.tables
133+
for table in data:
134+
df = pd.DataFrame(data=table.rows, columns=table.columns)
135+
print(df)
136+
except HttpResponseError as err:
137+
print("something fatal happened")
138+
print (err)
137139
```
138140

139141
#### Handle logs query response
140142

141-
The `query` API returns the `LogsQueryResult` while the `batch_query` API returns list of `LogsQueryResult`. Here's a hierarchy of the response:
143+
The `query` API returns a union of `LogsQueryResult` and `LogsQueryPartialResult` while the `batch_query` API returns list of `LogsQueryResult`, `LogsQueryPartialResult` and `LogsQueryError` objects. Here's a hierarchy of the response:
142144

143145
```
144146
LogsQueryResult
145147
|---statistics
146148
|---visualization
147-
|---error
148149
|---tables (list of `LogsTable` objects)
149150
|---name
150151
|---rows
151-
|---columns (list of `LogsTableColumn` objects)
152-
|---name
153-
|---type
152+
|---columns
153+
|---column_types
154+
155+
156+
LogsQueryPartialResult
157+
|---statistics
158+
|---visualization
159+
|---partial_error (a `LogsQueryError` object)
160+
|---partial_data (list of `LogsTable` objects)
161+
|---name
162+
|---rows
163+
|---columns
164+
|---column_types
154165
```
155166

167+
The `LogsQueryResult` directly iterates over the table as a convinience.
156168
For example, to handle a logs query response with tables and display it using pandas:
157169

158170
```python
159-
table = response.tables[0]
160-
df = pd.DataFrame(table.rows, columns=[col.name for col in table.columns])
171+
response = client.query(...)
172+
for table in response:
173+
df = pd.DataFrame(table.rows, columns=[col.name for col in table.columns])
161174
```
162175

163-
A full sample can be found [here](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/monitor/azure-monitor-query/samples/sample_log_query_client.py).
176+
A full sample can be found [here](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/monitor/azure-monitor-query/samples/sample_logs_single_query.py).
164177

165178
In a similar fashion, to handle a batch logs query response:
166179

167180
```python
168181
for result in response:
169-
table = result.tables[0]
170-
df = pd.DataFrame(table.rows, columns=[col.name for col in table.columns])
182+
if result.status == LogsQueryStatus.SUCCESS:
183+
for table in result:
184+
df = pd.DataFrame(table.rows, columns=table.columns)
185+
print(df)
171186
```
172187

173188
A full sample can be found [here](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/monitor/azure-monitor-query/samples/sample_batch_query.py).
@@ -178,41 +193,51 @@ The following example demonstrates sending multiple queries at the same time usi
178193

179194
```python
180195
import os
181-
from datetime import timedelta
196+
from datetime import timedelta, datetime, timezone
182197
import pandas as pd
183-
from azure.monitor.query import LogsQueryClient, LogsQueryRequest
198+
from azure.monitor.query import LogsQueryClient, LogsBatchQuery, LogsQueryStatus
184199
from azure.identity import DefaultAzureCredential
185200

186201
credential = DefaultAzureCredential()
187202
client = LogsQueryClient(credential)
188-
189203
requests = [
190204
LogsBatchQuery(
191205
query="AzureActivity | summarize count()",
192206
timespan=timedelta(hours=1),
193-
workspace_id=os.environ['LOG_WORKSPACE_ID']
207+
workspace_id= os.environ['LOG_WORKSPACE_ID']
194208
),
195209
LogsBatchQuery(
196-
query= """AppRequests | take 10 |
197-
summarize avgRequestDuration=avg(DurationMs) by bin(TimeGenerated, 10m), _ResourceId""",
198-
timespan=(datetime(2021, 6, 2), timedelta(hours=1)),
199-
workspace_id=os.environ['LOG_WORKSPACE_ID']
210+
query= """bad query""",
211+
timespan=timedelta(days=1),
212+
workspace_id= os.environ['LOG_WORKSPACE_ID']
200213
),
201214
LogsBatchQuery(
202-
query= "AppRequests | take 2",
203-
workspace_id=os.environ['LOG_WORKSPACE_ID']
215+
query= """let Weight = 92233720368547758;
216+
range x from 1 to 3 step 1
217+
| summarize percentilesw(x, Weight * 100, 50)""",
218+
workspace_id= os.environ['LOG_WORKSPACE_ID'],
219+
timespan=(datetime(2021, 6, 2, tzinfo=timezone.utc), datetime(2021, 6, 5, tzinfo=timezone.utc)), # (start, end)
220+
include_statistics=True
204221
),
205222
]
206-
response = client.query_batch(requests)
207-
208-
for rsp in response:
209-
body = rsp.body
210-
if not body.tables:
211-
print("Something is wrong")
212-
else:
213-
for table in body.tables:
214-
df = pd.DataFrame(table.rows, columns=[col.name for col in table.columns])
223+
results = client.query_batch(requests)
224+
225+
for res in results:
226+
if res.status == LogsQueryStatus.FAILURE:
227+
# this will be a LogsQueryError
228+
print(res.message)
229+
elif res.status == LogsQueryStatus.PARTIAL:
230+
## this will be a LogsQueryPartialResult
231+
print(res.partial_error.message)
232+
for table in res.partial_data:
233+
df = pd.DataFrame(table.rows, columns=table.columns)
215234
print(df)
235+
elif res.status == LogsQueryStatus.SUCCESS:
236+
## this will be a LogsQueryResult
237+
table = res.tables[0]
238+
df = pd.DataFrame(table.rows, columns=table.columns)
239+
print(df)
240+
216241
```
217242

218243
### Advanced logs query scenarios
@@ -233,6 +258,7 @@ client = LogsQueryClient(credential)
233258
response = client.query_workspace(
234259
os.environ['LOG_WORKSPACE_ID'],
235260
"range x from 1 to 10000000000 step 1 | count",
261+
timespan=None,
236262
server_timeout=1,
237263
)
238264
```
@@ -271,9 +297,11 @@ To find the resource URI:
271297
2. From the **Overview** blade, select the **JSON View** link.
272298
3. In the resulting JSON, copy the value of the `id` property.
273299

300+
**NOTE**: The metrics are returned in the order of the metric_names sent.
301+
274302
```python
275303
import os
276-
from datetime import timedelta
304+
from datetime import timedelta, datetime
277305
from azure.monitor.query import MetricsQueryClient
278306
from azure.identity import DefaultAzureCredential
279307

@@ -367,6 +395,27 @@ Optional keyword arguments can be passed in at the client and per-operation leve
367395

368396
To learn more about Azure Monitor, see the [Azure Monitor service documentation][azure_monitor_overview].
369397

398+
### Samples
399+
These code samples show common champion scenario operations with the Azure Monitor Query client library.
400+
401+
* Send a single query with LogsQueryClient and handle the response as a table: [sample_logs_single_query.py](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/monitor/azure-monitor-query/samples/sample_logs_single_query.py) ([async_sample](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/monitor/azure-monitor-query/samples/async_samples/sample_log_query_async.py))
402+
403+
* Send a single query with LogsQueryClient and handle the response in key value form: [sample_logs_query_key_value_form.py](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/monitor/azure-monitor-query/samples/sample_logs_query_key_value_form.py)
404+
405+
* Send a single query with LogsQueryClient without pandas: [sample_single_log_query_without_pandas.py.py](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/monitor/azure-monitor-query/samples/sample_single_log_query_without_pandas.py)
406+
407+
* Send a single query with LogsQueryClient across multiple workspaces: [sample_logs_query_multiple_workspaces.py](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/monitor/azure-monitor-query/samples/sample_log_query_multiple_workspaces.py)
408+
409+
* Send multiple queries with LogsQueryClient: [sample_batch_query.py](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/monitor/azure-monitor-query/samples/sample_batch_query.py)
410+
411+
* Send a single query with LogsQueryClient using server timeout: [sample_server_timeout.py](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/monitor/azure-monitor-query/samples/sample_server_timeout.py)
412+
413+
* Send a query using MetricsQueryClient: [sample_metrics_query.py](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))
414+
415+
* Get a list of metric namespaces: [sample_metric_namespaces.py](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))
416+
417+
* Get a list of metric definitions: [sample_metric_definitions.py](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))
418+
370419
## Contributing
371420

372421
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].

sdk/monitor/azure-monitor-query/azure/monitor/query/_exceptions.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@
1010
class LogsQueryError(object):
1111
"""The code and message for an error.
1212
13-
All required parameters must be populated in order to send to Azure.
14-
1513
:ivar code: A machine readable error code.
1614
:vartype code: str
1715
:ivar message: A human readable error message.

sdk/monitor/azure-monitor-query/azure/monitor/query/_helpers.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
# license information.
66
# --------------------------------------------------------------------------
77
from datetime import datetime, timedelta
8-
from typing import TYPE_CHECKING
8+
from typing import TYPE_CHECKING, List, Dict, Any
99
from msrest import Serializer, Deserializer
1010
from azure.core.exceptions import HttpResponseError
1111
from azure.core.pipeline.policies import BearerTokenCredentialPolicy
@@ -47,6 +47,7 @@ def get_metrics_authentication_policy(
4747

4848

4949
def order_results(request_order, mapping, **kwargs):
50+
# type: (List, Dict, Any) -> List
5051
ordered = [mapping[id] for id in request_order]
5152
results = []
5253
for item in ordered:

sdk/monitor/azure-monitor-query/azure/monitor/query/_logs_query_client.py

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,17 @@
2828

2929

3030
class LogsQueryClient(object):
31-
"""LogsQueryClient
31+
"""LogsQueryClient. Use this client to collect and organize log and performance data from
32+
monitored resources. Data from different sources such as platform logs from Azure services,
33+
log and performance data from virtual machines agents, and usage and performance data from
34+
apps can be consolidated into a single Azure Log Analytics workspace.
35+
36+
The various data types can be analyzed together using the
37+
[Kusto Query Language](https://docs.microsoft.com/azure/data-explorer/kusto/query/)
3238
3339
.. admonition:: Example:
3440
35-
.. literalinclude:: ../samples/sample_log_query_client.py
41+
.. literalinclude:: ../samples/sample_single_logs_query.py
3642
:start-after: [START client_auth_with_token_cred]
3743
:end-before: [END client_auth_with_token_cred]
3844
:language: python
@@ -83,13 +89,13 @@ def query_workspace(self, workspace_id, query, **kwargs):
8389
:keyword additional_workspaces: A list of workspaces that are included in the query.
8490
These can be qualified workspace names, workspace Ids, or Azure resource Ids.
8591
:paramtype additional_workspaces: list[str]
86-
:return: LogsQueryResult, or the result of cls(response)
92+
:return: LogsQueryResult if there is a success or LogsQueryPartialResult when there is a partial success.
8793
:rtype: Union[~azure.monitor.query.LogsQueryResult, ~azure.monitor.query.LogsQueryPartialResult]
8894
:raises: ~azure.core.exceptions.HttpResponseError
8995
9096
.. admonition:: Example:
9197
92-
.. literalinclude:: ../samples/sample_log_query_client.py
98+
.. literalinclude:: ../samples/sample_single_logs_query.py
9399
:start-after: [START send_logs_query]
94100
:end-before: [END send_logs_query]
95101
:language: python
@@ -131,7 +137,7 @@ def query_workspace(self, workspace_id, query, **kwargs):
131137
response = LogsQueryPartialResult._from_generated( # pylint: disable=protected-access
132138
generated_response, LogsQueryError
133139
)
134-
return response
140+
return cast(Union[LogsQueryResult, LogsQueryPartialResult], response)
135141

136142
@distributed_trace
137143
def query_batch(
@@ -140,14 +146,17 @@ def query_batch(
140146
**kwargs # type: Any
141147
):
142148
# type: (...) -> List[Union[LogsQueryResult, LogsQueryPartialResult, LogsQueryError]]
143-
"""Execute a list of analytics queries. Each request can be either a LogQueryRequest
149+
"""Execute a list of analytics queries. Each request can be either a LogsBatchQuery
144150
object or an equivalent serialized model.
145151
146-
The response is returned in the same order as that of the requests sent.
152+
**NOTE**: The response is returned in the same order as that of the requests sent.
147153
148154
:param queries: The list of Kusto queries to execute.
149155
:type queries: list[dict] or list[~azure.monitor.query.LogsBatchQuery]
150-
:return: List of LogsQueryResult, or the result of cls(response)
156+
:return: List of LogsQueryResult, LogsQueryPartialResult and LogsQueryError.
157+
For a given query, a LogsQueryResult is returned if the response is a success, LogsQueryPartialResult
158+
is returned when there is a partial success and a LogsQueryError is returned when there is a failure.
159+
The status of each response can be checked using `LogsQueryStatus` enum.
151160
:rtype: list[Union[~azure.monitor.query.LogsQueryResult, ~azure.monitor.query.LogsQueryPartialResult,
152161
~azure.monitor.query.LogsQueryError]
153162
:raises: ~azure.core.exceptions.HttpResponseError
@@ -162,7 +171,7 @@ def query_batch(
162171
:caption: Get a response for multiple Log Queries.
163172
"""
164173
try:
165-
queries = [LogsBatchQuery(**q) for q in queries]
174+
queries = [LogsBatchQuery(**cast(Dict, q)) for q in queries]
166175
except (KeyError, TypeError):
167176
pass
168177
queries = [
@@ -174,7 +183,7 @@ def query_batch(
174183
request_order = [req["id"] for req in queries]
175184
batch = BatchRequest(requests=queries)
176185
generated = self._query_op.batch(batch, **kwargs)
177-
mapping = {item.id: item for item in generated.responses}
186+
mapping = {item.id: item for item in generated.responses} # type: ignore
178187
return order_results(
179188
request_order,
180189
mapping,

0 commit comments

Comments
 (0)