From 632629c552cc0b395ad2785f5e0327f535d6cdaa Mon Sep 17 00:00:00 2001 From: KarishmaGhiya Date: Tue, 28 Sep 2021 18:50:44 -0700 Subject: [PATCH] Api Consistency Review feedback (#17873) --- .../monitor-query/review/monitor-query.api.md | 83 +++++++------------ .../monitor-query/samples-dev/logsQuery.ts | 4 +- .../logsQueryMultipleWorkspaces.ts | 4 +- .../monitor-query/samples-dev/metricsQuery.ts | 4 +- sdk/monitor/monitor-query/src/index.ts | 16 ++-- .../src/internal/modelConverters.ts | 34 ++++++-- .../monitor-query/src/logsQueryClient.ts | 37 ++++----- .../monitor-query/src/metricsQueryClient.ts | 34 ++++---- .../monitor-query/src/models/constants.ts | 14 ++-- .../src/models/publicLogsModels.ts | 42 +++------- .../src/models/publicMetricsModels.ts | 15 +++- .../monitor-query/src/models/timeInterval.ts | 2 +- .../monitor-query/src/timespanConversion.ts | 6 +- .../unit/logsQueryClient.unittest.spec.ts | 6 +- .../unit/modelConverters.unittest.spec.ts | 8 +- .../test/public/logsQueryClient.spec.ts | 42 +++++----- .../test/public/metricsQueryClient.spec.ts | 14 ++-- 17 files changed, 175 insertions(+), 190 deletions(-) diff --git a/sdk/monitor/monitor-query/review/monitor-query.api.md b/sdk/monitor/monitor-query/review/monitor-query.api.md index f0b8e86f6668..c13ec3a0b477 100644 --- a/sdk/monitor/monitor-query/review/monitor-query.api.md +++ b/sdk/monitor/monitor-query/review/monitor-query.api.md @@ -11,8 +11,7 @@ import { TokenCredential } from '@azure/core-auth'; // @public export class AggregateBatchError extends Error { - constructor(errors: ErrorInfo[]); - // (undocumented) + constructor(errors: LogsErrorInfo[]); errors: BatchError[]; } @@ -20,13 +19,9 @@ export class AggregateBatchError extends Error { export type AggregationType = "None" | "Average" | "Count" | "Minimum" | "Maximum" | "Total"; // @public -export class BatchError extends Error implements ErrorInfo { - constructor(errorInfo: ErrorInfo); - additionalProperties?: Record; +export class BatchError extends Error implements LogsErrorInfo { + constructor(errorInfo: LogsErrorInfo); code: string; - details?: ErrorDetail[]; - innerError?: ErrorInfo; - message: string; } // @public @@ -34,34 +29,15 @@ export const Durations: { readonly sevenDays: "P7D"; readonly threeDays: "P3D"; readonly twoDays: "P2D"; - readonly OneDay: "P1D"; - readonly OneHour: "PT1H"; - readonly FourHours: "PT4H"; - readonly TwentyFourHours: "P1D"; - readonly FourtyEightHours: "P2D"; - readonly ThirtyMinutes: "PT30M"; - readonly FiveMinutes: "PT5M"; + readonly oneDay: "P1D"; + readonly oneHour: "PT1H"; + readonly fourHours: "PT4H"; + readonly twentyFourHours: "P1D"; + readonly fourtyEightHours: "P2D"; + readonly thirtyMinutes: "PT30M"; + readonly fiveMinutes: "PT5M"; }; -// @public -export interface ErrorDetail { - additionalProperties?: Record; - code: string; - message: string; - resources?: string[]; - target?: string; - value?: string; -} - -// @public -export interface ErrorInfo extends Error { - additionalProperties?: Record; - code: string; - details?: ErrorDetail[]; - innerError?: ErrorInfo; - message: string; -} - // @public export interface ListMetricDefinitionsOptions extends OperationOptions { metricNamespace?: string; @@ -81,6 +57,11 @@ export interface LogsColumn { // @public export type LogsColumnType = string; +// @public +export interface LogsErrorInfo extends Error { + code: string; +} + // @public export interface LogsQueryBatchOptions extends OperationOptions { throwOnAnyFailure?: boolean; @@ -90,7 +71,7 @@ export interface LogsQueryBatchOptions extends OperationOptions { export interface LogsQueryBatchResult { results: { tables?: LogsTable[]; - error?: ErrorInfo; + error?: LogsErrorInfo; status?: LogsQueryResultStatus; statistics?: Record; visualization?: Record; @@ -100,15 +81,13 @@ export interface LogsQueryBatchResult { // @public export class LogsQueryClient { constructor(tokenCredential: TokenCredential, options?: LogsQueryClientOptions); - query(workspaceId: string, query: string, timespan: TimeInterval, options?: LogsQueryOptions): Promise; queryBatch(batch: QueryBatch[], options?: LogsQueryBatchOptions): Promise; + queryWorkspace(workspaceId: string, query: string, timespan: QueryTimeInterval, options?: LogsQueryOptions): Promise; } // @public export interface LogsQueryClientOptions extends CommonClientOptions { - credentialOptions?: { - credentialScopes?: string | string[]; - }; + audience?: string; endpoint?: string; } @@ -123,7 +102,7 @@ export interface LogsQueryOptions extends OperationOptions { // @public export interface LogsQueryResult { - error?: ErrorInfo; + error?: LogsErrorInfo; statistics?: Record; status: LogsQueryResultStatus; tables: LogsTable[]; @@ -131,7 +110,7 @@ export interface LogsQueryResult { } // @public -export type LogsQueryResultStatus = "Partial" | "Success" | "Failed"; +export type LogsQueryResultStatus = "PartialFailure" | "Success" | "Failure"; // @public export interface LogsTable { @@ -160,8 +139,8 @@ export interface Metric { // @public export interface MetricAvailability { + granularity?: string; retention?: string; - timeGrain?: string; } // @public @@ -195,6 +174,7 @@ export interface MetricNamespace { // @public export interface MetricsClientOptions extends CommonClientOptions { + audience?: string; endpoint?: string; } @@ -202,9 +182,8 @@ export interface MetricsClientOptions extends CommonClientOptions { export class MetricsQueryClient { constructor(tokenCredential: TokenCredential, options?: MetricsClientOptions); listMetricDefinitions(resourceUri: string, options?: ListMetricDefinitionsOptions): PagedAsyncIterableIterator; - // Warning: (ae-forgotten-export) The symbol "MetricNamespace" needs to be exported by the entry point index.d.ts - listMetricNamespaces(resourceUri: string, options?: ListMetricNamespacesOptions): PagedAsyncIterableIterator; - query(resourceUri: string, metricNames: string[], options?: MetricsQueryOptions): Promise; + listMetricNamespaces(resourceUri: string, options?: ListMetricNamespacesOptions): PagedAsyncIterableIterator; + queryResource(resourceUri: string, metricNames: string[], options?: MetricsQueryOptions): Promise; } // @public @@ -215,7 +194,7 @@ export interface MetricsQueryOptions extends OperationOptions { metricNamespace?: string; orderBy?: string; resultType?: ResultType; - timespan?: TimeInterval; + timespan?: QueryTimeInterval; top?: number; } @@ -227,7 +206,7 @@ export interface MetricsQueryResult { metrics: Metric[]; namespace?: string; resourceRegion?: string; - timespan: TimeInterval; + timespan: QueryTimeInterval; } // @public @@ -253,15 +232,12 @@ export interface QueryBatch { includeVisualization?: boolean; query: string; serverTimeoutInSeconds?: number; - timespan: TimeInterval; + timespan: QueryTimeInterval; workspaceId: string; } // @public -export type ResultType = "Data" | "Metadata"; - -// @public -export type TimeInterval = { +export type QueryTimeInterval = { startTime: Date; endTime: Date; } | { @@ -274,6 +250,9 @@ export type TimeInterval = { duration: string; }; +// @public +export type ResultType = "Data" | "Metadata"; + // @public export interface TimeSeriesElement { data?: MetricValue[]; diff --git a/sdk/monitor/monitor-query/samples-dev/logsQuery.ts b/sdk/monitor/monitor-query/samples-dev/logsQuery.ts index dff6a944da6a..3b1b3c98e262 100644 --- a/sdk/monitor/monitor-query/samples-dev/logsQuery.ts +++ b/sdk/monitor/monitor-query/samples-dev/logsQuery.ts @@ -32,13 +32,13 @@ export async function main() { includeQueryStatistics: true }; - const result = await logsQueryClient.query( + const result = await logsQueryClient.queryWorkspace( monitorWorkspaceId, kustoQuery, // The timespan is an ISO8601 formatted time (or interval). Some common aliases // are available (like OneDay, OneHour, FoutyEightHours, etc..) but any properly formatted ISO8601 // value is valid. - { duration: Durations.OneHour }, + { duration: Durations.oneHour }, queryLogsOptions ); diff --git a/sdk/monitor/monitor-query/samples-dev/logsQueryMultipleWorkspaces.ts b/sdk/monitor/monitor-query/samples-dev/logsQueryMultipleWorkspaces.ts index 73102d386d62..e47c45f830f6 100644 --- a/sdk/monitor/monitor-query/samples-dev/logsQueryMultipleWorkspaces.ts +++ b/sdk/monitor/monitor-query/samples-dev/logsQueryMultipleWorkspaces.ts @@ -35,13 +35,13 @@ export async function main() { additionalWorkspaces: [additionalWorkspaces1, additionalWorkspaces2] }; - const result = await logsQueryClient.query( + const result = await logsQueryClient.queryWorkspace( monitorWorkspaceId, kustoQuery, // The timespan is an ISO8601 formatted time (or interval). Some common aliases // are available (like durationOf1Day, durationOf1Hour, durationOf48Hours, etc..) but any properly formatted ISO8601 // value is valid. - { duration: Durations.OneHour }, + { duration: Durations.oneHour }, queryLogsOptions ); diff --git a/sdk/monitor/monitor-query/samples-dev/metricsQuery.ts b/sdk/monitor/monitor-query/samples-dev/metricsQuery.ts index 55c367036fb4..297aa14d19f7 100644 --- a/sdk/monitor/monitor-query/samples-dev/metricsQuery.ts +++ b/sdk/monitor/monitor-query/samples-dev/metricsQuery.ts @@ -32,9 +32,9 @@ export async function main() { if (metricNames.length > 0) { console.log(`Picking an example list of metrics to query: ${metricNames}`); - const metricsResponse = await metricsQueryClient.query(metricsResourceId, metricNames, { + const metricsResponse = await metricsQueryClient.queryResource(metricsResourceId, metricNames, { granularity: "PT1M", - timespan: { duration: Durations.FiveMinutes } + timespan: { duration: Durations.fiveMinutes } }); console.log( diff --git a/sdk/monitor/monitor-query/src/index.ts b/sdk/monitor/monitor-query/src/index.ts index 8ff2344e165a..9e29250b8108 100644 --- a/sdk/monitor/monitor-query/src/index.ts +++ b/sdk/monitor/monitor-query/src/index.ts @@ -16,7 +16,7 @@ export { LogsTable, LogsColumn, LogsQueryResultStatus, - ErrorInfo, + LogsErrorInfo, BatchError, AggregateBatchError } from "./models/publicLogsModels"; @@ -33,11 +33,12 @@ export { MetricsQueryOptions, MetricsQueryResult, TimeSeriesElement, - MetricNamespace + MetricNamespace, + MetricAvailability } from "./models/publicMetricsModels"; export { Durations } from "./models/constants"; -export { TimeInterval } from "./models/timeInterval"; +export { QueryTimeInterval } from "./models/timeInterval"; // // LogsClient: generated exports // @@ -45,8 +46,7 @@ export { TimeInterval } from "./models/timeInterval"; export { // TODO: these are the generated model names. We probably want to run them // through a manual review to make them consistent with style. - LogsColumnType, - ErrorDetail + LogsColumnType } from "./generated/logquery/src"; // @@ -60,9 +60,5 @@ export { MetricUnit } from "./generated/metrics/src"; -export { - AggregationType, - MetricAvailability, - MetricClass -} from "./generated/metricsdefinitions/src"; +export { AggregationType, MetricClass } from "./generated/metricsdefinitions/src"; export { NamespaceClassification } from "./generated/metricsnamespaces/src"; diff --git a/sdk/monitor/monitor-query/src/internal/modelConverters.ts b/sdk/monitor/monitor-query/src/internal/modelConverters.ts index 88fd302c5615..17c6f81948d9 100644 --- a/sdk/monitor/monitor-query/src/internal/modelConverters.ts +++ b/sdk/monitor/monitor-query/src/internal/modelConverters.ts @@ -40,14 +40,15 @@ import { Metric, MetricDefinition, TimeSeriesElement, - createMetricsQueryResult + createMetricsQueryResult, + MetricAvailability } from "../models/publicMetricsModels"; import { FullOperationResponse } from "@azure/core-client"; import { convertIntervalToTimeIntervalObject, convertTimespanToInterval } from "../timespanConversion"; -import { ErrorInfo, LogsQueryResult } from "../models/publicLogsModels"; +import { LogsErrorInfo, LogsQueryResult } from "../models/publicLogsModels"; /** * @internal @@ -137,11 +138,11 @@ export function convertResponseForQueryBatch( for (let i = 0; i < resultsCount; i++) { const result = newResponse.results[i]; if (result.error && result.tables) { - result.status = "Partial"; + result.status = "PartialFailure"; } else if (result.tables) { result.status = "Success"; } else { - result.status = "Failed"; + result.status = "Failure"; } } (newResponse as any)["__fixApplied"] = fixApplied; @@ -309,7 +310,7 @@ export function convertResponseForMetricsDefinitions( generatedResponse: Array ): Array { const definitions: Array = generatedResponse?.map((genDef) => { - const { name, dimensions, displayDescription, ...rest } = genDef; + const { name, dimensions, displayDescription, metricAvailabilities, ...rest } = genDef; const response: MetricDefinition = { ...rest @@ -322,6 +323,18 @@ export function convertResponseForMetricsDefinitions( response.name = name.value; } + const mappedMetricAvailabilities: + | Array + | undefined = metricAvailabilities?.map((genMetricAvail) => { + return { + granularity: genMetricAvail.timeGrain, + retention: genMetricAvail.retention + }; + }); + + if (mappedMetricAvailabilities) { + response.metricAvailabilities = mappedMetricAvailabilities; + } const mappedDimensions = dimensions?.map((dim) => dim.value); if (mappedDimensions) { @@ -422,12 +435,17 @@ export function convertBatchQueryResponseHelper( } } -export function mapError(error?: GeneratedErrorInfo): ErrorInfo | undefined { +export function mapError(error?: GeneratedErrorInfo): LogsErrorInfo | undefined { if (error) { + let innermostError = error; + while (innermostError.innerError) { + innermostError = innermostError.innerError; + } + return { - ...error, name: "Error", - innerError: mapError(error.innerError) + code: error.code, + message: `${error.message}. ${innermostError.message}` }; } return undefined; diff --git a/sdk/monitor/monitor-query/src/logsQueryClient.ts b/sdk/monitor/monitor-query/src/logsQueryClient.ts index 14a0a0466b57..f8ba5f34fa2d 100644 --- a/sdk/monitor/monitor-query/src/logsQueryClient.ts +++ b/sdk/monitor/monitor-query/src/logsQueryClient.ts @@ -12,7 +12,7 @@ import { LogsQueryResult, AggregateBatchError, BatchError, - ErrorInfo + LogsErrorInfo } from "./models/publicLogsModels"; import { @@ -23,7 +23,7 @@ import { } from "./internal/modelConverters"; import { formatPreferHeader } from "./internal/util"; import { CommonClientOptions, FullOperationResponse, OperationOptions } from "@azure/core-client"; -import { TimeInterval } from "./models/timeInterval"; +import { QueryTimeInterval } from "./models/timeInterval"; import { convertTimespanToInterval } from "./timespanConversion"; const defaultMonitorScope = "https://api.loganalytics.io/.default"; @@ -38,13 +38,11 @@ export interface LogsQueryClientOptions extends CommonClientOptions { endpoint?: string; /** - * The authentication scopes to use when getting authentication tokens. - * + * Gets or sets the audience to use for authentication with Azure Active Directory. + * The authentication scope will be set from this audience. * Defaults to 'https://api.loganalytics.io/.default' */ - credentialOptions?: { - credentialScopes?: string | string[]; - }; + audience?: string; } /** @@ -60,20 +58,18 @@ export class LogsQueryClient { * @param options - Options for the LogsClient. */ constructor(tokenCredential: TokenCredential, options?: LogsQueryClientOptions) { - // This client defaults to using 'https://api.loganalytics.io/v1' as the + // This client defaults to using 'https://api.loganalytics.io/' as the // host. - + const credentialOptions = { + credentialScopes: options?.audience + }; this._logAnalytics = new AzureLogAnalytics({ ...options, $host: options?.endpoint, endpoint: options?.endpoint, - credentialScopes: options?.credentialOptions?.credentialScopes ?? defaultMonitorScope, + credentialScopes: credentialOptions?.credentialScopes ?? defaultMonitorScope, credential: tokenCredential }); - // const scope = options?.scopes ?? defaultMonitorScope; - // this._logAnalytics.pipeline.addPolicy( - // bearerTokenAuthenticationPolicy({ scopes: scope, credential: tokenCredential }) - // ); } /** @@ -86,10 +82,11 @@ export class LogsQueryClient { * @param options - Options to adjust various aspects of the request. * @returns The result of the query. */ - async query( + async queryWorkspace( workspaceId: string, query: string, - timespan: TimeInterval, + timespan: QueryTimeInterval, + // eslint-disable-next-line @azure/azure-sdk/ts-naming-options options?: LogsQueryOptions ): Promise { let timeInterval: string = ""; @@ -132,13 +129,13 @@ export class LogsQueryClient { } else { // result.tables is always present in single query response, even is there is error if (result.tables.length === 0) { - result.status = "Failed"; + result.status = "Failure"; } else { - result.status = "Partial"; + result.status = "PartialFailure"; } } if (options?.throwOnAnyFailure && result.status !== "Success") { - throw new BatchError(result.error as ErrorInfo); + throw new BatchError(result.error as LogsErrorInfo); } return result; } @@ -164,7 +161,7 @@ export class LogsQueryClient { const errorResults = result.results .filter((it) => it.status !== "Success") .map((x) => x.error); - const batchErrorList = errorResults.map((x) => new BatchError(x as ErrorInfo)); + const batchErrorList = errorResults.map((x) => new BatchError(x as LogsErrorInfo)); throw new AggregateBatchError(batchErrorList); } return result; diff --git a/sdk/monitor/monitor-query/src/metricsQueryClient.ts b/sdk/monitor/monitor-query/src/metricsQueryClient.ts index 4ce8b61198c1..b5e6fc1a78b0 100644 --- a/sdk/monitor/monitor-query/src/metricsQueryClient.ts +++ b/sdk/monitor/monitor-query/src/metricsQueryClient.ts @@ -9,7 +9,8 @@ import { ListMetricNamespacesOptions, MetricsQueryOptions, MetricsQueryResult, - MetricDefinition + MetricDefinition, + MetricNamespace } from "./models/publicMetricsModels"; import { @@ -22,7 +23,6 @@ import { } from "./generated/metricsdefinitions/src"; import { KnownApiVersion20171201Preview as MetricNamespacesApiVersion, - MetricNamespace, MonitorManagementClient as GeneratedMetricsNamespacesClient } from "./generated/metricsnamespaces/src"; import { @@ -33,12 +33,20 @@ import { convertResponseForMetricsDefinitions } from "./internal/modelConverters"; +const defaultMetricsScope = "https://management.azure.com/.default"; + /** * Options for the MetricsQueryClient. */ export interface MetricsQueryClientOptions extends CommonClientOptions { /** Overrides client endpoint. */ endpoint?: string; + /** + * Gets or sets the audience to use for authentication with Azure Active Directory. + * The authentication scope will be set from this audience. + * Defaults to "https://management.azure.com/.default" + */ + audience?: string; } /** @@ -55,11 +63,15 @@ export class MetricsQueryClient { * @param options - Options for the client like controlling request retries. */ constructor(tokenCredential: TokenCredential, options?: MetricsQueryClientOptions) { + const credentialOptions = { + credentialScopes: options?.audience + }; + const serviceClientOptions = { ...options, $host: options?.endpoint, endpoint: options?.endpoint, - credentialScopes: formatScope(options?.endpoint), + credentialScopes: credentialOptions?.credentialScopes ?? defaultMetricsScope, credential: tokenCredential }; @@ -86,10 +98,10 @@ export class MetricsQueryClient { * @param options - Options for querying metrics. * @returns A response containing metrics. */ - async query( + async queryResource( resourceUri: string, metricNames: string[], - options?: MetricsQueryOptions + options?: MetricsQueryOptions // eslint-disable-line @azure/azure-sdk/ts-naming-options ): Promise { const response = await this._metricsClient.metrics.list( resourceUri, @@ -271,15 +283,3 @@ export class MetricsQueryClient { }; } } - -function formatScope(endpoint: string | undefined): string { - if (endpoint) { - if (endpoint.endsWith("/")) { - endpoint += "/"; - } - - return `${endpoint}/.default`; - } else { - return "https://management.azure.com/.default"; - } -} diff --git a/sdk/monitor/monitor-query/src/models/constants.ts b/sdk/monitor/monitor-query/src/models/constants.ts index 6b4c48b7ab13..4a8ccf7da5b7 100644 --- a/sdk/monitor/monitor-query/src/models/constants.ts +++ b/sdk/monitor/monitor-query/src/models/constants.ts @@ -12,17 +12,17 @@ export const Durations = { /** Alias for ISO8601 value 'P2D' */ twoDays: "P2D", /** Alias for ISO8601 value 'P1D' */ - OneDay: "P1D", + oneDay: "P1D", /** Alias for ISO8601 value 'PT1H' */ - OneHour: "PT1H", + oneHour: "PT1H", /** Alias for ISO8601 value 'PT4H' */ - FourHours: "PT4H", + fourHours: "PT4H", /** Alias for ISO8601 value 'P1D' */ - TwentyFourHours: "P1D", + twentyFourHours: "P1D", /** Alias for ISO8601 value 'P2D' */ - FourtyEightHours: "P2D", + fourtyEightHours: "P2D", /** Alias for ISO8601 value 'PT30M' */ - ThirtyMinutes: "PT30M", + thirtyMinutes: "PT30M", /** Alias for ISO8601 value 'PT5M' */ - FiveMinutes: "PT5M" + fiveMinutes: "PT5M" } as const; diff --git a/sdk/monitor/monitor-query/src/models/publicLogsModels.ts b/sdk/monitor/monitor-query/src/models/publicLogsModels.ts index cdce9e3dfac2..cc01e1392873 100644 --- a/sdk/monitor/monitor-query/src/models/publicLogsModels.ts +++ b/sdk/monitor/monitor-query/src/models/publicLogsModels.ts @@ -2,8 +2,8 @@ // Licensed under the MIT license. import { OperationOptions } from "@azure/core-client"; -import { ErrorDetail, LogsColumnType } from "../generated/logquery/src"; -import { TimeInterval } from "./timeInterval"; +import { LogsColumnType } from "../generated/logquery/src"; +import { QueryTimeInterval } from "./timeInterval"; // https://dev.loganalytics.io/documentation/Using-the-API/RequestOptions // https://dev.loganalytics.io/documentation/Using-the-API/Timeouts @@ -53,46 +53,28 @@ export interface QueryStatistics { } /** The code and message for an error. */ -export interface ErrorInfo extends Error { +export interface LogsErrorInfo extends Error { /** A machine readable error code. */ code: string; - /** A human readable error message. */ - message: string; - /** error details. */ - details?: ErrorDetail[]; - /** Inner error details if they exist. */ - innerError?: ErrorInfo; - /** Additional properties that can be provided on the error info object */ - additionalProperties?: Record; } /** Batch Error class for type of each error item in the {@link AggregateBatchError} list returned in logs query batch API */ -export class BatchError extends Error implements ErrorInfo { +export class BatchError extends Error implements LogsErrorInfo { /** A machine readable error code. */ code: string; - /** A human readable error message. */ - message: string; - /** error details. */ - details?: ErrorDetail[]; - /** Inner error details if they exist. */ - innerError?: ErrorInfo; - /** Additional properties that can be provided on the error info object */ - additionalProperties?: Record; - - constructor(errorInfo: ErrorInfo) { + + constructor(errorInfo: LogsErrorInfo) { super(); this.name = "Error"; this.code = errorInfo.code; this.message = errorInfo.message; - this.details = errorInfo.details; - this.innerError = errorInfo.innerError; - this.additionalProperties = errorInfo.additionalProperties; } } /** AggregateBatchError type for errors returned in logs query batch API*/ export class AggregateBatchError extends Error { + /** Represents list of errors if thrown for the queries executed in the queryBatch operation */ errors: BatchError[]; - constructor(errors: ErrorInfo[]) { + constructor(errors: LogsErrorInfo[]) { super(); this.errors = errors.map((x) => new BatchError(x)); } @@ -105,7 +87,7 @@ export interface LogsQueryResult { /** Populated results from the query. */ tables: LogsTable[]; /** error information for partial errors or failed queries */ - error?: ErrorInfo; + error?: LogsErrorInfo; /** Indicates if a query succeeded or failed or partially failed. * Represented by "Partial" | "Success" | "Failed". * For partially failed queries, users can find data in "tables" attribute @@ -137,7 +119,7 @@ export interface QueryBatch { /** The query to execute. */ query: string; /** The timespan over which to query data. This timespan is applied in addition to any that are specified in the query expression. */ - timespan: TimeInterval; + timespan: QueryTimeInterval; /** * A list of workspaces that are included in the query, except for the one set as the `workspaceId` parameter * These may consist of the following identifier formats: @@ -170,7 +152,7 @@ export interface LogsQueryBatchResult { /** Populated results from the query */ tables?: LogsTable[]; /** error information for partial errors or failed queries */ - error?: ErrorInfo; + error?: LogsErrorInfo; /** Indicates if a query succeeded or failed or partially failed. * Represented by "Partial" | "Success" | "Failed". * For partially failed queries, users can find data in "tables" attribute @@ -187,7 +169,7 @@ export interface LogsQueryBatchResult { * Represented by "Partial" | "Success" | "Failed". * For partially failed queries, users can find data in "tables" attribute * and error information in "error" attribute */ -export type LogsQueryResultStatus = "Partial" | "Success" | "Failed"; +export type LogsQueryResultStatus = "PartialFailure" | "Success" | "Failure"; /** Contains the columns and rows for one table in a query response. */ export interface LogsTable { diff --git a/sdk/monitor/monitor-query/src/models/publicMetricsModels.ts b/sdk/monitor/monitor-query/src/models/publicMetricsModels.ts index f5ac71ec384f..f9fa36f1c9c5 100644 --- a/sdk/monitor/monitor-query/src/models/publicMetricsModels.ts +++ b/sdk/monitor/monitor-query/src/models/publicMetricsModels.ts @@ -8,10 +8,9 @@ import { MetricUnit, MetricClass, AggregationType, - MetricAvailability, NamespaceClassification } from ".."; -import { TimeInterval } from "./timeInterval"; +import { QueryTimeInterval } from "./timeInterval"; /** * Options used when querying metrics. @@ -31,7 +30,7 @@ export interface MetricsQueryOptions extends OperationOptions { */ granularity?: string; /** The enclosing timespan for metrics. */ - timespan?: TimeInterval; + timespan?: QueryTimeInterval; /** The list of aggregation types (comma separated) to retrieve. */ aggregations?: AggregationType[]; /** @@ -102,7 +101,7 @@ export interface MetricsQueryResult { /** The integer value representing the cost of the query, for data case. */ cost?: number; /** The timespan for which the data was retrieved. Its value consists of two datetimes concatenated, separated by '/'. This may be adjusted in the future and returned back from what was originally requested. */ - timespan: TimeInterval; + timespan: QueryTimeInterval; /** The interval (window size) for which the metric data was returned in. This may be adjusted in the future and returned back from what was originally requested. This is not present if a metadata request was made. */ granularity?: string; /** The namespace of the metrics been queried */ @@ -188,3 +187,11 @@ export interface MetricDefinition { /** the name and the display name of the dimension, i.e. it is a localizable string. */ dimensions?: string[]; } + +/** Metric availability specifies the time grain (aggregation interval or frequency) and the retention period for that time grain. */ +export interface MetricAvailability { + /** the time grain specifies the aggregation interval for the metric. Expressed as a duration 'PT1M', 'P1D', etc. */ + granularity?: string; + /** the retention period for the metric at the specified granularity. Expressed as a duration 'PT1M', 'P1D', etc. */ + retention?: string; +} diff --git a/sdk/monitor/monitor-query/src/models/timeInterval.ts b/sdk/monitor/monitor-query/src/models/timeInterval.ts index 3971662f6a80..af6d2d23a142 100644 --- a/sdk/monitor/monitor-query/src/models/timeInterval.ts +++ b/sdk/monitor/monitor-query/src/models/timeInterval.ts @@ -11,7 +11,7 @@ * - start time, duration * - duration, end time */ -export type TimeInterval = +export type QueryTimeInterval = | { /** * Start time for time interval diff --git a/sdk/monitor/monitor-query/src/timespanConversion.ts b/sdk/monitor/monitor-query/src/timespanConversion.ts index 5d1b303e3f2e..9e54606ea3e0 100644 --- a/sdk/monitor/monitor-query/src/timespanConversion.ts +++ b/sdk/monitor/monitor-query/src/timespanConversion.ts @@ -1,9 +1,9 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -import { TimeInterval } from "./models/timeInterval"; +import { QueryTimeInterval } from "./models/timeInterval"; -export function convertTimespanToInterval(timespan: TimeInterval): string { +export function convertTimespanToInterval(timespan: QueryTimeInterval): string { if (isObjectWithProperties(timespan, ["startTime", "endTime", "duration"])) { throw new TypeError("Invalid Timespan - contains startTime, endTime, and duration."); } @@ -21,7 +21,7 @@ export function convertTimespanToInterval(timespan: TimeInterval): string { throw new TypeError("Invalid Timespan - no valid fields assigned."); } -export function convertIntervalToTimeIntervalObject(timespan: string): TimeInterval { +export function convertIntervalToTimeIntervalObject(timespan: string): QueryTimeInterval { if (timespan.includes("/")) { const intervalUnits: string[] = timespan.split("/"); if (Date.parse(intervalUnits[0]) && Date.parse(intervalUnits[2])) { diff --git a/sdk/monitor/monitor-query/test/internal/unit/logsQueryClient.unittest.spec.ts b/sdk/monitor/monitor-query/test/internal/unit/logsQueryClient.unittest.spec.ts index 4b3f0def9eed..dc3aa15db757 100644 --- a/sdk/monitor/monitor-query/test/internal/unit/logsQueryClient.unittest.spec.ts +++ b/sdk/monitor/monitor-query/test/internal/unit/logsQueryClient.unittest.spec.ts @@ -30,16 +30,14 @@ describe("LogsQueryClient unit tests", () => { const client = new LogsQueryClient(tokenCredential, { endpoint: "https://customEndpoint1", - credentialOptions: { - credentialScopes: "https://customscopes1/" - } + audience: "https://customscopes1/" }); assert.equal(client["_logAnalytics"].$host, "https://customEndpoint1"); assert.equal(client["_logAnalytics"]["_baseUri"], "https://customEndpoint1"); try { - await client.query("workspaceId", "query", { duration: Durations.FiveMinutes }); + await client.queryWorkspace("workspaceId", "query", { duration: Durations.fiveMinutes }); assert.fail("Should have thrown"); } catch (err) { assert.deepNestedInclude(err, { diff --git a/sdk/monitor/monitor-query/test/internal/unit/modelConverters.unittest.spec.ts b/sdk/monitor/monitor-query/test/internal/unit/modelConverters.unittest.spec.ts index 9030dffdc453..ae48fa471b73 100644 --- a/sdk/monitor/monitor-query/test/internal/unit/modelConverters.unittest.spec.ts +++ b/sdk/monitor/monitor-query/test/internal/unit/modelConverters.unittest.spec.ts @@ -34,7 +34,7 @@ describe("Model unit tests", () => { { query: "the kusto query", workspaceId: "the primary workspace id", - timespan: { duration: Durations.TwentyFourHours } + timespan: { duration: Durations.twentyFourHours } } ]); @@ -46,7 +46,7 @@ describe("Model unit tests", () => { headers: undefined, body: { query: "the kusto query", - timespan: Durations.TwentyFourHours + timespan: Durations.twentyFourHours } } ] @@ -58,11 +58,11 @@ describe("Model unit tests", () => { { query: "", workspaceId: "", - timespan: { duration: Durations.TwentyFourHours } + timespan: { duration: Durations.twentyFourHours } }, { query: "the kusto query", - timespan: { duration: Durations.FiveMinutes }, + timespan: { duration: Durations.fiveMinutes }, workspaceId: "the primary workspace id", includeQueryStatistics: true, serverTimeoutInSeconds: 100, diff --git a/sdk/monitor/monitor-query/test/public/logsQueryClient.spec.ts b/sdk/monitor/monitor-query/test/public/logsQueryClient.spec.ts index fa9dc4d1f6a0..a18d8e422782 100644 --- a/sdk/monitor/monitor-query/test/public/logsQueryClient.spec.ts +++ b/sdk/monitor/monitor-query/test/public/logsQueryClient.spec.ts @@ -38,8 +38,8 @@ describe("LogsQueryClient live tests", function() { try { // TODO: there is an error details in the query, but when I run an invalid query it // throws (and ErrorDetails are just present in the exception.) - await createClient().query(monitorWorkspaceId, kustoQuery, { - duration: Durations.OneDay + await createClient().queryWorkspace(monitorWorkspaceId, kustoQuery, { + duration: Durations.oneDay }); assert.fail("Should have thrown an exception"); } catch (err) { @@ -80,12 +80,12 @@ describe("LogsQueryClient live tests", function() { // query has timed out on purpose. it("serverTimeoutInSeconds", async () => { try { - await createClient({ maxRetries: 0, retryDelayInMs: 0, maxRetryDelayInMs: 0 }).query( + await createClient({ maxRetries: 0, retryDelayInMs: 0, maxRetryDelayInMs: 0 }).queryWorkspace( monitorWorkspaceId, // slow query suggested by Pavel. "range x from 1 to 10000000000 step 1 | count", { - duration: Durations.TwentyFourHours + duration: Durations.twentyFourHours }, { // the query above easily takes longer than 1 second. @@ -123,11 +123,11 @@ describe("LogsQueryClient live tests", function() { }); it("includeQueryStatistics", async () => { - const results = await createClient().query( + const results = await createClient().queryWorkspace( monitorWorkspaceId, "AppEvents | limit 1", { - duration: Durations.TwentyFourHours + duration: Durations.twentyFourHours }, { includeQueryStatistics: true @@ -141,11 +141,11 @@ describe("LogsQueryClient live tests", function() { }); it("includeRender/includeVisualization", async () => { - const results = await createClient().query( + const results = await createClient().queryWorkspace( monitorWorkspaceId, `datatable (s: string, i: long) [ "a", 1, "b", 2, "c", 3 ] | render columnchart with (title="the chart title", xtitle="the x axis title")`, { - duration: Durations.TwentyFourHours + duration: Durations.twentyFourHours }, { includeVisualization: true @@ -174,8 +174,8 @@ describe("LogsQueryClient live tests", function() { dynamiccolumn=print_6 `; - const results = await createClient().query(monitorWorkspaceId, constantsQuery, { - duration: Durations.FiveMinutes + const results = await createClient().queryWorkspace(monitorWorkspaceId, constantsQuery, { + duration: Durations.fiveMinutes }); const table = results.tables[0]; @@ -260,7 +260,7 @@ describe("LogsQueryClient live tests", function() { { workspaceId: monitorWorkspaceId, query: constantsQuery, - timespan: { duration: Durations.FiveMinutes } + timespan: { duration: Durations.fiveMinutes } } ]); @@ -275,7 +275,7 @@ describe("LogsQueryClient live tests", function() { throw new Error(JSON.stringify(result.results?.[0].error)); } - if (result.results?.[0].status === "Partial") { + if (result.results?.[0].status === "PartialFailure") { throw new Error( JSON.stringify({ ...result.results?.[0].error, ...result.results?.[0].tables }) ); @@ -380,9 +380,13 @@ describe("LogsQueryClient live tests", function() { it("queryLogs (last day)", async () => { const kustoQuery = `AppDependencies | where Properties['testRunId'] == '${testRunId}'| project Kind=Properties["kind"], Name, Target, TestRunId=Properties['testRunId']`; - const singleQueryLogsResult = await createClient().query(monitorWorkspaceId, kustoQuery, { - duration: Durations.OneDay - }); + const singleQueryLogsResult = await createClient().queryWorkspace( + monitorWorkspaceId, + kustoQuery, + { + duration: Durations.oneDay + } + ); // TODO: the actual types aren't being deserialized (everything is coming back as 'string') // this is incorrect, it'll be updated. @@ -403,12 +407,12 @@ describe("LogsQueryClient live tests", function() { { workspaceId: monitorWorkspaceId, query: `AppDependencies | where Properties['testRunId'] == '${testRunId}'| project Kind=Properties["kind"], Name, Target, TestRunId=Properties['testRunId']`, - timespan: { duration: Durations.TwentyFourHours } + timespan: { duration: Durations.twentyFourHours } }, { workspaceId: monitorWorkspaceId, query: `AppDependencies | where Properties['testRunId'] == '${testRunId}' | count`, - timespan: { duration: Durations.TwentyFourHours }, + timespan: { duration: Durations.twentyFourHours }, includeQueryStatistics: true, serverTimeoutInSeconds: 60 * 10 } @@ -456,8 +460,8 @@ describe("LogsQueryClient live tests", function() { const client = createClient(); for (let i = 0; i < args.maxTries; ++i) { - const result = await client.query(monitorWorkspaceId, query, { - duration: Durations.TwentyFourHours + const result = await client.queryWorkspace(monitorWorkspaceId, query, { + duration: Durations.twentyFourHours }); const numRows = result.tables?.[0].rows?.length; diff --git a/sdk/monitor/monitor-query/test/public/metricsQueryClient.spec.ts b/sdk/monitor/monitor-query/test/public/metricsQueryClient.spec.ts index abc451b8240a..ed89f42bf45e 100644 --- a/sdk/monitor/monitor-query/test/public/metricsQueryClient.spec.ts +++ b/sdk/monitor/monitor-query/test/public/metricsQueryClient.spec.ts @@ -25,7 +25,11 @@ describe("MetricsClient live tests", function() { let metricDefinitionsLength = 0; while (!result.done) { // you can only query 20 metrics at a time. - const resultQuery = await metricsQueryClient.query(resourceId, [result.value.name || ""], {}); + const resultQuery = await metricsQueryClient.queryResource( + resourceId, + [result.value.name || ""], + {} + ); assert(resultQuery); assert(resultQuery.granularity); assert.isNotEmpty(resultQuery.metrics); @@ -48,9 +52,9 @@ describe("MetricsClient live tests", function() { i++; if (i % 20 === 0 || i === metricDefinitionsLength) { - const newResults = await metricsQueryClient.query(resourceId, definitionNames, { + const newResults = await metricsQueryClient.queryResource(resourceId, definitionNames, { timespan: { - duration: Durations.TwentyFourHours + duration: Durations.twentyFourHours } }); assert.ok(newResults); @@ -64,11 +68,11 @@ describe("MetricsClient live tests", function() { assert.isNotEmpty(firstMetricDefinition.name); assert.isNotEmpty(firstMetricDefinition.namespace); - const individualMetricWithNamespace = metricsQueryClient.query( + const individualMetricWithNamespace = metricsQueryClient.queryResource( resourceId, [firstMetricDefinition.name!], { - timespan: { duration: Durations.TwentyFourHours }, + timespan: { duration: Durations.twentyFourHours }, metricNamespace: firstMetricDefinition.namespace } );