Skip to content

Commit 279e7eb

Browse files
author
Rakshith Bhyravabhotla
authored
Add a new row type in query (Azure#20685)
* Add row type * Add a new row type * add test * lint * Apply suggestions from code review * changes
1 parent 5016742 commit 279e7eb

File tree

7 files changed

+93
-8
lines changed

7 files changed

+93
-8
lines changed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,12 @@
77
- Added `QueryPartialErrorException` and `LogsQueryError` to handle errors.
88
- Added `partial_error` and `is_error` attributes to `LogsQueryResult`.
99
- Added an option `allow_partial_errors` that defaults to False, which can be set to not throw if there are any partial errors.
10+
- Added a new `LogsTableRow` type that represents a single row in a table.
1011

1112
### Breaking Changes
1213

1314
- `LogsQueryResult` now iterates over the tables directly as a convinience.
15+
- `metric_namespace` is renamed to `namespace` and is a keyword-only argument in `list_metric_definitions` API.
1416

1517
### Bugs Fixed
1618

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
MetricAggregationType,
1717
LogsQueryResult,
1818
LogsTable,
19+
LogsTableRow,
1920
MetricsResult,
2021
LogsBatchQuery,
2122
MetricNamespace,
@@ -38,6 +39,7 @@
3839
"LogsQueryError",
3940
"QueryPartialErrorException",
4041
"LogsTable",
42+
"LogsTableRow",
4143
"LogsBatchQuery",
4244
"MetricsQueryClient",
4345
"MetricNamespace",

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,8 +148,8 @@ def list_metric_namespaces(self, resource_uri, **kwargs):
148148
**kwargs)
149149

150150
@distributed_trace
151-
def list_metric_definitions(self, resource_uri, metric_namespace=None, **kwargs):
152-
# type: (str, str, Any) -> ItemPaged[MetricDefinition]
151+
def list_metric_definitions(self, resource_uri, **kwargs):
152+
# type: (str, Any) -> ItemPaged[MetricDefinition]
153153
"""Lists the metric definitions for the resource.
154154
155155
:param resource_uri: The identifier of the resource.

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

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,22 @@ class LogsTable(object):
2828
:ivar column_types: The types of columns in this table.
2929
:vartype columns: list[object]
3030
:ivar rows: Required. The resulting rows from this query.
31-
:vartype rows: list[list[object]]
31+
:vartype rows: list[~azure.monitor.query.LogsTableRow]
3232
"""
3333
def __init__(self, **kwargs):
3434
# type: (Any) -> None
3535
self.name = kwargs.pop('name', None) # type: str
3636
self.columns = kwargs.pop('columns', None) # type: Optional[str]
3737
self.columns_types = kwargs.pop('column_types', None) # type: Optional[Any]
3838
_rows = kwargs.pop('rows', None)
39-
self.rows = [process_row(self.columns_types, row) for row in _rows]
39+
self.rows = [
40+
LogsTableRow(
41+
row=row,
42+
row_index=ind,
43+
col_types=self.columns_types,
44+
columns=self.columns
45+
) for ind, row in enumerate(_rows)
46+
]
4047

4148
@classmethod
4249
def _from_generated(cls, generated):
@@ -48,6 +55,40 @@ def _from_generated(cls, generated):
4855
)
4956

5057

