From 54c66506cc9b4b11cb7fef0886c73debfe29d054 Mon Sep 17 00:00:00 2001 From: Rakshith Bhyravabhotla Date: Thu, 19 Aug 2021 12:20:27 -0700 Subject: [PATCH 1/6] Handle value types for results --- sdk/monitor/azure-monitor-query/CHANGELOG.md | 1 + .../azure/monitor/query/_helpers.py | 17 +++++++- .../azure/monitor/query/_models.py | 4 +- .../tests/test_logs_response.py | 43 +++++++++++++++++++ 4 files changed, 62 insertions(+), 3 deletions(-) create mode 100644 sdk/monitor/azure-monitor-query/tests/test_logs_response.py diff --git a/sdk/monitor/azure-monitor-query/CHANGELOG.md b/sdk/monitor/azure-monitor-query/CHANGELOG.md index 11fa24cf682f..6589176e48db 100644 --- a/sdk/monitor/azure-monitor-query/CHANGELOG.md +++ b/sdk/monitor/azure-monitor-query/CHANGELOG.md @@ -16,6 +16,7 @@ - `metric_namespace_name` is renamed to `fully_qualified_namespace` - `is_dimension_required` is renamed to `dimension_required` - `time_grain` is renamed to `granularity` +- `LogsQueryResult` now returns `datetime` objects for a time values. ### Bugs Fixed 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 d1333a4f362c..f4c6ec6a785d 100644 --- a/sdk/monitor/azure-monitor-query/azure/monitor/query/_helpers.py +++ b/sdk/monitor/azure-monitor-query/azure/monitor/query/_helpers.py @@ -6,7 +6,7 @@ # -------------------------------------------------------------------------- from datetime import datetime, timedelta from typing import TYPE_CHECKING -from msrest import Serializer +from msrest import Serializer, Deserializer from azure.core.exceptions import HttpResponseError from azure.core.pipeline.policies import BearerTokenCredentialPolicy @@ -81,3 +81,18 @@ def construct_iso8601(timespan=None): else: iso_str = duration return iso_str + +def native_col_type(col_type, value): + if col_type == 'datetime': + return Deserializer.deserialize_iso(value) + elif col_type in ('timespan', 'guid', 'string'): + return str(value) + elif col_type == 'bool': + return bool(value) + return value + +def process_row(col_types, row): + new_row = [] + for ind in range(len(row)): + new_row.append(native_col_type(col_types[ind].type, row[ind])) + return new_row 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 400f9f19f04a..fcc22a6ba687 100644 --- a/sdk/monitor/azure-monitor-query/azure/monitor/query/_models.py +++ b/sdk/monitor/azure-monitor-query/azure/monitor/query/_models.py @@ -9,7 +9,7 @@ import uuid from typing import Any, Optional, List -from ._helpers import construct_iso8601 +from ._helpers import construct_iso8601, process_row from ._generated.models import ( Column as InternalColumn, BatchQueryRequest as InternalLogQueryRequest, @@ -32,7 +32,7 @@ def __init__(self, name, columns, rows): # type: (str, List[LogsQueryResultColumn], List[List[str]]) -> None self.name = name self.columns = columns - self.rows = rows + self.rows = [process_row(self.columns, row) for row in rows] @classmethod def _from_generated(cls, generated): diff --git a/sdk/monitor/azure-monitor-query/tests/test_logs_response.py b/sdk/monitor/azure-monitor-query/tests/test_logs_response.py new file mode 100644 index 000000000000..44c81f824b45 --- /dev/null +++ b/sdk/monitor/azure-monitor-query/tests/test_logs_response.py @@ -0,0 +1,43 @@ +from datetime import datetime, time, timedelta +import pytest +import json +import os +from msrest.serialization import UTC + +from azure.identity import ClientSecretCredential +from azure.core.exceptions import HttpResponseError +from azure.monitor.query import LogsQueryClient, LogsBatchQuery + +from azure.monitor.query._helpers import construct_iso8601 + +def _credential(): + credential = ClientSecretCredential( + client_id = os.environ['AZURE_CLIENT_ID'], + client_secret = os.environ['AZURE_CLIENT_SECRET'], + tenant_id = os.environ['AZURE_TENANT_ID'] + ) + return credential + +@pytest.mark.live_test_only +def test_query_response_datetime(): + credential = _credential() + client = LogsQueryClient(credential) + query = """AppRequests | + where TimeGenerated > ago(12h) | + summarize avgRequestDuration=avg(DurationMs) by bin(TimeGenerated, 10m), _ResourceId""" + + # returns LogsQueryResult + result = client.query(os.environ['LOG_WORKSPACE_ID'], query, timespan=None) + assert result.tables[0].rows[0][0].__class__ == datetime + +@pytest.mark.live_test_only +def test_query_response_float(): + credential = _credential() + client = LogsQueryClient(credential) + query = """AppRequests | + where TimeGenerated > ago(12h) | + summarize avgRequestDuration=avg(DurationMs) by bin(TimeGenerated, 10m), _ResourceId""" + + # returns LogsQueryResult + result = client.query(os.environ['LOG_WORKSPACE_ID'], query, timespan=None) + assert result.tables[0].rows[0][2].__class__ == float From 4a344f14143fc32d23228073f84c4a638a3bf439 Mon Sep 17 00:00:00 2001 From: Rakshith Bhyravabhotla Date: Thu, 19 Aug 2021 12:54:13 -0700 Subject: [PATCH 2/6] update test --- .../tests/test_logs_response.py | 24 +++++++------------ 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/sdk/monitor/azure-monitor-query/tests/test_logs_response.py b/sdk/monitor/azure-monitor-query/tests/test_logs_response.py index 44c81f824b45..9a157d98d054 100644 --- a/sdk/monitor/azure-monitor-query/tests/test_logs_response.py +++ b/sdk/monitor/azure-monitor-query/tests/test_logs_response.py @@ -19,25 +19,17 @@ def _credential(): return credential @pytest.mark.live_test_only -def test_query_response_datetime(): +def test_query_response_types(): credential = _credential() client = LogsQueryClient(credential) - query = """AppRequests | - where TimeGenerated > ago(12h) | - summarize avgRequestDuration=avg(DurationMs) by bin(TimeGenerated, 10m), _ResourceId""" + query = """AppRequests | + summarize avgRequestDuration=avg(DurationMs) by bin(TimeGenerated, 10m), _ResourceId, Success, ItemCount, DurationMs""" # returns LogsQueryResult result = client.query(os.environ['LOG_WORKSPACE_ID'], query, timespan=None) - assert result.tables[0].rows[0][0].__class__ == datetime + assert result.tables[0].rows[0][0].__class__ == datetime # TimeGenerated generated is a datetime + assert result.tables[0].rows[0][1].__class__ == str # _ResourceId generated is a string + assert result.tables[0].rows[0][2].__class__ == bool # Success generated is a bool + assert result.tables[0].rows[0][3].__class__ == int # ItemCount generated is a int + assert result.tables[0].rows[0][4].__class__ == float # DurationMs generated is a real -@pytest.mark.live_test_only -def test_query_response_float(): - credential = _credential() - client = LogsQueryClient(credential) - query = """AppRequests | - where TimeGenerated > ago(12h) | - summarize avgRequestDuration=avg(DurationMs) by bin(TimeGenerated, 10m), _ResourceId""" - - # returns LogsQueryResult - result = client.query(os.environ['LOG_WORKSPACE_ID'], query, timespan=None) - assert result.tables[0].rows[0][2].__class__ == float From 9c9ea27ea87c329a3924dbecfbb1e8f22a5f3b79 Mon Sep 17 00:00:00 2001 From: Rakshith Bhyravabhotla Date: Thu, 19 Aug 2021 13:22:23 -0700 Subject: [PATCH 3/6] lint --- .../azure/monitor/query/_helpers.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) 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 f4c6ec6a785d..262353119be1 100644 --- a/sdk/monitor/azure-monitor-query/azure/monitor/query/_helpers.py +++ b/sdk/monitor/azure-monitor-query/azure/monitor/query/_helpers.py @@ -84,15 +84,15 @@ def construct_iso8601(timespan=None): def native_col_type(col_type, value): if col_type == 'datetime': - return Deserializer.deserialize_iso(value) + value = Deserializer.deserialize_iso(value) elif col_type in ('timespan', 'guid', 'string'): - return str(value) + value = str(value) elif col_type == 'bool': - return bool(value) + value = bool(value) return value def process_row(col_types, row): new_row = [] - for ind in range(len(row)): - new_row.append(native_col_type(col_types[ind].type, row[ind])) + for ind, val in enumerate(row): + new_row.append(native_col_type(col_types[ind].type, val)) return new_row From 2d26ec276458b9f236ff7c689e93b1e536d48fb5 Mon Sep 17 00:00:00 2001 From: Rakshith Bhyravabhotla Date: Thu, 19 Aug 2021 13:23:44 -0700 Subject: [PATCH 4/6] comprehension --- .../azure-monitor-query/azure/monitor/query/_helpers.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) 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 262353119be1..d8fe376c91b1 100644 --- a/sdk/monitor/azure-monitor-query/azure/monitor/query/_helpers.py +++ b/sdk/monitor/azure-monitor-query/azure/monitor/query/_helpers.py @@ -92,7 +92,4 @@ def native_col_type(col_type, value): return value def process_row(col_types, row): - new_row = [] - for ind, val in enumerate(row): - new_row.append(native_col_type(col_types[ind].type, val)) - return new_row + return [native_col_type(col_types[ind].type, val) for ind, val in enumerate(row)] From fa1cf6de5b4a525beda9a49335f5d0989b4dfa46 Mon Sep 17 00:00:00 2001 From: Rakshith Bhyravabhotla Date: Thu, 19 Aug 2021 13:53:14 -0700 Subject: [PATCH 5/6] more precis --- .../azure-monitor-query/azure/monitor/query/_helpers.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) 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 d8fe376c91b1..205239d1816f 100644 --- a/sdk/monitor/azure-monitor-query/azure/monitor/query/_helpers.py +++ b/sdk/monitor/azure-monitor-query/azure/monitor/query/_helpers.py @@ -85,10 +85,8 @@ def construct_iso8601(timespan=None): def native_col_type(col_type, value): if col_type == 'datetime': value = Deserializer.deserialize_iso(value) - elif col_type in ('timespan', 'guid', 'string'): + elif col_type in ('timespan', 'guid'): value = str(value) - elif col_type == 'bool': - value = bool(value) return value def process_row(col_types, row): From 55bbd8bbe8ba5917ce478f6a3931d02206bea31c Mon Sep 17 00:00:00 2001 From: Rakshith Bhyravabhotla Date: Thu, 19 Aug 2021 14:54:00 -0700 Subject: [PATCH 6/6] fix test --- .../tests/test_logs_response.py | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/sdk/monitor/azure-monitor-query/tests/test_logs_response.py b/sdk/monitor/azure-monitor-query/tests/test_logs_response.py index 9a157d98d054..3c69e01caa69 100644 --- a/sdk/monitor/azure-monitor-query/tests/test_logs_response.py +++ b/sdk/monitor/azure-monitor-query/tests/test_logs_response.py @@ -1,14 +1,10 @@ -from datetime import datetime, time, timedelta +from datetime import datetime import pytest -import json +import six import os -from msrest.serialization import UTC from azure.identity import ClientSecretCredential -from azure.core.exceptions import HttpResponseError -from azure.monitor.query import LogsQueryClient, LogsBatchQuery - -from azure.monitor.query._helpers import construct_iso8601 +from azure.monitor.query import LogsQueryClient def _credential(): credential = ClientSecretCredential( @@ -27,9 +23,9 @@ def test_query_response_types(): # returns LogsQueryResult result = client.query(os.environ['LOG_WORKSPACE_ID'], query, timespan=None) - assert result.tables[0].rows[0][0].__class__ == datetime # TimeGenerated generated is a datetime - assert result.tables[0].rows[0][1].__class__ == str # _ResourceId generated is a string - assert result.tables[0].rows[0][2].__class__ == bool # Success generated is a bool - assert result.tables[0].rows[0][3].__class__ == int # ItemCount generated is a int - assert result.tables[0].rows[0][4].__class__ == float # DurationMs generated is a real + assert isinstance(result.tables[0].rows[0][0], datetime) # TimeGenerated generated is a datetime + assert isinstance(result.tables[0].rows[0][1], six.string_types) # _ResourceId generated is a string + assert isinstance(result.tables[0].rows[0][2], bool) # Success generated is a bool + assert isinstance(result.tables[0].rows[0][3], int) # ItemCount generated is a int + assert isinstance(result.tables[0].rows[0][4], float) # DurationMs generated is a real