diff --git a/sdk/monitor/monitor-query/CHANGELOG.md b/sdk/monitor/monitor-query/CHANGELOG.md index 8fff74ee0c15..085e62ac388c 100644 --- a/sdk/monitor/monitor-query/CHANGELOG.md +++ b/sdk/monitor/monitor-query/CHANGELOG.md @@ -1,14 +1,15 @@ # Release History -## 1.2.0-beta.2 (Unreleased) +## 1.2.0-beta.2 (2023-08-21) -### Features Added +- Added `batchMetricsAuthScope` property to `MetricsBatchQueryClientOptions` object. +- Added integration test cases for `MetricsBatchQueryClient`. ### Breaking Changes -### Bugs Fixed - -### Other Changes +- In the `MetricsBatchOptionalParams` object, the casing of property names `endtime`, `orderby`, and `starttime` changed to `endTime`, `orderBy`, and `startTime` respectively. +- In the `MetricsBatchQueryClientOptions` object, the `batchEndPoint` has been removed as optional property. Instead, this has been changed to mandatory parameter in the `MetricsBatchQueryClient` class. +- In the `MetricsBatchOptionalParams` object, the data type properties of `startTime` & `endTime` have been changed from `string` to `Date`. ## 1.2.0-beta.1 (2023-08-11) diff --git a/sdk/monitor/monitor-query/review/monitor-query.api.md b/sdk/monitor/monitor-query/review/monitor-query.api.md index da7fdb45e5aa..52d81466f521 100644 --- a/sdk/monitor/monitor-query/review/monitor-query.api.md +++ b/sdk/monitor/monitor-query/review/monitor-query.api.md @@ -205,23 +205,23 @@ export interface MetricResultsResponseValuesItem { // @public export interface MetricsBatchOptionalParams extends coreClient.OperationOptions { aggregation?: string; - endtime?: string; + endTime?: Date; filter?: string; interval?: string; - orderby?: string; - starttime?: string; + orderBy?: string; + startTime?: Date; top?: number; } // @public export class MetricsBatchQueryClient { - constructor(tokenCredential: TokenCredential, options?: MetricsBatchQueryClientOptions); + constructor(batchEndPoint: string, tokenCredential: TokenCredential, options?: MetricsBatchQueryClientOptions); queryBatch(resourceIds: string[], metricNamespace: string, metricNames: string[], options?: MetricsBatchOptionalParams): Promise; } // @public export interface MetricsBatchQueryClientOptions extends CommonClientOptions { - batchEndPoint?: string; + batchMetricsAuthScope?: string; } // @public diff --git a/sdk/monitor/monitor-query/src/index.ts b/sdk/monitor/monitor-query/src/index.ts index 7b28386d0339..55a838ccdb04 100644 --- a/sdk/monitor/monitor-query/src/index.ts +++ b/sdk/monitor/monitor-query/src/index.ts @@ -62,9 +62,10 @@ export { export { AggregationType, MetricClass } from "./generated/metricsdefinitions/src"; export { NamespaceClassification } from "./generated/metricsnamespaces/src"; -export { MetricsBatchOptionalParams, LocalizableString } from "./generated/metricBatch/src"; +export { LocalizableString } from "./generated/metricBatch/src"; export { MetricResultsResponseValuesItem, Metric as BatchQueryMetric, + MetricsBatchOptionalParams, } from "./models/publicBatchModels"; export { MetricsBatchQueryClient, MetricsBatchQueryClientOptions } from "./metricsBatchQueryClient"; diff --git a/sdk/monitor/monitor-query/src/internal/modelConverters.ts b/sdk/monitor/monitor-query/src/internal/modelConverters.ts index 7c05c12df5f0..b626f397e334 100644 --- a/sdk/monitor/monitor-query/src/internal/modelConverters.ts +++ b/sdk/monitor/monitor-query/src/internal/modelConverters.ts @@ -55,8 +55,14 @@ import { LogsQueryResultStatus, LogsQuerySuccessfulResult, } from "../models/publicLogsModels"; -import { MetricsBatchResponse as GeneratedMetricsBatchResponse } from "../generated/metricBatch/src"; -import { MetricResultsResponseValuesItem } from "../models/publicBatchModels"; +import { + MetricsBatchResponse as GeneratedMetricsBatchResponse, + MetricsBatchOptionalParams as GeneratedMetricsBatchOptionalParams, +} from "../generated/metricBatch/src"; +import { + MetricResultsResponseValuesItem, + MetricsBatchOptionalParams, +} from "../models/publicBatchModels"; /** * @internal @@ -183,6 +189,23 @@ export function fixInvalidBatchQueryResponse( return hadToFix; } +/** + * @internal + */ +export function convertRequestForMetricsBatchQuery( + metricsBatchQueryOptions: MetricsBatchOptionalParams | undefined +): GeneratedMetricsBatchOptionalParams { + if (!metricsBatchQueryOptions) { + return {}; + } + + return { + starttime: metricsBatchQueryOptions.startTime?.toISOString(), + endtime: metricsBatchQueryOptions.endTime?.toISOString(), + ...metricsBatchQueryOptions, + }; +} + /** * @internal */ diff --git a/sdk/monitor/monitor-query/src/metricsBatchQueryClient.ts b/sdk/monitor/monitor-query/src/metricsBatchQueryClient.ts index 343b6960b3ba..f239956d9f5f 100644 --- a/sdk/monitor/monitor-query/src/metricsBatchQueryClient.ts +++ b/sdk/monitor/monitor-query/src/metricsBatchQueryClient.ts @@ -6,11 +6,16 @@ import { tracingClient } from "./tracing"; import { AzureMonitorMetricBatch as GeneratedMonitorMetricBatchClient, KnownApiVersion20230501Preview as MonitorMetricBatchApiVersion, - MetricsBatchOptionalParams, } from "./generated/metricBatch/src"; -import { convertResponseForMetricBatch } from "./internal/modelConverters"; +import { + convertResponseForMetricBatch, + convertRequestForMetricsBatchQuery, +} from "./internal/modelConverters"; import { SDK_VERSION } from "./constants"; -import { MetricResultsResponseValuesItem } from "./models/publicBatchModels"; +import { + MetricResultsResponseValuesItem, + MetricsBatchOptionalParams, +} from "./models/publicBatchModels"; const defaultMetricsScope = "https://management.azure.com/.default"; @@ -18,8 +23,8 @@ const defaultMetricsScope = "https://management.azure.com/.default"; * Options for the MetricsQueryClient. */ export interface MetricsBatchQueryClientOptions extends CommonClientOptions { - /** Overrides batch client endpoint. */ - batchEndPoint?: string; + /** Metrics scope */ + batchMetricsAuthScope?: string; } export const getSubscriptionFromResourceId = function (resourceId: string): string { @@ -35,10 +40,14 @@ export class MetricsBatchQueryClient { private _metricBatchClient: GeneratedMonitorMetricBatchClient; private _baseUrl: string; - constructor(tokenCredential: TokenCredential, options?: MetricsBatchQueryClientOptions) { + constructor( + batchEndPoint: string, + tokenCredential: TokenCredential, + options?: MetricsBatchQueryClientOptions + ) { let scope; - if (options?.batchEndPoint) { - scope = `${options?.batchEndPoint}/.default`; + if (options?.batchMetricsAuthScope) { + scope = `${options?.batchMetricsAuthScope}/.default`; } const credentialOptions = { credentialScopes: scope, @@ -50,8 +59,8 @@ export class MetricsBatchQueryClient { : `${packageDetails}`; const serviceClientOptions = { ...options, - $host: options?.batchEndPoint, - endpoint: options?.batchEndPoint, + $host: batchEndPoint, + endpoint: batchEndPoint, credentialScopes: credentialOptions?.credentialScopes ?? defaultMetricsScope, credential: tokenCredential, userAgentOptions: { @@ -59,7 +68,7 @@ export class MetricsBatchQueryClient { }, }; - this._baseUrl = serviceClientOptions.batchEndPoint ?? ""; + this._baseUrl = batchEndPoint; this._metricBatchClient = new GeneratedMonitorMetricBatchClient( MonitorMetricBatchApiVersion.TwoThousandTwentyThree0501Preview, @@ -80,21 +89,25 @@ export class MetricsBatchQueryClient { throw new Error("Resource IDs can not be empty"); } - return tracingClient.withSpan("MetricsBatchClient.batch", options, async (updatedOptions) => { - const subscriptionId = getSubscriptionFromResourceId(resourceIds[0]); + return tracingClient.withSpan( + "MetricsBatchQueryClient.batch", + options, + async (updatedOptions) => { + const subscriptionId = getSubscriptionFromResourceId(resourceIds[0]); - const response = await this._metricBatchClient.metrics.batch( - this._baseUrl, - subscriptionId, - metricNamespace, - metricNames, - { - resourceids: resourceIds, - }, - updatedOptions - ); + const response = await this._metricBatchClient.metrics.batch( + this._baseUrl, + subscriptionId, + metricNamespace, + metricNames, + { + resourceids: resourceIds, + }, + convertRequestForMetricsBatchQuery(updatedOptions) + ); - return convertResponseForMetricBatch(response); - }); + return convertResponseForMetricBatch(response); + } + ); } } diff --git a/sdk/monitor/monitor-query/src/models/publicBatchModels.ts b/sdk/monitor/monitor-query/src/models/publicBatchModels.ts index 9acb9f0f8f0a..1cda23a9b159 100644 --- a/sdk/monitor/monitor-query/src/models/publicBatchModels.ts +++ b/sdk/monitor/monitor-query/src/models/publicBatchModels.ts @@ -4,6 +4,7 @@ import { TimeSeriesElement } from "./publicMetricsModels"; import { MetricUnit } from "../generated/metrics/src"; import { LocalizableString } from "../generated/metricBatch/src"; +import * as coreClient from "@azure/core-client"; /** * Metric Results Response Values Item @@ -44,3 +45,39 @@ export interface Metric { /** Error message encountered querying this specific metric. */ errorMessage?: string; } + +/** Optional parameters. */ +export interface MetricsBatchOptionalParams extends coreClient.OperationOptions { + /** + * The start time of the query. It is a string in the format 'yyyy-MM-ddTHH:mm:ss.fffZ'. If you have specified the endTime parameter, then this parameter is required. + * If only startTime is specified, then endTime defaults to the current time. + * If no time interval is specified, the default is 1 hour. + */ + startTime?: Date; + /** The end time of the query. It is a string in the format 'yyyy-MM-ddTHH:mm:ss.fffZ'. */ + endTime?: Date; + /** + * The interval (i.e. timegrain) of the query. + * *Examples: PT15M, PT1H, P1D* + */ + interval?: string; + /** + * The list of aggregation types (comma separated) to retrieve. + * *Examples: average, minimum, maximum* + */ + aggregation?: string; + /** + * The maximum number of records to retrieve per resource ID in the request. + * Valid only if filter is specified. + * Defaults to 10. + */ + top?: number; + /** + * The aggregation to use for sorting results and the direction of the sort. + * Only one order can be specified. + * *Examples: sum asc* + */ + orderBy?: string; + /** The filter is used to reduce the set of metric data returned.
Example:
Metric contains metadata A, B and C.
- Return all time series of C where A = a1 and B = b1 or b2
**filter=A eq ‘a1’ and B eq ‘b1’ or B eq ‘b2’ and C eq ‘*’**
- Invalid variant:
**filter=A eq ‘a1’ and B eq ‘b1’ and C eq ‘*’ or B = ‘b2’**
This is invalid because the logical or operator cannot separate two different metadata names.
- Return all time series where A = a1, B = b1 and C = c1:
**filter=A eq ‘a1’ and B eq ‘b1’ and C eq ‘c1’**
- Return all time series where A = a1
**filter=A eq ‘a1’ and B eq ‘*’ and C eq ‘*’**. */ + filter?: string; +} diff --git a/sdk/monitor/monitor-query/swagger/metric-Batch.md b/sdk/monitor/monitor-query/swagger/metric-Batch.md index 8e02c97eb5cd..c14fd8440952 100644 --- a/sdk/monitor/monitor-query/swagger/metric-Batch.md +++ b/sdk/monitor/monitor-query/swagger/metric-Batch.md @@ -8,7 +8,7 @@ input-file: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5f700acd3d094d8eedca381932f2e7916afd2e55/specification/monitor/data-plane/Microsoft.Insights/preview/2023-05-01-preview/metricBatch.json output-folder: ../src/generated/metricBatch package-name: "monitor-metric-batch" -package-version: "1.2.0-beta.1" +package-version: "1.2.0-beta.2" clear-output-folder: true generate-metadata: false add-credentials: false diff --git a/sdk/monitor/monitor-query/test/public/metricsBatchClient.spec.ts b/sdk/monitor/monitor-query/test/public/metricsBatchClient.spec.ts new file mode 100644 index 000000000000..12415fe20d93 --- /dev/null +++ b/sdk/monitor/monitor-query/test/public/metricsBatchClient.spec.ts @@ -0,0 +1,61 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { assert } from "chai"; +import { Context } from "mocha"; +import { MetricsBatchQueryClient, MetricResultsResponseValuesItem } from "../../src"; +import { + RecorderAndMetricsBatchQueryClient, + createRecorderAndMetricsBatchQueryClient, + getMetricsBatchResourceIds, + getMetricsBatchNamespace, + getMetricsBatchNames, +} from "./shared/testShared"; + +describe.skip("MetricsBatchClient live tests", function () { + let resourceIds: string[]; + let metricsNamespace: string; + let metricNames: string[]; + let metricsBatchQueryClient: MetricsBatchQueryClient; + + beforeEach(async function (this: Context) { + const recordedClient: RecorderAndMetricsBatchQueryClient = + await createRecorderAndMetricsBatchQueryClient(); + resourceIds = getMetricsBatchResourceIds(); + metricsNamespace = getMetricsBatchNamespace(); + metricNames = getMetricsBatchNames(); + metricsBatchQueryClient = recordedClient.client; + }); + + // afterEach(async function () { + // loggerForTest.verbose("Recorder: stopping"); + // await recorder.stop(); + // }); + + it("batch query with no resource ids", async () => { + try { + await metricsBatchQueryClient.queryBatch([], metricsNamespace, metricNames); + assert.fail("Code should not reach here."); + } catch (e) { + assert.equal(1, 1); + } + }); + + it("batch query for 2 resource ids", async () => { + const result: MetricResultsResponseValuesItem[] = await metricsBatchQueryClient.queryBatch( + resourceIds, + metricsNamespace, + metricNames + ); + assert.equal(result.length, 2); + }); + + it("batch query for 1 resource id", async () => { + const result: MetricResultsResponseValuesItem[] = await metricsBatchQueryClient.queryBatch( + [resourceIds[0]], + metricsNamespace, + metricNames + ); + assert.equal(result.length, 1); + }); +}); diff --git a/sdk/monitor/monitor-query/test/public/shared/testShared.ts b/sdk/monitor/monitor-query/test/public/shared/testShared.ts index 233d4f944c3a..078583053bfa 100644 --- a/sdk/monitor/monitor-query/test/public/shared/testShared.ts +++ b/sdk/monitor/monitor-query/test/public/shared/testShared.ts @@ -9,7 +9,12 @@ import { } from "@azure-tools/test-recorder"; import * as assert from "assert"; import { createClientLogger } from "@azure/logger"; -import { LogsQueryClient, LogsTable, MetricsQueryClient } from "../../../src"; +import { + LogsQueryClient, + LogsTable, + MetricsQueryClient, + MetricsBatchQueryClient, +} from "../../../src"; import { ExponentialRetryPolicyOptions } from "@azure/core-rest-pipeline"; export const loggerForTest = createClientLogger("test"); const replacementForLogsResourceId = env["LOGS_RESOURCE_ID"]?.startsWith("/") @@ -39,6 +44,41 @@ export interface RecorderAndMetricsClient { recorder: Recorder; } +export interface RecorderAndMetricsBatchQueryClient { + client: MetricsBatchQueryClient; + // recorder: Recorder; +} + +export async function createRecorderAndMetricsBatchQueryClient(): Promise { + // await recorder.start(recorderOptions); + const testCredential = createTestCredential(); + const batchEndPoint = + env["AZURE_MONITOR_BATCH_ENDPOINT"] ?? "https://eastus.metrics.monitor.azure.com/"; + const client = new MetricsBatchQueryClient(batchEndPoint, testCredential); + + return { + client: client, + // recorder: recorder, + }; +} + +export function getMetricsBatchResourceIds(): string[] { + const resourceId: string = assertEnvironmentVariable("LOGS_RESOURCE_ID"); + return [resourceId, `${resourceId}2`]; +} + +export function getMetricsBatchNamespace(): string { + return env["AZURE_MONITOR_BATCH_NAMESPACE"] ?? "requests/count"; +} + +export function getMetricsBatchNames(): string[] { + const metricNamesString = env["AZURE_MONITOR_BATCH_METRICNAMES"]; + if (!metricNamesString) { + return ["requests", "count"]; + } + return metricNamesString.split(" "); +} + export const testEnv = new Proxy(envSetupForPlayback, { get: (target, key: string) => { return env[key] || target[key];