58+
class LogsTableRow(object):
59+
"""Represents a single row in logs table.
60+
61+
ivar list row: The collection of values in the row.
62+
ivar int row_index: The index of the row in the table
63+
"""
64+
def __init__(self, **kwargs):
65+
# type: (Any) -> None
66+
_col_types = kwargs['col_types']
67+
row = kwargs['row']
68+
self.row = process_row(_col_types, row)
69+
self.row_index = kwargs['row_index']
70+
_columns = kwargs['columns']
71+
self._row_dict = {
72+
_columns[i]: self.row[i] for i in range(len(self.row))
73+
}
74+
75+
def __iter__(self):
76+
"""This will iterate over the row directly.
77+
"""
78+
return iter(self.row)
79+
80+
def __getitem__(self, column):
81+
"""This type must be subscriptable directly to row.
82+
Must be gettableby both column name and row index
83+
Example: row[0] -> returns the first element of row and
84+
row[column_name] -> returns the row element against the given column name.
85+
"""
86+
try:
87+
return self._row_dict[column]
88+
except KeyError:
89+
return self.row[column]
90+
91+
5192
class MetricsResult(object):
5293
"""The response to a metrics query.
5394

sdk/monitor/azure-monitor-query/samples/sample_log_query_client.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,14 @@
1717
# Response time trend
1818
# request duration over the last 12 hours.
1919
# [START send_logs_query]
20-
query = """AppRwequests | take 5"""
20+
query = """AppRequests | take 5"""
2121

2222
# returns LogsQueryResult
2323
try:
2424
response = client.query(os.environ['LOG_WORKSPACE_ID'], query, timespan=timedelta(days=1))
2525
for table in response:
26-
print(table)
26+
df = pd.DataFrame(data=table.rows, columns=table.columns)
27+
print(df)
2728
except QueryPartialErrorException as err:
2829
print("this is a partial error")
2930
print(err.details)

sdk/monitor/azure-monitor-query/tests/async/test_logs_client_async.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import os
55
from azure.identity.aio import ClientSecretCredential
66
from azure.core.exceptions import HttpResponseError
7-
from azure.monitor.query import LogsBatchQuery, LogsQueryError, LogsTable, LogsQueryResult
7+
from azure.monitor.query import LogsBatchQuery, LogsQueryError, LogsTable, LogsQueryResult, LogsTableRow
88
from azure.monitor.query.aio import LogsQueryClient
99

1010
def _credential():
@@ -202,3 +202,23 @@ async def test_logs_query_result_iterate_over_tables():
202202
assert response.visualization is not None
203203
assert len(response.tables) == 2
204204
assert response.__class__ == LogsQueryResult
205+
206+
@pytest.mark.live_test_only
207+
@pytest.mark.asyncio
208+
async def test_logs_query_result_row_type():
209+
client = LogsQueryClient(_credential())
210+
211+
query = "AppRequests | take 5"
212+
213+
response = await client.query(
214+
os.environ['LOG_WORKSPACE_ID'],
215+
query,
216+
timespan=None,
217+
)
218+
219+
## should iterate over tables
220+
for table in response:
221+
assert table.__class__ == LogsTable
222+
223+
for row in table.rows:
224+
assert row.__class__ == LogsTableRow

sdk/monitor/azure-monitor-query/tests/test_logs_client.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import os
44
from azure.identity import ClientSecretCredential
55
from azure.core.exceptions import HttpResponseError
6-
from azure.monitor.query import LogsQueryClient, LogsBatchQuery, LogsQueryError, LogsTable, LogsQueryResult
6+
from azure.monitor.query import LogsQueryClient, LogsBatchQuery, LogsQueryError, LogsTable, LogsQueryResult, LogsTableRow
77

88
def _credential():
99
credential = ClientSecretCredential(
@@ -245,3 +245,22 @@ def test_logs_query_result_iterate_over_tables():
245245
assert response.visualization is not None
246246
assert len(response.tables) == 2
247247
assert response.__class__ == LogsQueryResult
248+
249+
@pytest.mark.live_test_only
250+
def test_logs_query_result_row_type():
251+
client = LogsQueryClient(_credential())
252+
253+
query = "AppRequests | take 5"
254+
255+
response = client.query(
256+
os.environ['LOG_WORKSPACE_ID'],
257+
query,
258+
timespan=None,
259+
)
260+
261+
## should iterate over tables
262+
for table in response:
263+
assert table.__class__ == LogsTable
264+
265+
for row in table.rows:
266+
assert row.__class__ == LogsTableRow

0 commit comments

Comments
 (0)