Skip to content
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
1 change: 1 addition & 0 deletions sdk/monitor/azure-monitor-query/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
- `workspaces`, `workspace_ids`, `qualified_names` and `azure_resource_ids` are now merged into a single `additional_workspaces` list in the query API.
- The `LogQueryRequest` object now takes in a `workspace_id` and `additional_workspaces` instead of `workspace`.
- `aggregation` param is now a list instead of a string in the `query` method.
- `duration` must now be provided as a timedelta instead of a string.

### Key Bugs Fixed

Expand Down
8 changes: 5 additions & 3 deletions sdk/monitor/azure-monitor-query/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ This sample shows sending multiple queries at the same time using batch query AP

```Python
import os
from datetime import timedelta
import pandas as pd
from azure.monitor.query import LogsQueryClient, LogsQueryRequest
from azure.identity import ClientSecretCredential
Expand All @@ -169,13 +170,13 @@ client = LogsQueryClient(credential)
requests = [
LogsQueryRequest(
query="AzureActivity | summarize count()",
duration="PT1H",
duration=timedelta(hours=1),
workspace= os.environ['LOG_WORKSPACE_ID']
),
LogsQueryRequest(
query= """AppRequests | take 10 |
summarize avgRequestDuration=avg(DurationMs) by bin(TimeGenerated, 10m), _ResourceId""",
duration="PT1H",
duration=timedelta(hours=1),
start_time=datetime(2021, 6, 2),
workspace= os.environ['LOG_WORKSPACE_ID']
),
Expand Down Expand Up @@ -228,6 +229,7 @@ This example shows getting the metrics for an EventGrid subscription. The resour

```Python
import os
from datetime import timedelta
from azure.monitor.query import MetricsQueryClient
from azure.identity import ClientSecretCredential

Expand All @@ -245,7 +247,7 @@ response = client.query(
metrics_uri,
metric_names=["PublishSuccessCount"],
start_time=datetime(2021, 5, 25),
duration='P1D'
duration=timedelta(days=1),
)

for metric in response.metrics:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,17 +50,23 @@ def order_results(request_order, responses):
return ordered

def construct_iso8601(start=None, end=None, duration=None):
if duration is not None:
duration = 'PT{}S'.format(duration.total_seconds())
Copy link
Member

Choose a reason for hiding this comment

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

Should we use isinstance?

If user uses a class that has total_seconds property, is it valid?

Copy link
Member

@xiangyan99 xiangyan99 Jun 24, 2021

Choose a reason for hiding this comment

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

What if duration is None in line 69 & 71?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

changed to if duration is not None

  • for the second question - it's okay to be None

Copy link
Member

Choose a reason for hiding this comment

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

Just to confirm, you mean

end = Serializer.serialize_iso(end)
iso_str = None + '/' + end

is valid?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

oops - line 69-71 got changed when i made the changes :)
nope = iso_str = None + '/' + end is not a valid format - although end must be provided with a duration

  • it's worth improving the message :)

iso_str = None
if start is not None:
start = Serializer.serialize_iso(start)
if end and duration:
raise ValueError("start_time can only be provided with duration or end_time, but not both.")
if end is not None:
end = Serializer.serialize_iso(end)
iso_str = start + '/' + end
elif duration is not None:
Copy link
Member

Choose a reason for hiding this comment

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

What's the behavior if user provides start, end and duration?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

we would take the start and end time - we have documented that all three should not be provided - on retrospect, let me warn here too

Copy link
Member

Choose a reason for hiding this comment

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

In fact my question is if three are provided, we would silently ignore duration (current behavior) or give error? :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

we now give error :)

iso_str = start + '/' + duration
else:
raise ValueError("Start time must be provided aling with duration or end time.")
raise ValueError("Start time must be provided along with duration or end time.")
elif end is not None:
if not duration:
raise ValueError("End time must be provided along with duration or start time.")
end = Serializer.serialize_iso(end)
iso_str = duration + '/' + end
else:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
# license information.
# --------------------------------------------------------------------------

from typing import TYPE_CHECKING, Any, Union, Sequence, Dict
from typing import TYPE_CHECKING, Any, Union, Sequence, Dict, Optional
from azure.core.exceptions import HttpResponseError

from ._generated._monitor_query_client import MonitorQueryClient
Expand All @@ -16,6 +16,7 @@

if TYPE_CHECKING:
from azure.core.credentials import TokenCredential
from datetime import timedelta


class LogsQueryClient(object):
Expand Down Expand Up @@ -49,7 +50,7 @@ def __init__(self, credential, **kwargs):
self._query_op = self._client.query

