Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a new row type in query #20685

Merged
merged 6 commits into from
Sep 14, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions sdk/monitor/azure-monitor-query/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@
- Added `QueryPartialErrorException` and `LogsQueryError` to handle errors.
- Added `partial_error` and `is_error` attributes to `LogsQueryResult`.
- Added an option `allow_partial_errors` that defaults to False, which can be set to not throw if there are any partial errors.
- Added a new `LogsTableRow` type that represents a single row in a table.

### Breaking Changes

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

### Bugs Fixed

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
MetricAggregationType,
LogsQueryResult,
LogsTable,
LogsTableRow,
MetricsResult,
LogsBatchQuery,
MetricNamespace,
Expand All @@ -38,6 +39,7 @@
"LogsQueryError",
"QueryPartialErrorException",
"LogsTable",
"LogsTableRow",
"LogsBatchQuery",
"MetricsQueryClient",
"MetricNamespace",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,8 +148,8 @@ def list_metric_namespaces(self, resource_uri, **kwargs):
**kwargs)

@distributed_trace
def list_metric_definitions(self, resource_uri, metric_namespace=None, **kwargs):
# type: (str, str, Any) -> ItemPaged[MetricDefinition]
def list_metric_definitions(self, resource_uri, **kwargs):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Breaking change. Do you want to add it into changelog?

# type: (str, Any) -> ItemPaged[MetricDefinition]
"""Lists the metric definitions for the resource.

:param resource_uri: The identifier of the resource.
Expand Down
45 changes: 43 additions & 2 deletions sdk/monitor/azure-monitor-query/azure/monitor/query/_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,22 @@ class LogsTable(object):
:ivar column_types: The types of columns in this table.
:vartype columns: list[object]
:ivar rows: Required. The resulting rows from this query.
:vartype rows: list[list[object]]
:vartype rows: list[~azure.monitor.query.LogsTableRow]
"""
def __init__(self, **kwargs):
# type: (Any) -> None
self.name = kwargs.pop('name', None) # type: str
self.columns = kwargs.pop('columns', None) # type: Optional[str]
self.columns_types = kwargs.pop('column_types', None) # type: Optional[Any]
_rows = kwargs.pop('rows', None)
self.rows = [process_row(self.columns_types, row) for row in _rows]
self.rows = [
LogsTableRow(
row=row,
row_index=ind,
col_types=self.columns_types,
columns=self.columns
) for ind, row in enumerate(_rows)
]

@classmethod
def _from_generated(cls, generated):
Expand All @@ -48,6 +55,40 @@ def _from_generated(cls, generated):
)


class LogsTableRow(object):
"""Represents a single row in logs table.

ivar list row: The collection of values in the row.
ivar int row_index: The index of the row in the table
"""
def __init__(self, **kwargs):
# type: (Any) -> None
_col_types = kwargs['col_types']
row = kwargs['row']
self.row = process_row(_col_types, row)
self.row_index = kwargs['row_index']
_columns = kwargs['columns']
self._row_dict = {
_columns[i]: self.row[i] for i in range(len(self.row))
}

def __iter__(self):
"""This will iterate over the row directly.
"""
return iter(self.row)

def __getitem__(self, column):
"""This type must be subscriptable directly to row.
Must be gettableby both column name and row index
Example: row[0] -> returns the first element of row and
row[column_name] -> returns the row element against the given column name.
"""
try:
return self._row_dict[column]
except KeyError:
return self.row[column]


class MetricsResult(object):
"""The response to a metrics query.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,14 @@
# Response time trend
# request duration over the last 12 hours.
# [START send_logs_query]
query = """AppRwequests | take 5"""
query = """AppRequests | take 5"""

# returns LogsQueryResult
try:
response = client.query(os.environ['LOG_WORKSPACE_ID'], query, timespan=timedelta(days=1))
for table in response:
print(table)
df = pd.DataFrame(data=table.rows, columns=table.columns)
print(df)
except QueryPartialErrorException as err:
print("this is a partial error")
print(err.details)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import os
from azure.identity.aio import ClientSecretCredential
from azure.core.exceptions import HttpResponseError
from azure.monitor.query import LogsBatchQuery, LogsQueryError, LogsTable, LogsQueryResult
from azure.monitor.query import LogsBatchQuery, LogsQueryError, LogsTable, LogsQueryResult, LogsTableRow
from azure.monitor.query.aio import LogsQueryClient

def _credential():
Expand Down Expand Up @@ -202,3 +202,23 @@ async def test_logs_query_result_iterate_over_tables():
assert response.visualization is not None
assert len(response.tables) == 2
assert response.__class__ == LogsQueryResult

@pytest.mark.live_test_only
@pytest.mark.asyncio
async def test_logs_query_result_row_type():
client = LogsQueryClient(_credential())

query = "AppRequests | take 5"

response = await client.query(
os.environ['LOG_WORKSPACE_ID'],
query,
timespan=None,
)

## should iterate over tables
for table in response:
assert table.__class__ == LogsTable

for row in table.rows:
assert row.__class__ == LogsTableRow
21 changes: 20 additions & 1 deletion sdk/monitor/azure-monitor-query/tests/test_logs_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import os
from azure.identity import ClientSecretCredential
from azure.core.exceptions import HttpResponseError
from azure.monitor.query import LogsQueryClient, LogsBatchQuery, LogsQueryError, LogsTable, LogsQueryResult
from azure.monitor.query import LogsQueryClient, LogsBatchQuery, LogsQueryError, LogsTable, LogsQueryResult, LogsTableRow

def _credential():
credential = ClientSecretCredential(
Expand Down Expand Up @@ -245,3 +245,22 @@ def test_logs_query_result_iterate_over_tables():
assert response.visualization is not None
assert len(response.tables) == 2
assert response.__class__ == LogsQueryResult

@pytest.mark.live_test_only
def test_logs_query_result_row_type():
client = LogsQueryClient(_credential())

query = "AppRequests | take 5"

response = client.query(
os.environ['LOG_WORKSPACE_ID'],
query,
timespan=None,
)

## should iterate over tables
for table in response:
assert table.__class__ == LogsTable

for row in table.rows:
assert row.__class__ == LogsTableRow