Skip to content
Merged

Timespan #19100

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
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
# license information.
# --------------------------------------------------------------------------

from typing import TYPE_CHECKING
from typing import Mapping, TYPE_CHECKING
from azure.core.exceptions import HttpResponseError
from azure.core.pipeline.policies import BearerTokenCredentialPolicy

Expand Down Expand Up @@ -43,3 +43,8 @@ def get_metrics_authentication_policy(
def process_error(exception):
raise_error = HttpResponseError
raise raise_error(message=exception.message, response=exception.response)

def order_results(request_order, responses):
mapping = {item.id: item for item in responses}
ordered = [mapping[id] for id in request_order]
return ordered
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,10 @@ def query(self, workspace_id, query, **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
:keyword ~datetime.timedelta timespan: Optional. The timespan over which to query data. This is an ISO8601 time
:keyword str timespan: Optional. The timespan over which to query data. This is an ISO8601 time
period value. This timespan is applied in addition to any that are specified in the query
expression.
:keyword int server_timeout: the server timeout. The default timeout is 3 minutes,
:keyword int server_timeout: the server timeout in seconds. The default timeout is 3 minutes,
and the maximum timeout is 10 minutes.
:keyword bool include_statistics: To get information about query statistics.
:keyword bool include_render: In the query language, it is possible to specify different render options.
Expand Down Expand Up @@ -121,9 +121,14 @@ def batch_query(self, queries, **kwargs):
queries = [LogsQueryRequest(**q) for q in queries]
except (KeyError, TypeError):
pass
try:
request_order = [req.id for req in queries]
except AttributeError:
request_order = [req['id'] for req in queries]
batch = BatchRequest(requests=queries)
generated = self._query_op.batch(batch, **kwargs)
return LogsBatchResults._from_generated( # pylint: disable=protected-access
self._query_op.batch(batch, **kwargs)
generated, request_order
)

def close(self):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
MonitorQueryClient,
)

from ._models import MetricsResult, MetricDefinition
from ._models import MetricsResult, MetricDefinition, MetricNamespace
from ._helpers import get_metrics_authentication_policy

if TYPE_CHECKING:
Expand Down Expand Up @@ -100,7 +100,15 @@ def list_metric_namespaces(self, resource_uri, **kwargs):
:rtype: ~azure.core.paging.ItemPaged[~azure.monitor.query.MetricNamespace]
:raises: ~azure.core.exceptions.HttpResponseError
"""
return self._namespace_op.list(resource_uri, **kwargs)
return self._namespace_op.list(
resource_uri,
cls=kwargs.pop(
"cls",
lambda objs: [
MetricNamespace._from_generated(x) for x in objs
]
),
**kwargs)

def list_metric_definitions(self, resource_uri, metric_namespace=None, **kwargs):
# type: (str, str, Any) -> ItemPaged[MetricDefinition]
Expand All @@ -114,7 +122,16 @@ def list_metric_definitions(self, resource_uri, metric_namespace=None, **kwargs)
:rtype: ~azure.core.paging.ItemPaged[~azure.monitor.query.MetricDefinition]
:raises: ~azure.core.exceptions.HttpResponseError
"""
return self._definitions_op.list(resource_uri, metric_namespace, **kwargs)
return self._definitions_op.list(
resource_uri,
metric_namespace,
cls=kwargs.pop(
"cls",
lambda objs: [
MetricDefinition._from_generated(x) for x in objs
]
),
**kwargs)

def close(self):
# type: () -> None
Expand Down
58 changes: 33 additions & 25 deletions sdk/monitor/azure-monitor-query/azure/monitor/query/_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@
import uuid
from typing import Any, Optional, List

from ._helpers import order_results
from ._generated.models import (
Column as InternalColumn,
QueryBody as InternalQueryBody,
LogQueryRequest as InternalLogQueryRequest,
MetricNamespace as InternalMetricNamespace,
ErrorDetails as InternalErrorDetails
)

Expand Down Expand Up @@ -168,7 +168,7 @@ class LogsQueryRequest(InternalLogQueryRequest):
def __init__(self, query, workspace, timespan=None, **kwargs):
# type: (str, str, Optional[str], Any) -> None
super(LogsQueryRequest, self).__init__(**kwargs)
self.id = kwargs.get("request_id", uuid.uuid4())
self.id = kwargs.get("request_id", str(uuid.uuid4()))
self.headers = kwargs.get("headers", None)
self.body = {
"query": query, "timespan": timespan
Expand Down Expand Up @@ -250,13 +250,13 @@ def __init__(self, **kwargs):
self.error = kwargs.get("error", None)

@classmethod
def _from_generated(cls, generated):
def _from_generated(cls, generated, request_order):
if not generated:
return cls()
return cls(
responses=[
responses=order_results(request_order, [
LogsQueryResult._from_generated(rsp) for rsp in generated.responses # pylint: disable=protected-access
],
]),
error=LogsBatchResultError._from_generated(generated.error) # pylint: disable=protected-access
)

Expand Down Expand Up @@ -314,35 +314,40 @@ def __init__(
self.target = kwargs.get('target', None)


class MetricNamespace(InternalMetricNamespace):
class MetricNamespace(object):
"""Metric namespace class specifies the metadata for a metric namespace.

:param id: The ID of the metricNamespace.
:type id: str
:param type: The type of the namespace.
:type type: str
:param name: The name of the namespace.
:type name: str
:param properties: Properties which include the fully qualified namespace name.
:type properties: ~monitor_query_client.models.MetricNamespaceName
:keyword id: The ID of the metricNamespace.
:paramtype id: str
:keyword type: The type of the namespace.
:paramtype type: str
:keyword name: The name of the namespace.
:paramtype name: str
:keyword metric_namespace_name: The fully qualified namespace name.
:paramtype properties: str
"""

_attribute_map = {
'id': {'key': 'id', 'type': 'str'},
'type': {'key': 'type', 'type': 'str'},
'name': {'key': 'name', 'type': 'str'},
'properties': {'key': 'properties', 'type': 'MetricNamespaceName'},
}

def __init__(
self,
**kwargs
):
super(MetricNamespace, self).__init__(**kwargs)
self.id = kwargs.get('id', None)
self.type = kwargs.get('type', None)
self.name = kwargs.get('name', None)
self.properties = kwargs.get('properties', None)
self.metric_namespace_name = kwargs.get('metric_namespace_name', None)

@classmethod
def _from_generated(cls, generated):
if not generated:
return cls()
metric_namespace_name = None
if generated.properties:
metric_namespace_name = generated.properties.metric_namespace_name
return cls(
id=generated.id,
type=generated.type,
name=generated.name,
metric_namespace_name=metric_namespace_name
)

class MetricDefinition(object):
"""Metric definition class specifies the metadata for a metric.
Expand Down Expand Up @@ -394,6 +399,9 @@ def __init__(
def _from_generated(cls, generated):
if not generated:
return cls()
dimensions = None
if generated.dimensions is not None:
dimensions = [d.value for d in generated.dimensions]
return cls(
is_dimension_required=generated.is_dimension_required,
resource_id=generated.resource_id,
Expand All @@ -408,7 +416,7 @@ def _from_generated(cls, generated):
) for val in generated.metric_availabilities
],
id=generated.id,
dimensions=[d.value for d in generated.dimensions]
dimensions=dimensions
)

class MetricValue(object):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ async def query(self, workspace_id: str, query: str, **kwargs: Any) -> LogsQuery
)

try:
return await LogsQueryResults._from_generated(self._query_op.execute( # pylint: disable=protected-access
return LogsQueryResults._from_generated(await self._query_op.execute( # pylint: disable=protected-access
workspace_id=workspace_id,
body=body,
prefer=prefer,
Expand Down Expand Up @@ -120,9 +120,13 @@ async def batch_query(
queries = [LogsQueryRequest(**q) for q in queries]
except (KeyError, TypeError):
pass
try:
request_order = [req.id for req in queries]
except AttributeError:
request_order = [req['id'] for req in queries]
batch = BatchRequest(requests=queries)
return await LogsBatchResults._from_generated( # pylint: disable=protected-access
self._query_op.batch(batch, **kwargs)
return LogsBatchResults._from_generated( # pylint: disable=protected-access
await self._query_op.batch(batch, **kwargs), request_order
)

async def __aenter__(self) -> "LogsClient":
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from .._generated.aio._monitor_query_client import (
MonitorQueryClient,
)
from .._models import MetricsResult, MetricDefinition
from .._models import MetricsResult, MetricDefinition, MetricNamespace
from .._helpers import get_authentication_policy
from .._models import MetricNamespace

Expand Down Expand Up @@ -95,7 +95,15 @@ async def list_metric_namespaces(self, resource_uri: str, **kwargs: Any) -> Item
:rtype: ~azure.core.paging.ItemPaged[~azure.monitor.query.MetricNamespace]
:raises: ~azure.core.exceptions.HttpResponseError
"""
return await self._namespace_op.list(resource_uri, **kwargs)
return await self._namespace_op.list(
resource_uri,
cls=kwargs.pop(
"cls",
lambda objs: [
MetricNamespace._from_generated(x) for x in objs
]
),
**kwargs)

async def list_metric_definitions(
self,
Expand All @@ -113,7 +121,16 @@ async def list_metric_definitions(
:rtype: ~azure.core.paging.ItemPaged[~azure.monitor.query.MetricDefinition]
:raises: ~azure.core.exceptions.HttpResponseError
"""
return await self._definitions_op.list(resource_uri, metric_namespace, **kwargs)
return await self._definitions_op.list(
resource_uri,
metric_namespace,
cls=kwargs.pop(
"cls",
lambda objs: [
MetricDefinition._from_generated(x) for x in objs
]
),
**kwargs)

async def __aenter__(self) -> "MetricsClient":
await self._client.__aenter__()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@

for response in response.responses:
body = response.body
print(response.id)
if not body.tables:
print("Something is wrong")
else:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,6 @@
response = client.list_metric_definitions(metrics_uri, metric_namespace='microsoft.eventgrid/topics')

for item in response:
pass
print(item)
for availability in item.metric_availabilities:
print(availability.time_grain)
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.

import os
from azure.monitor.query import MetricsClient
from azure.identity import ClientSecretCredential

credential = ClientSecretCredential(
client_id = os.environ['AZURE_CLIENT_ID'],
client_secret = os.environ['AZURE_CLIENT_SECRET'],
tenant_id = os.environ['AZURE_TENANT_ID']
)

client = MetricsClient(credential)

metrics_uri = os.environ['METRICS_RESOURCE_URI']
response = client.list_metric_namespaces(metrics_uri)

for item in response:
print(item.metric_namespace_name)
print(item.type)
1 change: 1 addition & 0 deletions sdk/monitor/azure-monitor-query/sdk_packaging.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[packaging]
auto_update = false
package_name = "azure-monitor-query"
package_nspkg = "azure-monitor-nspkg"
package_pprint_name = "Monitor Query"
package_doc_id = "monitor-query"
is_stable = false
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import pytest
import os
from azure.identity import ClientSecretCredential
from azure.identity.aio import ClientSecretCredential
from azure.core.exceptions import HttpResponseError
from azure.monitor.query import LogsClient, LogsQueryRequest
from azure.monitor.query import LogsQueryRequest
from azure.monitor.query.aio import LogsClient

def _credential():
credential = ClientSecretCredential(
Expand All @@ -12,6 +13,7 @@ def _credential():
)
return credential

@pytest.mark.live_test_only
async def test_logs_auth():
credential = _credential()
client = LogsClient(credential)
Expand All @@ -25,6 +27,7 @@ async def test_logs_auth():
assert response is not None
assert response.tables is not None

@pytest.mark.live_test_only
async def test_logs_server_timeout():
client = LogsClient(_credential())

Expand All @@ -36,6 +39,7 @@ async def test_logs_server_timeout():
)
assert e.message.contains('Gateway timeout')

@pytest.mark.live_test_only
async def test_logs_batch_query():
client = LogsClient(_credential())

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import py
import pytest
import os
from azure.identity import ClientSecretCredential
from azure.core.exceptions import HttpResponseError
from azure.monitor.query import MetricsClient
from azure.identity.aio import ClientSecretCredential
from azure.monitor.query.aio import MetricsClient

def _credential():
credential = ClientSecretCredential(
Expand All @@ -12,6 +12,7 @@ def _credential():
)
return credential

@pytest.mark.live_test_only
async def test_metrics_auth():
credential = _credential()
client = MetricsClient(credential)
Expand All @@ -21,13 +22,15 @@ async def test_metrics_auth():
assert response is not None
assert response.metrics is not None

@pytest.mark.live_test_only
async def test_metrics_namespaces():
client = MetricsClient(_credential())

response = await client.list_metric_namespaces(os.environ['METRICS_RESOURCE_URI'])

assert response is not None

@pytest.mark.live_test_only
async def test_metrics_definitions():
client = MetricsClient(_credential())

Expand Down
Loading