def query(self, workspace_id, query, duration=None, **kwargs):
# type: (str, str, str, Any) -> LogsQueryResults
# type: (str, str, Optional[timedelta], Any) -> LogsQueryResults
"""Execute an Analytics query.

Executes an Analytics query for data.
Expand All @@ -63,9 +64,9 @@ def query(self, workspace_id, query, duration=None, **kwargs):
:param query: The Analytics query. Learn more about the `Analytics query syntax
<https://azure.microsoft.com/documentation/articles/app-insights-analytics-reference/>`_.
:type query: str
:param str duration: The duration for which to query the data. This can also be accompanied
:param ~datetime.timedelta duration: The duration for which to query the data. This can also be accompanied
with either start_time or end_time. If start_time or end_time is not provided, the current time is
taken as the end time. This should be provided in a ISO8601 string format like 'PT1H', 'P1Y2M10DT2H30M'.
taken as the end time.
:keyword datetime start_time: The start time from which to query the data. This should be accompanied
with either end_time or duration.
:keyword datetime end_time: The end time till which to query the data. This should be accompanied
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

# pylint: disable=anomalous-backslash-in-string

from typing import TYPE_CHECKING, Any
from typing import TYPE_CHECKING, Any, Optional

from ._generated._monitor_query_client import (
MonitorQueryClient,
Expand All @@ -17,6 +17,7 @@
from ._helpers import get_metrics_authentication_policy, construct_iso8601

if TYPE_CHECKING:
from datetime import timedelta
from azure.core.credentials import TokenCredential
from azure.core.paging import ItemPaged

Expand Down Expand Up @@ -53,7 +54,7 @@ def __init__(self, credential, **kwargs):
self._definitions_op = self._client.metric_definitions

def query(self, resource_uri, metric_names, duration=None, **kwargs):
# type: (str, list, str, Any) -> MetricsResult
# type: (str, list, Optional[timedelta], Any) -> MetricsResult
"""Lists the metric values for a resource.

**Note**: Although the start_time, end_time, duration are optional parameters, it is highly
Expand All @@ -63,9 +64,9 @@ def query(self, resource_uri, metric_names, duration=None, **kwargs):
:type resource_uri: str
:param metric_names: The names of the metrics to retrieve.
:type metric_names: list[str]
:param str duration: The duration for which to query the data. This can also be accompanied
:param ~datetime.timedelta duration: The duration for which to query the data. This can also be accompanied
with either start_time or end_time. If start_time or end_time is not provided, the current time is
taken as the end time. This should be provided in a ISO8601 string format like 'PT1H', 'P1Y2M10DT2H30M'.
taken as the end time.
:keyword datetime start_time: The start time from which to query the data. This should be accompanied
with either end_time or duration.
:keyword datetime end_time: The end time till which to query the data. This should be accompanied
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,9 +151,9 @@ class LogsQueryRequest(InternalLogQueryRequest):
:param query: The Analytics query. Learn more about the `Analytics query syntax
<https://azure.microsoft.com/documentation/articles/app-insights-analytics-reference/>`_.
:type query: str
:param str duration: The duration for which to query the data. This can also be accompanied
:param ~datetime.timedelta duration: The duration for which to query the data. This can also be accompanied
with either start_time or end_time. If start_time or end_time is not provided, the current time is
taken as the end time. This should be provided in a ISO8601 string format like 'PT1H', 'P1Y2M10DT2H30M'.
taken as the end time.
:keyword datetime start_time: The start time from which to query the data. This should be accompanied
with either end_time or duration.
:keyword datetime end_time: The end time till which to query the data. This should be accompanied
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
# license information.
# --------------------------------------------------------------------------

from typing import Any, Union, Sequence, Dict, TYPE_CHECKING
from datetime import timedelta
from typing import Any, Union, Sequence, Dict, Optional, TYPE_CHECKING
from azure.core.exceptions import HttpResponseError
from .._generated.aio._monitor_query_client import MonitorQueryClient

Expand Down Expand Up @@ -41,7 +42,7 @@ async def query(
self,
workspace_id: str,
query: str,
duration: str = None,
duration: Optional[timedelta] = None,
**kwargs: Any) -> LogsQueryResults:
"""Execute an Analytics query.

Expand All @@ -56,9 +57,9 @@ async def query(
:param query: The Analytics query. Learn more about the `Analytics query syntax
<https://azure.microsoft.com/documentation/articles/app-insights-analytics-reference/>`_.
:type query: str
:param str duration: The duration for which to query the data. This can also be accompanied
:param ~datetime.timedelta duration: The duration for which to query the data. This can also be accompanied
with either start_time or end_time. If start_time or end_time is not provided, the current time is
taken as the end time. This should be provided in a ISO8601 string format like 'PT1H', 'P1Y2M10DT2H30M'.
taken as the end time.
:keyword datetime start_time: The start time from which to query the data. This should be accompanied
with either end_time or duration.
:keyword datetime end_time: The end time till which to query the data. This should be accompanied
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@

# pylint: disable=anomalous-backslash-in-string

from typing import TYPE_CHECKING, Any, List
from datetime import timedelta
from typing import TYPE_CHECKING, Any, List, Optional

from azure.core.async_paging import AsyncItemPaged

Expand Down Expand Up @@ -42,7 +43,13 @@ def __init__(self, credential: "AsyncTokenCredential", **kwargs: Any) -> None:
self._namespace_op = self._client.metric_namespaces
self._definitions_op = self._client.metric_definitions

async def query(self, resource_uri: str, metric_names: List, duration: str = None, **kwargs: Any) -> MetricsResult:
async def query(
self,
resource_uri: str,
metric_names: List,
duration: Optional[timedelta] = None,
**kwargs: Any
) -> MetricsResult:
"""Lists the metric values for a resource.

