Skip to content

Commit 6f2695b

Browse files
author
Rakshith Bhyravabhotla
authored
Workspaces must be a single param (#19344)
* Workspaces must be common * tests yml * lint * changelog * Update sdk/monitor/azure-monitor-query/tests/async/test_logs_client_async.py
1 parent 5de5861 commit 6f2695b

File tree

9 files changed

+165
-67
lines changed

9 files changed

+165
-67
lines changed

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66

77
### Breaking Changes
88

9+
- `workspaces`, `workspace_ids`, `qualified_names` and `azure_resource_ids` are now merged into a single `additional_workspaces` list in the query API.
10+
- The `LogQueryRequest` object now takes in a `workspace_id` and `additional_workspaces` instead of `workspace`.
11+
912
### Key Bugs Fixed
1013

1114
### Fixed

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

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@
1010

1111
from ._generated._monitor_query_client import MonitorQueryClient
1212

13-
from ._generated.models import BatchRequest
13+
from ._generated.models import BatchRequest, QueryBody as LogsQueryBody
1414
from ._helpers import get_authentication_policy, process_error, construct_iso8601
15-
from ._models import LogsQueryResults, LogsQueryRequest, LogsQueryBody, LogsBatchResults
15+
from ._models import LogsQueryResults, LogsQueryRequest, LogsBatchResults
1616

1717
if TYPE_CHECKING:
1818
from azure.core.credentials import TokenCredential
@@ -76,14 +76,9 @@ def query(self, workspace_id, query, duration=None, **kwargs):
7676
:keyword bool include_render: In the query language, it is possible to specify different render options.
7777
By default, the API does not return information regarding the type of visualization to show.
7878
If your client requires this information, specify the preference
79-
:keyword workspaces: A list of workspaces that are included in the query.
80-
:paramtype workspaces: list[str]
81-
:keyword qualified_names: A list of qualified workspace names that are included in the query.
82-
:paramtype qualified_names: list[str]
83-
:keyword workspace_ids: A list of workspace IDs that are included in the query.
84-
:paramtype workspace_ids: list[str]
85-
:keyword azure_resource_ids: A list of Azure resource IDs that are included in the query.
86-
:paramtype azure_resource_ids: list[str]
79+
:keyword additional_workspaces: A list of workspaces that are included in the query.
80+
These can be qualified workspace names, workspsce Ids or Azure resource Ids.
81+
:paramtype additional_workspaces: list[str]
8782
:return: QueryResults, or the result of cls(response)
8883
:rtype: ~azure.monitor.query.LogsQueryResults
8984
:raises: ~azure.core.exceptions.HttpResponseError
@@ -103,6 +98,7 @@ def query(self, workspace_id, query, duration=None, **kwargs):
10398
include_statistics = kwargs.pop("include_statistics", False)
10499
include_render = kwargs.pop("include_render", False)
105100
server_timeout = kwargs.pop("server_timeout", None)
101+
workspaces = kwargs.pop("additional_workspaces", None)
106102

107103
prefer = ""
108104
if server_timeout:
@@ -119,6 +115,7 @@ def query(self, workspace_id, query, duration=None, **kwargs):
119115
body = LogsQueryBody(
120116
query=query,
121117
timespan=timespan,
118+
workspaces=workspaces,
122119
**kwargs
123120
)
124121

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

Lines changed: 9 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
from ._helpers import order_results, construct_iso8601
1212
from ._generated.models import (
1313
Column as InternalColumn,
14-
QueryBody as InternalQueryBody,
1514
LogQueryRequest as InternalLogQueryRequest,
1615
ErrorDetails as InternalErrorDetails
1716
)
@@ -151,6 +150,8 @@ class LogsQueryRequest(InternalLogQueryRequest):
151150
152151
Variables are only populated by the server, and will be ignored when sending a request.
153152
153+
:param workspace_id: Workspace Id to be included in the query.
154+
:type workspace_id: str
154155
:param query: The Analytics query. Learn more about the `Analytics query syntax
155156
<https://azure.microsoft.com/documentation/articles/app-insights-analytics-reference/>`_.
156157
:type query: str
@@ -161,60 +162,30 @@ class LogsQueryRequest(InternalLogQueryRequest):
161162
with either end_time or duration.
162163
:keyword datetime end_time: The end time till which to query the data. This should be accompanied
163164
with either start_time or duration.
164-
:param workspace: Workspace Id to be included in the query.
165-
:type workspace: str
165+
:keyword additional_workspaces: A list of workspaces that are included in the query.
166+
These can be qualified workspace names, workspsce Ids or Azure resource Ids.
167+
:paramtype additional_workspaces: list[str]
166168
:keyword request_id: The error details.
167169
:paramtype request_id: str
168170
:keyword headers: Dictionary of :code:`<string>`.
169171
:paramtype headers: dict[str, str]
170172
"""
171173

172-
def __init__(self, query, workspace, duration=None, **kwargs):
174+
def __init__(self, query, workspace_id, duration=None, **kwargs):
173175
# type: (str, str, Optional[str], Any) -> None
174176
super(LogsQueryRequest, self).__init__(**kwargs)
175177
start = kwargs.pop('start_time', None)
176178
end = kwargs.pop('end_time', None)
177179
timespan = construct_iso8601(start, end, duration)
180+
additional_workspaces = kwargs.pop("additional_workspaces", None)
178181
self.id = kwargs.get("request_id", str(uuid.uuid4()))
179182
self.headers = kwargs.get("headers", None)
180183
self.body = {
181-
"query": query, "timespan": timespan
184+
"query": query, "timespan": timespan, "workspaces": additional_workspaces
182185
}
183-
self.workspace = workspace
186+
self.workspace = workspace_id
184187

185188

186-
class LogsQueryBody(InternalQueryBody):
187-
"""The Analytics query. Learn more about the
188-
`Analytics query syntax <https://azure.microsoft.com/documentation/articles/app-insights-analytics-reference/>`_.
189-
190-
All required parameters must be populated in order to send to Azure.
191-
192-
:param query: Required. The query to execute.
193-
:type query: str
194-
:keyword timespan: Optional. The timespan over which to query data. This is an ISO8601 time
195-
period value. This timespan is applied in addition to any that are specified in the query
196-
expression.
197-
:paramtype timespan: str
198-
:keyword workspaces: A list of workspaces that are included in the query.
199-
:paramtype workspaces: list[str]
200-
:keyword qualified_names: A list of qualified workspace names that are included in the query.
201-
:paramtype qualified_names: list[str]
202-
:keyword workspace_ids: A list of workspace IDs that are included in the query.
203-
:paramtype workspace_ids: list[str]
204-
:keyword azure_resource_ids: A list of Azure resource IDs that are included in the query.
205-
:paramtype azure_resource_ids: list[str]
206-
"""
207-
208-
def __init__(self, query, timespan=None, **kwargs):
209-
# type: (str, Optional[str], Any) -> None
210-
kwargs.setdefault("query", query)
211-
kwargs.setdefault("timespan", timespan)
212-
super(LogsQueryBody, self).__init__(**kwargs)
213-
self.workspaces = kwargs.get("workspaces", None)
214-
self.qualified_names = kwargs.get("qualified_names", None)
215-
self.workspace_ids = kwargs.get("workspace_ids", None)
216-
self.azure_resource_ids = kwargs.get("azure_resource_ids", None)
217-
218189
class LogsQueryResult(object):
219190
"""The LogsQueryResult.
220191

sdk/monitor/azure-monitor-query/azure/monitor/query/aio/_log_query_client_async.py

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@
99
from azure.core.exceptions import HttpResponseError
1010
from .._generated.aio._monitor_query_client import MonitorQueryClient
1111

12-
from .._generated.models import BatchRequest
12+
from .._generated.models import BatchRequest, QueryBody as LogsQueryBody
1313
from .._helpers import process_error, construct_iso8601
14-
from .._models import LogsQueryResults, LogsQueryRequest, LogsQueryBody, LogsBatchResults
14+
from .._models import LogsQueryResults, LogsQueryRequest, LogsBatchResults
1515
from ._helpers_asyc import get_authentication_policy
1616

1717
if TYPE_CHECKING:
@@ -69,14 +69,9 @@ async def query(
6969
:keyword bool include_render: In the query language, it is possible to specify different render options.
7070
By default, the API does not return information regarding the type of visualization to show.
7171
If your client requires this information, specify the preference
72-
:keyword workspaces: A list of workspaces that are included in the query.
73-
:paramtype workspaces: list[str]
74-
:keyword qualified_names: A list of qualified workspace names that are included in the query.
75-
:paramtype qualified_names: list[str]
76-
:keyword workspace_ids: A list of workspace IDs that are included in the query.
77-
:paramtype workspace_ids: list[str]
78-
:keyword azure_resource_ids: A list of Azure resource IDs that are included in the query.
79-
:paramtype azure_resource_ids: list[str]
72+
:keyword additional_workspaces: A list of workspaces that are included in the query.
73+
These can be qualified workspace names, workspsce Ids or Azure resource Ids.
74+
:paramtype additional_workspaces: list[str]
8075
:return: QueryResults, or the result of cls(response)
8176
:rtype: ~azure.monitor.query.LogsQueryResults
8277
:raises: ~azure.core.exceptions.HttpResponseError
@@ -87,6 +82,7 @@ async def query(
8782
include_statistics = kwargs.pop("include_statistics", False)
8883
include_render = kwargs.pop("include_render", False)
8984
server_timeout = kwargs.pop("server_timeout", None)
85+
additional_workspaces = kwargs.pop("additional_workspaces", None)
9086

9187
prefer = ""
9288
if server_timeout:
@@ -103,6 +99,7 @@ async def query(
10399
body = LogsQueryBody(
104100
query=query,
105101
timespan=timespan,
102+
workspaces=additional_workspaces,
106103
**kwargs
107104
)
108105

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

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,16 @@
77
from azure.monitor.query import LogsQueryClient
88
from azure.identity import ClientSecretCredential
99

10-
# [START client_auth_with_token_cred]
1110
credential = ClientSecretCredential(
1211
client_id = os.environ['AZURE_CLIENT_ID'],
1312
client_secret = os.environ['AZURE_CLIENT_SECRET'],
1413
tenant_id = os.environ['AZURE_TENANT_ID']
1514
)
1615

1716
client = LogsQueryClient(credential)
18-
# [END client_auth_with_token_cred]
1917

2018
# Response time trend
2119
# request duration over the last 12 hours.
22-
# [START send_logs_query]
2320
query = """AppRequests |
2421
summarize avgRequestDuration=avg(DurationMs) by bin(TimeGenerated, 10m), _ResourceId"""
2522

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT License.
3+
4+
import os
5+
import pandas as pd
6+
from datetime import datetime
7+
from msrest.serialization import UTC
8+
from azure.monitor.query import LogsQueryClient
9+
from azure.identity import ClientSecretCredential
10+
11+
credential = ClientSecretCredential(
12+
client_id = os.environ['AZURE_CLIENT_ID'],
13+
client_secret = os.environ['AZURE_CLIENT_SECRET'],
14+
tenant_id = os.environ['AZURE_TENANT_ID']
15+
)
16+
17+
client = LogsQueryClient(credential)
18+
19+
# Response time trend
20+
# request duration over the last 12 hours.
21+
query = "union * | where TimeGenerated > ago(100d) | project TenantId | summarize count() by TenantId"
22+
23+
end_time = datetime.now(UTC())
24+
25+
# returns LogsQueryResults
26+
response = client.query(
27+
os.environ['LOG_WORKSPACE_ID'],
28+
query,
29+
additional_workspaces=[os.environ["SECONDARY_WORKSPACE_ID"]],
30+
)
31+
32+
if not response.tables:
33+
print("No results for the query")
34+
35+
for table in response.tables:
36+
df = pd.DataFrame(table.rows, columns=[col.name for col in table.columns])
37+
print(df)
38+

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

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,20 +47,68 @@ async def test_logs_batch_query():
4747
LogsQueryRequest(
4848
query="AzureActivity | summarize count()",
4949
timespan="PT1H",
50-
workspace= os.environ['LOG_WORKSPACE_ID']
50+
workspace_id= os.environ['LOG_WORKSPACE_ID']
5151
),
5252
LogsQueryRequest(
5353
query= """AppRequests | take 10 |
5454
summarize avgRequestDuration=avg(DurationMs) by bin(TimeGenerated, 10m), _ResourceId""",
5555
timespan="PT1H",
56-
workspace= os.environ['LOG_WORKSPACE_ID']
56+
workspace_id= os.environ['LOG_WORKSPACE_ID']
5757
),
5858
LogsQueryRequest(
5959
query= "AppRequests | take 2",
60-
workspace= os.environ['LOG_WORKSPACE_ID']
60+
workspace_id= os.environ['LOG_WORKSPACE_ID']
6161
),
6262
]
6363
response = await client.batch_query(requests)
6464

6565
assert len(response.responses) == 3
6666

67+
@pytest.mark.live_test_only
68+
@pytest.mark.asyncio
69+
async def test_logs_single_query_additional_workspaces_async():
70+
credential = _credential()
71+
client = LogsQueryClient(credential)
72+
query = "union * | where TimeGenerated > ago(100d) | project TenantId | summarize count() by TenantId"
73+
74+
# returns LogsQueryResults
75+
response = await client.query(
76+
os.environ['LOG_WORKSPACE_ID'],
77+
query,
78+
additional_workspaces=[os.environ["SECONDARY_WORKSPACE_ID"]],
79+
)
80+
81+
assert response
82+
assert len(response.tables[0].rows) == 2
83+
84+
@pytest.mark.live_test_only
85+
@pytest.mark.asyncio
86+
async def test_logs_batch_query_additional_workspaces():
87+
client = LogsQueryClient(_credential())
88+
query = "union * | where TimeGenerated > ago(100d) | project TenantId | summarize count() by TenantId"
89+
90+
requests = [
91+
LogsQueryRequest(
92+
query,
93+
timespan="PT1H",
94+
workspace_id= os.environ['LOG_WORKSPACE_ID'],
95+
additional_workspaces=[os.environ['SECONDARY_WORKSPACE_ID']]
96+
),
97+
LogsQueryRequest(
98+
query,
99+
timespan="PT1H",
100+
workspace_id= os.environ['LOG_WORKSPACE_ID'],
101+
additional_workspaces=[os.environ['SECONDARY_WORKSPACE_ID']]
102+
),
103+
LogsQueryRequest(
104+
query,
105+
workspace_id= os.environ['LOG_WORKSPACE_ID'],
106+
additional_workspaces=[os.environ['SECONDARY_WORKSPACE_ID']]
107+
),
108+
]
109+
response = await client.batch_query(requests)
110+
111+
assert len(response.responses) == 3
112+
113+
for resp in response.responses:
114+
assert len(resp.body.tables[0].rows) == 2

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

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,20 +68,66 @@ def test_logs_batch_query():
6868
LogsQueryRequest(
6969
query="AzureActivity | summarize count()",
7070
timespan="PT1H",
71-
workspace= os.environ['LOG_WORKSPACE_ID']
71+
workspace_id= os.environ['LOG_WORKSPACE_ID']
7272
),
7373
LogsQueryRequest(
7474
query= """AppRequests | take 10 |
7575
summarize avgRequestDuration=avg(DurationMs) by bin(TimeGenerated, 10m), _ResourceId""",
7676
timespan="PT1H",
77-
workspace= os.environ['LOG_WORKSPACE_ID']
77+
workspace_id= os.environ['LOG_WORKSPACE_ID']
7878
),
7979
LogsQueryRequest(
8080
query= "AppRequests | take 2",
81-
workspace= os.environ['LOG_WORKSPACE_ID']
81+
workspace_id= os.environ['LOG_WORKSPACE_ID']
8282
),
8383
]
8484
response = client.batch_query(requests)
8585

8686
assert len(response.responses) == 3
8787

88+
@pytest.mark.live_test_only
89+
def test_logs_single_query_additional_workspaces():
90+
credential = _credential()
91+
client = LogsQueryClient(credential)
92+
query = "union * | where TimeGenerated > ago(100d) | project TenantId | summarize count() by TenantId"
93+
94+
# returns LogsQueryResults
95+
response = client.query(
96+
os.environ['LOG_WORKSPACE_ID'],
97+
query,
98+
additional_workspaces=[os.environ["SECONDARY_WORKSPACE_ID"]],
99+
)
100+
101+
assert response is not None
102+
assert len(response.tables[0].rows) == 2
103+
104+
@pytest.mark.live_test_only
105+
def test_logs_batch_query_additional_workspaces():
106+
client = LogsQueryClient(_credential())
107+
query = "union * | where TimeGenerated > ago(100d) | project TenantId | summarize count() by TenantId"
108+
109+
requests = [
110+
LogsQueryRequest(
111+
query,
112+
timespan="PT1H",
113+
workspace_id= os.environ['LOG_WORKSPACE_ID'],
114+
additional_workspaces=[os.environ['SECONDARY_WORKSPACE_ID']]
115+
),
116+
LogsQueryRequest(
117+
query,
118+
timespan="PT1H",
119+
workspace_id= os.environ['LOG_WORKSPACE_ID'],
120+
additional_workspaces=[os.environ['SECONDARY_WORKSPACE_ID']]
121+
),
122+
LogsQueryRequest(
123+
query,
124+
workspace_id= os.environ['LOG_WORKSPACE_ID'],
125+
additional_workspaces=[os.environ['SECONDARY_WORKSPACE_ID']]
126+
),
127+
]
128+
response = client.batch_query(requests)
129+
130+
assert len(response.responses) == 3
131+
132+
for resp in response.responses:
133+
assert len(resp.body.tables[0].rows) == 2

sdk/monitor/tests.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,6 @@ stages:
1212
AZURE_CLIENT_ID: $(aad-azure-sdk-test-client-id)
1313
AZURE_CLIENT_SECRET: $(aad-azure-sdk-test-client-secret)
1414
LOG_WORKSPACE_ID: $(azure-monitor-query-log-workspace)
15+
SECONDARY_WORKSPACE_ID: $(python-query-secondary-workspace-id)
1516
METRICS_RESOURCE_URI: $(azure-monitor-query-metrics-uri)
1617
AZURE_TEST_RUN_LIVE: 'true'

0 commit comments

Comments
 (0)