**Note**: Although the start_time, end_time, duration are optional parameters, it is highly
Expand All @@ -52,9 +59,9 @@ async def query(self, resource_uri: str, metric_names: List, duration: str = Non
:type resource_uri: str
:param metric_names: The names of the metrics to retrieve.
:type metric_names: list
:param str duration: The duration for which to query the data. This can also be accompanied
:param ~datetime.timedelta duration: The duration for which to query the data. This can also be accompanied
with either start_time or end_time. If start_time or end_time is not provided, the current time is
taken as the end time. This should be provided in a ISO8601 string format like 'PT1H', 'P1Y2M10DT2H30M'.
taken as the end time.
:keyword datetime start_time: The start time from which to query the data. This should be accompanied
with either end_time or duration.
:keyword datetime end_time: The end time till which to query the data. This should be accompanied
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import os
import asyncio
from datetime import datetime
from datetime import datetime, timedelta
import urllib3
from azure.monitor.query.aio import MetricsQueryClient
from azure.identity.aio import ClientSecretCredential
Expand All @@ -25,7 +25,7 @@ async def query_metrics():
metrics_uri,
metric_names=["PublishSuccessCount"],
start_time=datetime(2021, 5, 25),
duration='P1D'
duration=timedelta(days=1)
)

for metric in response.metrics:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.

from datetime import datetime
from datetime import datetime, timedelta
import os
import pandas as pd
from azure.monitor.query import LogsQueryClient, LogsQueryRequest
Expand All @@ -20,13 +20,13 @@
requests = [
LogsQueryRequest(
query="AzureActivity | summarize count()",
duration="PT1H",
duration=timedelta(hours=1),
workspace_id= os.environ['LOG_WORKSPACE_ID']
),
LogsQueryRequest(
query= """AppRequests | take 10 |
summarize avgRequestDuration=avg(DurationMs) by bin(TimeGenerated, 10m), _ResourceId""",
duration="PT1H",
duration=timedelta(hours=1),
start_time=datetime(2021, 6, 2),
workspace_id= os.environ['LOG_WORKSPACE_ID']
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import os
import pandas as pd
from datetime import datetime
from datetime import datetime, timedelta
from msrest.serialization import UTC
from azure.monitor.query import LogsQueryClient
from azure.identity import ClientSecretCredential
Expand All @@ -27,7 +27,7 @@
end_time = datetime.now(UTC())

# returns LogsQueryResults
response = client.query(os.environ['LOG_WORKSPACE_ID'], query, duration='PT1H', end_time=end_time)
response = client.query(os.environ['LOG_WORKSPACE_ID'], query, duration=timedelta(days=1), end_time=end_time)

if not response.tables:
print("No results for the query")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# Licensed under the MIT License.

import os
from datetime import datetime
from datetime import datetime, timedelta
from msrest.serialization import UTC
from azure.monitor.query import LogsQueryClient
from azure.identity import ClientSecretCredential
Expand All @@ -23,7 +23,7 @@
end_time = datetime.now(UTC())

# returns LogsQueryResults
response = client.query(os.environ['LOG_WORKSPACE_ID'], query, duration='PT1H', end_time=end_time)
response = client.query(os.environ['LOG_WORKSPACE_ID'], query, duration=timedelta(hours=1), end_time=end_time)

if not response.tables:
print("No results for the query")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
metrics_uri,
metric_names=["MatchedEventCount"],
start_time=datetime(2021, 6, 21),
duration='P1D',
duration=timedelta(days=1),
aggregation=['Count']
)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from datetime import datetime
from datetime import datetime, time, timedelta
import pytest
import os
from azure.identity.aio import ClientSecretCredential
Expand All @@ -20,7 +20,7 @@ async def test_metrics_auth():
os.environ['METRICS_RESOURCE_URI'],
metric_names=["MatchedEventCount"],
start_time=datetime(2021, 6, 21),
duration='P1D',
duration=timedelta(days=1),
aggregation=['Count']
)
assert response
Expand Down
Loading