This commit is contained in:
KarishmaGhiya 2021-09-01 18:16:05 -07:00 коммит произвёл GitHub
Родитель b832d302a7
Коммит d5893c42fe
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
23 изменённых файлов: 909 добавлений и 629 удалений

Просмотреть файл

@ -127,27 +127,36 @@ Each set of metric values is a time series with the following characteristics:
The [`MetricsQueryClient`][msdocs_metrics_client] allows you to query metrics.
#### Resource URI of a resource
The resource URI must be that of the resource for which metrics are being queried. It's normally of the format `/subscriptions/<id>/resourceGroups/<rg-name>/providers/<source>/topics/<resource-name>`.
To find the resource URI:
1. Navigate to your resource's page in the Azure portal.
2. From the **Overview** blade, select the **JSON View** link.
3. In the resulting JSON, copy the value of the `id` property.
## Examples
### Querying logs
The `LogsQueryClient` can be used to query a Monitor workspace using the Kusto Query language. The timespan can be specified as a string in an ISO8601 duration format.
The `LogsQueryClient` can be used to query a Monitor workspace using the [Kusto Query Language](https://docs.microsoft.com/azure/data-explorer/kusto/query). The `timespan.duration` can be specified as a string in an ISO8601 duration format.
You can use the `Durations` constants provided for some commonly used ISO8601 durations.
```ts
const { LogsQueryClient,Durations } = require("@azure/monitor-query");
const { LogsQueryClient, Durations } = require("@azure/monitor-query");
const { DefaultAzureCredential } = require("@azure/identity");
g;
const azureLogAnalyticsWorkspaceId = "<the Workspace Id for your Azure Log Analytics resource>";
const logsQueryClient = new LogsQueryClient(new DefaultAzureCredential());
async function run() {
const kustoQuery = "AppEvents | limit 1";
const result = await logsQueryClient.queryLogs(
azureLogAnalyticsWorkspaceId,
kustoQuery,
Durations.last24Hours
);
const result = await logsQueryClient.query(azureLogAnalyticsWorkspaceId, kustoQuery, {
duration: Durations.TwentFourHours
});
const tablesFromResult = result.tables;
if (tablesFromResult == null) {
@ -174,12 +183,12 @@ run().catch((err) => console.log("ERROR:", err));
#### Handling the response for Logs Query
The `queryLogs` API returns the `QueryLogsResult`.
The `query` API for `LogsQueryClient` returns the `LogsQueryResult`.
Here is a heirarchy of the response:
Here is a hierarchy of the response:
```
QueryLogsResult
LogsQueryResult
|---statistics
|---visalization
|---error
@ -213,41 +222,20 @@ A full sample can be found [here](https://github.com/Azure/azure-sdk-for-js/blob
#### Set logs query timeout
```ts
// setting optional parameters
const queryLogsOptions: QueryLogsOptions = {
// explicitly control the amount of time the server can spend processing the query.
serverTimeoutInSeconds: 60
};
// setting optional parameters
const queryLogsOptions: LogsQueryOptions = {
// explicitly control the amount of time the server can spend processing the query.
serverTimeoutInSeconds: 60
};
const result = await logsQueryClient.queryLogs(
azureLogAnalyticsWorkspaceId,
kustoQuery,
Durations.last24Hours,
queryLogsOptions
);
const result = await logsQueryClient.query(
azureLogAnalyticsWorkspaceId,
kustoQuery,
{ duration: Durations.TwentyFourHours },
queryLogsOptions
);
const tablesFromResult = result.tables;
if (tablesFromResult == null) {
console.log(`No results for query '${kustoQuery}'`);
return;
}
console.log(`Results for query '${kustoQuery}'`);
// Formatting the table from results
for (const table of tablesFromResult) {
const columnHeaderString = table.columns
.map((column) => `${column.name}(${column.type}) `)
.join("| ");
console.log("| " + columnHeaderString);
for (const row of table.rows) {
const columnValuesString = row.map((columnValue) => `'${columnValue}' `).join("| ");
console.log("| " + columnValuesString);
}
}
}
const tablesFromResult = result.tables;
```
### Batch logs query
@ -262,35 +250,32 @@ export async function main() {
const tokenCredential = new DefaultAzureCredential();
const logsQueryClient = new LogsQueryClient(tokenCredential);
const queriesBatch: BatchQuery[] = [
const queriesBatch: QueryBatch[] = [
{
workspaceId: monitorWorkspaceId,
query: "AppEvents | project TimeGenerated, Name, AppRoleInstance | limit 1",
timespan: "P1D"
timespan: { duration: "P1D" }
},
{
workspaceId: monitorWorkspaceId,
query: "AzureActivity | summarize count()",
timespan: "PT1H"
timespan: { duration: "PT1H" }
},
{
workspaceId: monitorWorkspaceId,
query:
"AppRequests | take 10 | summarize avgRequestDuration=avg(DurationMs) by bin(TimeGenerated, 10m), _ResourceId",
timespan: "PT1H"
timespan: { duration: "PT1H" }
},
{
workspaceId: monitorWorkspaceId,
query: "AppRequests | take 2",
timespan: "PT1H"
timespan: { duration: "PT1H" },
includeQueryStatistics: true
}
];
const result = await logsQueryClient.queryLogsBatch({
queries: queriesBatch
});
const result = await logsQueryClient.queryBatch(queriesBatch);
if (result.results == null) {
throw new Error("No response for query");
}
@ -330,12 +315,12 @@ export async function main() {
#### Handling the response for Query Logs Batch
The `queryLogsBatch` API returns the `QueryLogsBatchResult`.
The `queryLogsBatch` API returns the `LogsQueryBatchResult`.
Here is a heirarchy of the response:
Here is a hierarchy of the response:
```
QueryLogsBatchResult
LogsQueryBatchResult
|---results (list of following objects)
|---id
|---status
@ -384,14 +369,6 @@ A full sample can be found [here](https://github.com/Azure/azure-sdk-for-js/blob
The following example gets metrics for an [Azure Metrics Advisor](https://docs.microsoft.com/azure/applied-ai-services/metrics-advisor/overview) subscription. The resource URI is that of a Metrics Advisor resource.
The resource URI must be that of the resource for which metrics are being queried. It's normally of the format `/subscriptions/<id>/resourceGroups/<rg-name>/providers/<source>/topics/<resource-name>`.
To find the resource URI:
1. Navigate to your resource's page in the Azure portal.
2. From the **Overview** blade, select the **JSON View** link.
3. In the resulting JSON, copy the value of the `id` property.
```ts
import { DefaultAzureCredential } from "@azure/identity";
import { Durations, Metric, MetricsQueryClient } from "@azure/monitor-query";
@ -421,7 +398,7 @@ export async function main() {
const metricsResponse = await metricsQueryClient.queryMetrics(
metricsResourceId,
Durations.last5Minutes,
{ duration: Durations.FiveMinutes },
{
metricNames: [firstMetric.name!],
interval: "PT1M"
@ -486,7 +463,7 @@ export async function main() {
const metricsResponse = await metricsQueryClient.queryMetrics(
metricsResourceId,
Durations.last5Minutes,
{ duration: Durations.FiveMinutes },
{
metricNames: ["MatchedEventCount"],
interval: "PT1M",
@ -534,7 +511,7 @@ The same log query can be executed across multiple Log Analytics workspaces. In
For example, the following query executes in three workspaces:
```ts
const queryLogsOptions: QueryLogsOptions = {
const queryLogsOptions: LogsQueryOptions = {
additionalWorkspaces: ["<workspace2>", "<workspace3>"]
};
@ -542,7 +519,7 @@ const kustoQuery = "AppEvents | limit 1";
const result = await logsQueryClient.queryLogs(
azureLogAnalyticsWorkspaceId,
kustoQuery,
Durations.last24Hours,
{ duration: Durations.TwentyFourHours },
queryLogsOptions
);
```

Просмотреть файл

@ -101,6 +101,7 @@
"@azure/core-tracing": "1.0.0-preview.13",
"@azure/core-client": "^1.0.0",
"@azure/core-rest-pipeline": "^1.1.0",
"@azure/core-paging": "^1.1.1",
"@azure/logger": "^1.0.0",
"tslib": "^2.2.0"
},

Просмотреть файл

@ -4,36 +4,27 @@
```ts
import { CommonClientOptions } from '@azure/core-client';
import { OperationOptions } from '@azure/core-client';
import { PagedAsyncIterableIterator } from '@azure/core-paging';
import { PipelineOptions } from '@azure/core-rest-pipeline';
import { TokenCredential } from '@azure/core-auth';
// @public
export type AggregationType = "None" | "Average" | "Count" | "Minimum" | "Maximum" | "Total";
// @public
export interface BatchQuery {
additionalWorkspaces?: string[];
includeQueryStatistics?: boolean;
includeVisualization?: boolean;
query: string;
serverTimeoutInSeconds?: number;
timespan: string;
workspaceId: string;
}
// @public
export const Durations: {
readonly last7Days: "P7D";
readonly last3Days: "P3D";
readonly last2Days: "P2D";
readonly lastDay: "P1D";
readonly lastHour: "PT1H";
readonly last4Hours: "PT4H";
readonly last24Hours: "P1D";
readonly last48Hours: "P2D";
readonly last30Minutes: "PT30M";
readonly last5Minutes: "PT5M";
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";
};
// @public
@ -56,44 +47,73 @@ export interface ErrorInfo {
}
// @public
export interface GetMetricDefinitionsOptions extends OperationOptions {
export interface ListMetricDefinitionsOptions extends OperationOptions {
metricNamespace?: string;
}
// @public
export interface GetMetricDefinitionsResult {
definitions: MetricDefinition[];
}
// @public
export interface GetMetricNamespacesOptions {
export interface ListMetricNamespacesOptions {
startTime?: string;
}
// @public
export interface GetMetricNamespacesResult {
namespaces: MetricNamespace[];
export interface LogsColumn {
name?: string;
type?: LogsColumnType;
}
// @public
export type LogsColumnType = string;
// @public
export class LogsQueryClient {
constructor(tokenCredential: TokenCredential, options?: LogsQueryClientOptions);
queryLogs(workspaceId: string, query: string, timespan: string, options?: QueryLogsOptions): Promise<QueryLogsResult>;
queryLogsBatch(batch: QueryLogsBatch, options?: QueryLogsBatchOptions): Promise<QueryLogsBatchResult>;
export type LogsQueryBatchOptions = OperationOptions;
// @public
export interface LogsQueryBatchResult {
results?: {
id?: string;
status?: number;
tables?: LogsTable[];
error?: ErrorInfo;
statistics?: Record<string, unknown>;
visualization?: Record<string, unknown>;
}[];
}
// @public
export interface LogsQueryClientOptions extends PipelineOptions {
export class LogsQueryClient {
constructor(tokenCredential: TokenCredential, options?: LogsQueryClientOptions);
query(workspaceId: string, query: string, timespan: TimeInterval, options?: LogsQueryOptions): Promise<LogsQueryResult>;
queryBatch(batch: QueryBatch[], options?: LogsQueryBatchOptions): Promise<LogsQueryBatchResult>;
}
// @public
export interface LogsQueryClientOptions extends CommonClientOptions {
credentialOptions?: {
credentialScopes?: string | string[];
};
endpoint?: string;
scopes?: string | string[];
}
// @public
export interface LogsQueryOptions extends OperationOptions {
additionalWorkspaces?: string[];
includeQueryStatistics?: boolean;
includeVisualization?: boolean;
serverTimeoutInSeconds?: number;
}
// @public
export interface LogsQueryResult {
error?: ErrorInfo;
statistics?: Record<string, unknown>;
tables: LogsTable[];
visualization?: Record<string, unknown>;
}
// @public
export interface LogsTable {
columns: MetricColumn[];
columns: LogsColumn[];
name: string;
rows: (Date | string | number | Record<string, unknown> | boolean)[][];
}
@ -106,7 +126,7 @@ export interface MetadataValue {
// @public
export interface Metric {
displayDescription?: string;
description?: string;
errorCode?: string;
id: string;
name: string;
@ -124,31 +144,11 @@ export interface MetricAvailability {
// @public
export type MetricClass = string;
// @public
export interface MetricColumn {
name?: string;
type?: LogsColumnType;
}
// @public
export interface MetricDefinition {
category?: string;
description?: string;
dimensions?: string[];
displayDescription?: string;
id?: string;
isDimensionRequired?: boolean;
metricAvailabilities?: MetricAvailability[];
name?: string;
primaryAggregationType?: AggregationType;
resourceId?: string;
unit?: MetricUnit;
}
// @public
export interface MetricDefinition {
category?: string;
dimensions?: string[];
displayDescription?: string;
id?: string;
isDimensionRequired?: boolean;
metricAvailabilities?: MetricAvailability[];
@ -165,14 +165,9 @@ export interface MetricDefinition {
export interface MetricNamespace {
classification?: NamespaceClassification;
id?: string;
name?: string;
properties?: MetricNamespaceName;
type?: string;
}
// @public
export interface MetricNamespaceName {
metricNamespaceName?: string;
name?: string;
type?: string;
}
// @public
@ -183,9 +178,32 @@ export interface MetricsClientOptions extends PipelineOptions {
// @public
export class MetricsQueryClient {
constructor(tokenCredential: TokenCredential, options?: MetricsClientOptions);
getMetricDefinitions(resourceUri: string, options?: GetMetricDefinitionsOptions): Promise<GetMetricDefinitionsResult>;
getMetricNamespaces(resourceUri: string, options?: GetMetricNamespacesOptions): Promise<GetMetricNamespacesResult>;
queryMetrics(resourceUri: string, timespan: string, options?: QueryMetricsOptions): Promise<QueryMetricsResult>;
listMetricDefinitions(resourceUri: string, options?: ListMetricDefinitionsOptions): PagedAsyncIterableIterator<MetricDefinition>;
// Warning: (ae-forgotten-export) The symbol "MetricNamespace" needs to be exported by the entry point index.d.ts
listMetricNamespaces(resourceUri: string, options?: ListMetricNamespacesOptions): PagedAsyncIterableIterator<MetricNamespace_2>;
query(resourceUri: string, metricNames: string[], options?: MetricsQueryOptions): Promise<MetricsQueryResult>;
}
// @public
export interface MetricsQueryOptions extends OperationOptions {
aggregations?: AggregationType[];
filter?: string;
granularity?: string;
metricNamespace?: string;
orderBy?: string;
resultType?: ResultType;
timespan?: TimeInterval;
top?: number;
}
// @public
export interface MetricsQueryResult {
cost?: number;
granularity?: string;
metrics: Metric[];
namespace?: string;
resourceRegion?: string;
timespan: string;
}
// @public
@ -205,66 +223,33 @@ export interface MetricValue {
export type NamespaceClassification = string;
// @public
export interface QueryLogsBatch {
queries: BatchQuery[];
}
// @public
export type QueryLogsBatchOptions = OperationOptions;
// @public
export interface QueryLogsBatchResult {
results?: {
id?: string;
status?: number;
tables?: LogsTable[];
error?: ErrorInfo;
statistics?: any;
visualization?: any;
}[];
}
// @public
export interface QueryLogsOptions extends OperationOptions {
export interface QueryBatch {
additionalWorkspaces?: string[];
includeQueryStatistics?: boolean;
includeVisualization?: boolean;
query: string;
serverTimeoutInSeconds?: number;
}
// @public
export interface QueryLogsResult {
error?: ErrorInfo;
statistics?: any;
tables: LogsTable[];
visualization?: any;
}
// @public
export interface QueryMetricsOptions extends OperationOptions {
aggregations?: string[];
filter?: string;
interval?: string;
metricNames?: string[];
metricNamespace?: string;
orderBy?: string;
resultType?: ResultType;
top?: number;
}
// @public
export interface QueryMetricsResult {
cost?: number;
interval?: string;
metrics: Metric[];
namespace?: string;
resourceRegion?: string;
timespan: string;
timespan?: TimeInterval;
workspaceId: string;
}
// @public
export type ResultType = "Data" | "Metadata";
// @public
export type TimeInterval = {
startTime: Date;
endTime: Date;
} | {
startTime: Date;
duration: string;
} | {
duration: string;
endTime: Date;
} | {
duration: string;
};
// @public
export interface TimeSeriesElement {
data?: MetricValue[];

Просмотреть файл

@ -6,7 +6,7 @@
*/
import { DefaultAzureCredential } from "@azure/identity";
import { Durations, LogsQueryClient, LogsTable, QueryLogsOptions } from "@azure/monitor-query";
import { Durations, LogsQueryClient, LogsTable, LogsQueryOptions } from "@azure/monitor-query";
import * as dotenv from "dotenv";
dotenv.config();
@ -23,8 +23,8 @@ export async function main() {
const kustoQuery =
"AppEvents | project TimeGenerated, Name, AppRoleInstance | order by TimeGenerated asc | limit 10";
console.log(`Running '${kustoQuery}' over the last 5 minutes`);
const queryLogsOptions: QueryLogsOptions = {
console.log(`Running '${kustoQuery}' over the last One Hour`);
const queryLogsOptions: LogsQueryOptions = {
// explicitly control the amount of time the server can spend processing the query.
serverTimeoutInSeconds: 60,
// optionally enable returning additional statistics about the query's execution.
@ -32,13 +32,13 @@ export async function main() {
includeQueryStatistics: true
};
const result = await logsQueryClient.queryLogs(
const result = await logsQueryClient.query(
monitorWorkspaceId,
kustoQuery,
// The timespan is an ISO8601 formatted time (or interval). Some common aliases
// are available (like lastDay, lastHour, last48Hours, etc..) but any properly formatted ISO8601
// are available (like OneDay, OneHour, FoutyEightHours, etc..) but any properly formatted ISO8601
// value is valid.
Durations.lastHour,
{ duration: Durations.OneHour },
queryLogsOptions
);
@ -50,7 +50,7 @@ export async function main() {
}
const executionTime =
result.statistics && result.statistics.query && result.statistics.query.executionTime;
result.statistics && result.statistics.query && (result.statistics.query as any).executionTime;
console.log(
`Results for query '${kustoQuery}', execution time: ${

Просмотреть файл

@ -25,30 +25,28 @@ export async function main() {
{
workspaceId: monitorWorkspaceId,
query: kqlQuery,
timespan: "P1D"
timespan: { duration: "P1D" }
},
{
workspaceId: monitorWorkspaceId,
query: "AzureActivity | summarize count()",
timespan: "PT1H"
timespan: { duration: "PT1H" }
},
{
workspaceId: monitorWorkspaceId,
query:
"AppRequests | take 10 | summarize avgRequestDuration=avg(DurationMs) by bin(TimeGenerated, 10m), _ResourceId",
timespan: "PT1H"
timespan: { duration: "PT1H" }
},
{
workspaceId: monitorWorkspaceId,
query: "AppRequests | take 2",
timespan: "PT1H",
timespan: { duration: "PT1H" },
includeQueryStatistics: true
}
];
const result = await logsQueryClient.queryLogsBatch({
queries: queriesBatch
});
const result = await logsQueryClient.queryBatch(queriesBatch);
if (result.results == null) {
throw new Error("No response for query");

Просмотреть файл

@ -6,7 +6,7 @@
*/
import { DefaultAzureCredential } from "@azure/identity";
import { Durations, LogsQueryClient, LogsTable, QueryLogsOptions } from "@azure/monitor-query";
import { Durations, LogsQueryClient, LogsTable, LogsQueryOptions } from "@azure/monitor-query";
import * as dotenv from "dotenv";
dotenv.config();
@ -26,7 +26,7 @@ export async function main() {
"AppEvents | project TimeGenerated, Name, AppRoleInstance | order by TimeGenerated asc | limit 10";
console.log(`Running '${kustoQuery}' over the last 5 minutes`);
const queryLogsOptions: QueryLogsOptions = {
const queryLogsOptions: LogsQueryOptions = {
// explicitly control the amount of time the server can spend processing the query.
serverTimeoutInSeconds: 60,
// optionally enable returning additional statistics about the query's execution.
@ -35,13 +35,13 @@ export async function main() {
additionalWorkspaces: [additionalWorkspaces1, additionalWorkspaces2]
};
const result = await logsQueryClient.queryLogs(
const result = await logsQueryClient.query(
monitorWorkspaceId,
kustoQuery,
// The timespan is an ISO8601 formatted time (or interval). Some common aliases
// are available (like lastDay, lastHour, last48Hours, etc..) but any properly formatted ISO8601
// are available (like durationOf1Day, durationOf1Hour, durationOf48Hours, etc..) but any properly formatted ISO8601
// value is valid.
Durations.lastHour,
{ duration: Durations.OneHour },
queryLogsOptions
);
@ -53,7 +53,7 @@ export async function main() {
}
const executionTime =
result.statistics && result.statistics.query && result.statistics.query.executionTime;
result.statistics && result.statistics.query && (result.statistics.query as any).executionTime;
console.log(
`Results for query '${kustoQuery}', execution time: ${

Просмотреть файл

@ -6,7 +6,7 @@
*/
import { DefaultAzureCredential } from "@azure/identity";
import { Durations, Metric, MetricsQueryClient } from "@azure/monitor-query";
import { Durations, Metric, MetricsQueryClient, MetricDefinition } from "@azure/monitor-query";
import * as dotenv from "dotenv";
dotenv.config();
@ -21,27 +21,25 @@ export async function main() {
throw new Error("METRICS_RESOURCE_ID must be set in the environment for this sample");
}
const result = await metricsQueryClient.getMetricDefinitions(metricsResourceId);
const iterator = metricsQueryClient.listMetricDefinitions(metricsResourceId);
let result = await iterator.next();
const firstMetric: MetricDefinition = result.value;
for (const definition of result.definitions) {
console.log(`Definition = ${definition.name}`);
while (!result.done) {
console.log(` metricDefinitions - ${result.value.id}, ${result.value.name}`);
result = await iterator.next();
}
console.log(`First Metric Definition = ${firstMetric.name}`);
const firstMetric = result.definitions[0];
console.log(`Picking an example metric to query: ${firstMetric.name!}`);
console.log(`Picking an example metric to query: ${firstMetric.name}`);
const metricsResponse = await metricsQueryClient.queryMetrics(
metricsResourceId,
Durations.last5Minutes,
{
metricNames: [firstMetric.name!],
interval: "PT1M"
}
);
const metricsResponse = await metricsQueryClient.query(metricsResourceId, [firstMetric.name!], {
granularity: "PT1M",
timespan: { duration: Durations.FiveMinutes }
});
console.log(
`Query cost: ${metricsResponse.cost}, interval: ${metricsResponse.interval}, time span: ${metricsResponse.timespan}`
`Query cost: ${metricsResponse.cost}, interval: ${metricsResponse.granularity}, time span: ${metricsResponse.timespan}`
);
const metrics: Metric[] = metricsResponse.metrics;

Просмотреть файл

@ -6,35 +6,34 @@
//
export { LogsQueryClientOptions, LogsQueryClient } from "./logsQueryClient";
export {
BatchQuery,
QueryLogsBatch,
QueryLogsBatchOptions,
QueryLogsBatchResult,
QueryLogsOptions,
QueryLogsResult,
QueryBatch,
LogsQueryBatchOptions,
LogsQueryBatchResult,
LogsQueryOptions,
LogsQueryResult,
// TODO: design issues around this still pending.
// QueryStatistics,
LogsTable
LogsTable,
LogsColumn
} from "./models/publicLogsModels";
export {
MetricsQueryClient,
MetricsQueryClientOptions as MetricsClientOptions
} from "./metricsQueryClient";
export {
GetMetricDefinitionsOptions,
GetMetricDefinitionsResult,
GetMetricNamespacesOptions,
GetMetricNamespacesResult,
ListMetricDefinitionsOptions,
ListMetricNamespacesOptions,
MetadataValue,
Metric,
MetricDefinition,
QueryMetricsOptions,
QueryMetricsResult,
TimeSeriesElement
MetricsQueryOptions,
MetricsQueryResult,
TimeSeriesElement,
MetricNamespace
} from "./models/publicMetricsModels";
export { Durations } from "./models/constants";
export { TimeInterval } from "./models/timeInterval";
//
// LogsClient: generated exports
//
@ -42,7 +41,6 @@ export { Durations } from "./models/constants";
export {
// TODO: these are the generated model names. We probably want to run them
// through a manual review to make them consistent with style.
Column as MetricColumn,
LogsColumnType,
ErrorDetail,
ErrorInfo
@ -64,8 +62,4 @@ export {
MetricAvailability,
MetricClass
} from "./generated/metricsdefinitions/src";
export {
MetricNamespace,
MetricNamespaceName,
NamespaceClassification
} from "./generated/metricsnamespaces/src";
export { NamespaceClassification } from "./generated/metricsnamespaces/src";

Просмотреть файл

@ -19,40 +19,41 @@ import {
import {
MetricDefinitionsListOptionalParams as GeneratedMetricDefinitionsListOptionalParams,
MetricDefinitionsListResponse as GeneratedMetricDefinitionsListResponse
MetricDefinition as GeneratedMetricDefinition
} from "../generated/metricsdefinitions/src";
import { MetricNamespacesListResponse as GeneratedMetricNamespacesListResponse } from "../generated/metricsnamespaces/src";
import { MetricNamespace as GeneratedMetricNamespace } from "../generated/metricsnamespaces/src";
import { formatPreferHeader } from "./util";
import {
BatchQuery,
GetMetricDefinitionsOptions,
GetMetricDefinitionsResult,
GetMetricNamespacesResult,
QueryBatch,
ListMetricDefinitionsOptions,
LogsTable,
QueryLogsBatch,
QueryLogsBatchResult,
QueryMetricsOptions,
QueryMetricsResult
LogsQueryBatchResult,
MetricsQueryOptions,
MetricsQueryResult
} from "../../src";
import { Metric, MetricDefinition, TimeSeriesElement } from "../models/publicMetricsModels";
import {
MetricNamespace,
Metric,
MetricDefinition,
TimeSeriesElement
} from "../models/publicMetricsModels";
import { FullOperationResponse } from "../../../../core/core-client/types/latest/core-client";
import { convertTimespanToInterval } from "../timespanConversion";
/**
* @internal
*/
export function convertRequestForQueryBatch(batch: QueryLogsBatch): GeneratedBatchRequest {
export function convertRequestForQueryBatch(batch: QueryBatch[]): GeneratedBatchRequest {
let id = 0;
const requests: GeneratedBatchQueryRequest[] = batch.queries.map((query: BatchQuery) => {
const body: QueryBody &
const requests: GeneratedBatchQueryRequest[] = batch.map((query: QueryBatch) => {
const body: Exclude<QueryBody, "timespan"> &
Partial<
Pick<
BatchQuery,
QueryBatch,
| "query"
| "timespan"
| "workspaceId"
| "includeQueryStatistics"
| "additionalWorkspaces"
@ -60,11 +61,15 @@ export function convertRequestForQueryBatch(batch: QueryLogsBatch): GeneratedBat
| "serverTimeoutInSeconds"
>
> = {
...query
workspaceId: query.workspaceId,
query: query.query
};
if (query["additionalWorkspaces"]) {
body["workspaces"] = query["additionalWorkspaces"].map((x) => x);
}
if (query["timespan"]) {
body["timespan"] = convertTimespanToInterval(query["timespan"]);
}
delete body["workspaceId"];
delete body["includeQueryStatistics"];
delete body["includeVisualization"];
@ -94,14 +99,14 @@ export function convertRequestForQueryBatch(batch: QueryLogsBatch): GeneratedBat
export function convertResponseForQueryBatch(
generatedResponse: GeneratedQueryBatchResponse,
rawResponse: FullOperationResponse
): QueryLogsBatchResult {
): LogsQueryBatchResult {
const fixApplied = fixInvalidBatchQueryResponse(generatedResponse, rawResponse);
/* Sort the ids that are passed in with the queries, as numbers instead of strings
* It is not guaranteed that service will return the responses for queries in the same order
* as the queries are passed in
*/
const newResponse: QueryLogsBatchResult = {
const newResponse: LogsQueryBatchResult = {
results: generatedResponse.responses
?.sort((a, b) => {
let left = 0;
@ -174,22 +179,30 @@ export function fixInvalidBatchQueryResponse(
* @internal
*/
export function convertRequestForMetrics(
timespan: string,
queryMetricsOptions: QueryMetricsOptions | undefined
metricNames: string[],
queryMetricsOptions: MetricsQueryOptions | undefined
): GeneratedMetricsListOptionalParams {
if (!queryMetricsOptions) {
return {
timespan
};
return {};
}
const { orderBy, metricNames, aggregations, metricNamespace, ...rest } = queryMetricsOptions;
const {
orderBy,
aggregations,
metricNamespace,
timespan,
granularity,
...rest
} = queryMetricsOptions;
const obj: GeneratedMetricsListOptionalParams = {
...rest,
timespan
...rest
};
if (timespan) {
obj.timespan = convertTimespanToInterval(timespan);
}
if (orderBy) {
obj.orderby = orderBy;
}
@ -202,6 +215,9 @@ export function convertRequestForMetrics(
if (metricNamespace) {
obj.metricnamespace = metricNamespace;
}
if (granularity) {
obj.interval = granularity;
}
return obj;
}
@ -210,11 +226,12 @@ export function convertRequestForMetrics(
*/
export function convertResponseForMetrics(
generatedResponse: GeneratedMetricsListResponse
): QueryMetricsResult {
): MetricsQueryResult {
const metrics: Metric[] = generatedResponse.value.map((metric: GeneratedMetric) => {
return {
const metricObject = {
...metric,
name: metric.name.value,
description: metric.displayDescription,
timeseries: metric.timeseries.map(
(ts: GeneratedTimeSeriesElement) =>
<TimeSeriesElement>{
@ -226,12 +243,14 @@ export function convertResponseForMetrics(
}
)
};
delete metricObject.displayDescription;
return metricObject;
});
// eslint-disable-next-line @typescript-eslint/no-unused-vars -- eslint doesn't recognize that the extracted variables are prefixed with '_' and are purposefully unused.
const { resourceregion, value: _ignoredValue, ...rest } = generatedResponse;
const { resourceregion, value: _ignoredValue, interval, ...rest } = generatedResponse;
const obj: QueryMetricsResult = {
const obj: MetricsQueryResult = {
...rest,
metrics
};
@ -239,6 +258,9 @@ export function convertResponseForMetrics(
if (resourceregion) {
obj.resourceRegion = resourceregion;
}
if (interval) {
obj.granularity = interval;
}
return obj;
}
@ -247,7 +269,7 @@ export function convertResponseForMetrics(
* @internal
*/
export function convertRequestOptionsForMetricsDefinitions(
options: GetMetricDefinitionsOptions | undefined
options: ListMetricDefinitionsOptions | undefined
): GeneratedMetricDefinitionsListOptionalParams {
if (!options) {
return {};
@ -270,40 +292,52 @@ export function convertRequestOptionsForMetricsDefinitions(
* @internal
*/
export function convertResponseForMetricsDefinitions(
generatedResponse: GeneratedMetricDefinitionsListResponse
): GetMetricDefinitionsResult {
return {
definitions: generatedResponse.value?.map((genDef) => {
const { name, dimensions, ...rest } = genDef;
generatedResponse: Array<GeneratedMetricDefinition>
): Array<MetricDefinition> {
const definitions: Array<MetricDefinition> = generatedResponse?.map((genDef) => {
const { name, dimensions, displayDescription, ...rest } = genDef;
const response: MetricDefinition = {
...rest
};
const response: MetricDefinition = {
...rest
};
if (name?.value) {
response.name = name.value;
}
if (displayDescription) {
response.description = displayDescription;
}
if (name?.value) {
response.name = name.value;
}
const mappedDimensions = dimensions?.map((dim) => dim.value);
const mappedDimensions = dimensions?.map((dim) => dim.value);
if (mappedDimensions) {
response.dimensions = mappedDimensions;
}
return response;
})
};
if (mappedDimensions) {
response.dimensions = mappedDimensions;
}
return response;
});
return definitions;
}
/**
* @internal
*/
export function convertResponseForMetricNamespaces(
generatedResponse: GeneratedMetricNamespacesListResponse
): GetMetricNamespacesResult {
return {
namespaces: generatedResponse.value
};
generatedResponse: Array<GeneratedMetricNamespace>
): Array<MetricNamespace> {
const namespaces: Array<MetricNamespace> = generatedResponse?.map((genDef) => {
const { properties, ...rest } = genDef;
const response: MetricNamespace = {
...rest
};
if (properties) {
response.metricNamespaceName = properties.metricNamespaceName;
}
return response;
});
return namespaces;
}
/**

Просмотреть файл

@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import { QueryLogsOptions } from "../models/publicLogsModels";
import { LogsQueryOptions } from "../models/publicLogsModels";
/**
* @internal
@ -9,7 +9,7 @@ import { QueryLogsOptions } from "../models/publicLogsModels";
export function formatPreferHeader(
args:
| Pick<
QueryLogsOptions,
LogsQueryOptions,
"serverTimeoutInSeconds" | "includeQueryStatistics" | "includeVisualization"
>
| undefined

Просмотреть файл

@ -3,14 +3,13 @@
import { AzureLogAnalytics } from "./generated/logquery/src/azureLogAnalytics";
import { TokenCredential } from "@azure/core-auth";
import { PipelineOptions, bearerTokenAuthenticationPolicy } from "@azure/core-rest-pipeline";
import {
QueryLogsBatch,
QueryLogsBatchOptions,
QueryLogsBatchResult,
QueryLogsOptions,
QueryLogsResult
QueryBatch,
LogsQueryBatchOptions,
LogsQueryBatchResult,
LogsQueryOptions,
LogsQueryResult
} from "./models/publicLogsModels";
import {
@ -19,14 +18,16 @@ import {
convertResponseForQueryBatch
} from "./internal/modelConverters";
import { formatPreferHeader } from "./internal/util";
import { FullOperationResponse, OperationOptions } from "@azure/core-client";
import { CommonClientOptions, FullOperationResponse, OperationOptions } from "@azure/core-client";
import { TimeInterval } from "./models/timeInterval";
import { convertTimespanToInterval } from "./timespanConversion";
const defaultMonitorScope = "https://api.loganalytics.io/.default";
/**
* Options for the LogsQueryClient.
*/
export interface LogsQueryClientOptions extends PipelineOptions {
export interface LogsQueryClientOptions extends CommonClientOptions {
/**
* The host to connect to.
*/
@ -37,7 +38,9 @@ export interface LogsQueryClientOptions extends PipelineOptions {
*
* Defaults to 'https://api.loganalytics.io/.default'
*/
scopes?: string | string[];
credentialOptions?: {
credentialScopes?: string | string[];
};
}
/**
@ -59,12 +62,14 @@ export class LogsQueryClient {
this._logAnalytics = new AzureLogAnalytics({
...options,
$host: options?.endpoint,
endpoint: options?.endpoint
endpoint: options?.endpoint,
credentialScopes: options?.credentialOptions?.credentialScopes ?? defaultMonitorScope,
credential: tokenCredential
});
const scope = options?.scopes ?? defaultMonitorScope;
this._logAnalytics.pipeline.addPolicy(
bearerTokenAuthenticationPolicy({ scopes: scope, credential: tokenCredential })
);
// const scope = options?.scopes ?? defaultMonitorScope;
// this._logAnalytics.pipeline.addPolicy(
// bearerTokenAuthenticationPolicy({ scopes: scope, credential: tokenCredential })
// );
}
/**
@ -77,19 +82,23 @@ export class LogsQueryClient {
* @param options - Options to adjust various aspects of the request.
* @returns The result of the query.
*/
async queryLogs(
async query(
workspaceId: string,
query: string,
timespan: string,
options?: QueryLogsOptions
): Promise<QueryLogsResult> {
timespan: TimeInterval,
options?: LogsQueryOptions
): Promise<LogsQueryResult> {
let timeInterval: string = "";
if (timespan) {
timeInterval = convertTimespanToInterval(timespan);
}
const { flatResponse, rawResponse } = await getRawResponse(
(paramOptions) =>
this._logAnalytics.query.execute(
workspaceId,
{
query,
timespan,
timespan: timeInterval,
workspaces: options?.additionalWorkspaces
},
paramOptions
@ -119,10 +128,10 @@ export class LogsQueryClient {
* @param options - Options for querying logs in a batch.
* @returns The Logs query results for all the queries.
*/
async queryLogsBatch(
batch: QueryLogsBatch,
options?: QueryLogsBatchOptions
): Promise<QueryLogsBatchResult> {
async queryBatch(
batch: QueryBatch[],
options?: LogsQueryBatchOptions
): Promise<LogsQueryBatchResult> {
const generatedRequest = convertRequestForQueryBatch(batch);
const { flatResponse, rawResponse } = await getRawResponse(
(paramOptions) => this._logAnalytics.query.batch(generatedRequest, paramOptions),

Просмотреть файл

@ -2,14 +2,14 @@
// Licensed under the MIT license.
import { TokenCredential } from "@azure/core-auth";
import { PipelineOptions, bearerTokenAuthenticationPolicy } from "@azure/core-rest-pipeline";
import { PagedAsyncIterableIterator } from "@azure/core-paging";
import {
GetMetricDefinitionsOptions,
GetMetricDefinitionsResult,
GetMetricNamespacesOptions,
GetMetricNamespacesResult,
QueryMetricsOptions,
QueryMetricsResult
ListMetricDefinitionsOptions,
ListMetricNamespacesOptions,
MetricsQueryOptions,
MetricsQueryResult,
MetricDefinition
} from "./models/publicMetricsModels";
import {
@ -22,6 +22,7 @@ import {
} from "./generated/metricsdefinitions/src";
import {
KnownApiVersion20171201Preview as MetricNamespacesApiVersion,
MetricNamespace,
MonitorManagementClient as GeneratedMetricsNamespacesClient
} from "./generated/metricsnamespaces/src";
import {
@ -85,53 +86,193 @@ export class MetricsQueryClient {
/**
* Query metrics, given a resource URI
* @param resourceUri - The resource URI to query.
* @param timespan - The enclosing timespan for metrics.
* @param metricNames - The names of the metrics to retrieve.
* @param options - Options for querying metrics.
* @returns A response containing metrics.
*/
async queryMetrics(
async query(
resourceUri: string,
timespan: string,
options?: QueryMetricsOptions
): Promise<QueryMetricsResult> {
metricNames: string[],
options?: MetricsQueryOptions
): Promise<MetricsQueryResult> {
const response = await this._metricsClient.metrics.list(
resourceUri,
convertRequestForMetrics(timespan, options)
convertRequestForMetrics(metricNames, options)
);
return convertResponseForMetrics(response);
}
/**
* List alert segments for Metric Definitions
*/
private async *listSegmentOfMetricDefinitions(
resourceUri: string,
options: ListMetricDefinitionsOptions = {}
): AsyncIterableIterator<Array<MetricDefinition>> {
const segmentResponse = await this._definitionsClient.metricDefinitions.list(
resourceUri,
convertRequestOptionsForMetricsDefinitions(options)
);
yield convertResponseForMetricsDefinitions(segmentResponse.value);
}
/**
* List items for Metric Definitions
*/
private async *listItemsOfMetricDefinitions(
resourceUri: string,
options?: ListMetricDefinitionsOptions
): AsyncIterableIterator<MetricDefinition> {
for await (const segment of this.listSegmentOfMetricDefinitions(resourceUri, options)) {
if (segment) {
yield* segment;
}
}
}
/**
* /**
*
* Returns an async iterable iterator to list metric definitions.
*
* Example using `for await` syntax:
*
* ```js
* const metricsQueryClient = new MetricsQueryClient(tokenCredential);
* const metricDefinitions = client.listMetricDefinitions(resourceUri, options);
* let i = 1;
* for await (const metricDefinition of metricDefinitions) {
* console.log(`metricDefinition ${i++}:`);
* console.log(metricDefinition);
* }
* ```
*
* Example using `iter.next()`:
*
* ```js
* let iter = client.listMetricDefinitions(resourceUri, options);
* let result = await iter.next();
* while (!result.done) {
* console.log(` metricDefinitions - ${result.value.id}, ${result.value.name}`);
* result = await iter.next();
* }
* ```
*
* Get a list of metric definitions, given a resource URI.
* @param resourceUri - The resource URI to get metric definitions for.
* @param options - Options for getting metric definitions.
* @returns Metric definitions for a given resource URI.
*/
async getMetricDefinitions(
listMetricDefinitions(
resourceUri: string,
options?: GetMetricDefinitionsOptions
): Promise<GetMetricDefinitionsResult> {
const response = await this._definitionsClient.metricDefinitions.list(
resourceUri,
convertRequestOptionsForMetricsDefinitions(options)
);
return convertResponseForMetricsDefinitions(response);
options?: ListMetricDefinitionsOptions
): PagedAsyncIterableIterator<MetricDefinition> {
const iter = this.listItemsOfMetricDefinitions(resourceUri, options);
return {
/**
* The next method, part of the iteration protocol
*/
next() {
return iter.next();
},
/**
* The connection to the async iterator, part of the iteration protocol
*/
[Symbol.asyncIterator]() {
return this;
},
/**
* @returns an AsyncIterableIterator that works a page at a time
*/
byPage: () => {
return this.listSegmentOfMetricDefinitions(resourceUri, options);
}
};
}
/**
* List alert segments for Metric Namespaces
*/
private async *listSegmentOfMetricNamespaces(
resourceUri: string,
options: ListMetricNamespacesOptions = {}
): AsyncIterableIterator<Array<MetricNamespace>> {
const segmentResponse = await this._namespacesClient.metricNamespaces.list(
resourceUri,
options
);
yield convertResponseForMetricNamespaces(segmentResponse.value);
}
/**
* List items for Metric Namespaces
*/
private async *listItemsOfMetricNamespaces(
resourceUri: string,
options?: ListMetricNamespacesOptions
): AsyncIterableIterator<MetricNamespace> {
for await (const segment of this.listSegmentOfMetricNamespaces(resourceUri, options)) {
if (segment) {
yield* segment;
}
}
}
/**
*
* Returns an async iterable iterator to list metric namespaces.
*
* Example using `for await` syntax:
*
* ```js
* const metricsQueryClient = new MetricsQueryClient(tokenCredential);
* const metricNamespaces = client.listMetricNamespaces(resourceUri, options);
* let i = 1;
* for await (const metricNamespace of metricNamespaces) {
* console.log(`metricNamespace ${i++}:`);
* console.log(metricNamespace);
* }
* ```
*
* Example using `iter.next()`:
*
* ```js
* let iter = client.listMetricNamespaces(resourceUri, options);
* let result = await iter.next();
* while (!result.done) {
* console.log(` metricNamespace - ${result.value.id}, ${result.value.name}`);
* result = await iter.next();
* }
* ```
* Get a list of metric namespaces, given a resource URI.
* @param resourceUri - The resource URI to get metric namespaces for.
* @param options - Options for getting metric namespaces.
* @returns Metric namespaces for a given resource URI.
*/
async getMetricNamespaces(
listMetricNamespaces(
resourceUri: string,
options?: GetMetricNamespacesOptions
): Promise<GetMetricNamespacesResult> {
const response = await this._namespacesClient.metricNamespaces.list(resourceUri, options);
return convertResponseForMetricNamespaces(response);
options?: ListMetricNamespacesOptions
): PagedAsyncIterableIterator<MetricNamespace> {
const iter = this.listItemsOfMetricNamespaces(resourceUri, options);
return {
/**
* The next method, part of the iteration protocol
*/
next() {
return iter.next();
},
/**
* The connection to the async iterator, part of the iteration protocol
*/
[Symbol.asyncIterator]() {
return this;
},
/**
* @returns an AsyncIterableIterator that works a page at a time
*/
byPage: () => {
return this.listSegmentOfMetricNamespaces(resourceUri, options);
}
};
}
}

Просмотреть файл

@ -6,25 +6,23 @@
*/
export const Durations = {
/** Alias for ISO8601 value 'P7D' */
last7Days: "P7D",
sevenDays: "P7D",
/** Alias for ISO8601 value 'P3D' */
last3Days: "P3D",
threeDays: "P3D",
/** Alias for ISO8601 value 'P2D' */
last2Days: "P2D",
twoDays: "P2D",
/** Alias for ISO8601 value 'P1D' */
lastDay: "P1D",
OneDay: "P1D",
/** Alias for ISO8601 value 'PT1H' */
lastHour: "PT1H",
OneHour: "PT1H",
/** Alias for ISO8601 value 'PT4H' */
last4Hours: "PT4H",
FourHours: "PT4H",
/** Alias for ISO8601 value 'P1D' */
last24Hours: "P1D",
TwentyFourHours: "P1D",
/** Alias for ISO8601 value 'P2D' */
last48Hours: "P2D",
FourtyEightHours: "P2D",
/** Alias for ISO8601 value 'PT30M' */
last30Minutes: "PT30M",
ThirtyMinutes: "PT30M",
/** Alias for ISO8601 value 'PT5M' */
last5Minutes: "PT5M"
FiveMinutes: "PT5M"
} as const;

Просмотреть файл

@ -2,7 +2,8 @@
// Licensed under the MIT license.
import { OperationOptions } from "@azure/core-client";
import { Column as LogsColumn, ErrorInfo } from "../generated/logquery/src";
import { ErrorInfo, LogsColumnType } from "../generated/logquery/src";
import { TimeInterval } from "./timeInterval";
// https://dev.loganalytics.io/documentation/Using-the-API/RequestOptions
// https://dev.loganalytics.io/documentation/Using-the-API/Timeouts
@ -10,7 +11,7 @@ import { Column as LogsColumn, ErrorInfo } from "../generated/logquery/src";
/**
* Options for querying logs.
*/
export interface QueryLogsOptions extends OperationOptions {
export interface LogsQueryOptions extends OperationOptions {
/**
* 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:
@ -50,31 +51,23 @@ export interface QueryStatistics {
/**
* Tables and statistic results from a logs query.
*/
export interface QueryLogsResult {
export interface LogsQueryResult {
/** The list of tables, columns and rows. */
tables: LogsTable[];
/** Statistics represented in JSON format. */
statistics?: any;
statistics?: Record<string, unknown>;
/** Visualization data in JSON format. */
visualization?: any;
visualization?: Record<string, unknown>;
/** The code and message for an error. */
error?: ErrorInfo;
}
/** Options when query logs with a batch. */
export type QueryLogsBatchOptions = OperationOptions;
/** An array of queries to run as a batch. */
export interface QueryLogsBatch {
/**
* Queries that will be run for the batch.
*/
queries: BatchQuery[];
}
/** Configurable HTTP request settings for the Logs query batch operation. */
export type LogsQueryBatchOptions = OperationOptions;
/** The Analytics query. Learn more about the [Analytics query syntax](https://azure.microsoft.com/documentation/articles/app-insights-analytics-reference/) */
// NOTE: 'id' is added automatically by our LogsClient.
export interface BatchQuery {
// NOTE: 'id' is added automatically by our LogsQueryClient.
export interface QueryBatch {
/** The workspace for this query. */
workspaceId: string;
@ -83,8 +76,8 @@ export interface BatchQuery {
/** The query to execute. */
query: string;
/** 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. */
timespan: 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;
/**
* 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:
@ -111,7 +104,7 @@ export interface BatchQuery {
}
/** Results for a batch query. */
export interface QueryLogsBatchResult {
export interface LogsQueryBatchResult {
/** An array of responses corresponding to each individual request in a batch. */
results?: {
id?: string;
@ -121,9 +114,9 @@ export interface QueryLogsBatchResult {
tables?: LogsTable[];
error?: ErrorInfo;
/** Statistics represented in JSON format. */
statistics?: any;
statistics?: Record<string, unknown>;
/** Visualization data in JSON format. */
visualization?: any;
visualization?: Record<string, unknown>;
}[];
// TODO: this is omitted from the Java models.
@ -140,3 +133,26 @@ export interface LogsTable {
/** The resulting rows from this query. */
rows: (Date | string | number | Record<string, unknown> | boolean)[][];
}
/** A column in a table. */
export interface LogsColumn {
/** The name of this column. */
name?: string;
/** The data type of this column.
* Defines values for LogsColumnType.
* {@link KnownLogsColumnType} can be used interchangeably with LogsColumnType,
* this enum contains the known values that the service supports.
* ### Known values supported by the service
* **bool**
* **datetime**
* **dynamic**
* **int**
* **long**
* **real**
* **string**
* **guid**
* **decimal**
* **timespan**
*/
type?: LogsColumnType;
}

Просмотреть файл

@ -3,25 +3,37 @@
import { OperationOptions } from "@azure/core-client";
import {
MetricNamespace,
MetricValue,
ResultType,
MetricUnit,
MetricClass,
AggregationType,
MetricAvailability
MetricAvailability,
NamespaceClassification
} from "..";
import { TimeInterval } from "./timeInterval";
/**
* Options used when querying metrics.
*/
export interface QueryMetricsOptions extends OperationOptions {
/** The interval (i.e. timegrain) of the query. */
interval?: string;
/** The names of the metrics to retrieve **/
metricNames?: string[];
export interface MetricsQueryOptions extends OperationOptions {
/** The interval (i.e. timegrain) of the query. {@link Durations} helper contains aliases for some common ISO8601 durations.
* This is an ISO8601 duration value in the format P[n]Y[n]M[n]DT[n]H[n]M[n]S
* where P is the duration designator (for period) placed at the start of the duration representation.
* Y is the year designator that follows the value for the number of years.
* M is the month designator that follows the value for the number of months.
* W is the week designator that follows the value for the number of weeks.
* D is the day designator that follows the value for the number of days.
* T is the time designator that precedes the time components of the representation.
* H is the hour designator that follows the value for the number of hours.
* M is the minute designator that follows the value for the number of minutes.
* S is the second designator that follows the value for the number of seconds.
*/
granularity?: string;
/** The enclosing timespan for metrics. */
timespan?: TimeInterval;
/** The list of aggregation types (comma separated) to retrieve. */
aggregations?: string[];
aggregations?: AggregationType[];
/**
* The maximum number of records to retrieve.
* Valid only if $filter is specified.
@ -51,7 +63,7 @@ export interface Metric {
/** the name of the metric */
name: string;
/** Detailed description of this metric. */
displayDescription?: string;
description?: string;
/** 'Success' or the error details on query failures for this metric. */
errorCode?: string;
/** the unit of the metric. */
@ -82,7 +94,7 @@ export interface TimeSeriesElement {
/**
* Metrics, including additional information like cost, the resourceRegion, etc...
*/
export interface QueryMetricsResult {
export interface MetricsQueryResult {
// track 2 version of `MetricsListResponse`
/** The integer value representing the cost of the query, for data case. */
@ -90,7 +102,7 @@ export interface QueryMetricsResult {
/** 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: string;
/** 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. */
interval?: string;
granularity?: string;
/** The namespace of the metrics been queried */
namespace?: string;
/** The region of the resource been queried for metrics. */
@ -102,68 +114,38 @@ export interface QueryMetricsResult {
/**
* Options used when getting metric definitions.
*/
export interface GetMetricDefinitionsOptions extends OperationOptions {
export interface ListMetricDefinitionsOptions extends OperationOptions {
// track 2 version of `MetricDefinitionsListOptionalParams`
/** Metric namespace to query metric definitions for. */
metricNamespace?: string;
}
/** Metric definition class specifies the metadata for a metric. */
export interface MetricDefinition {
/** Flag to indicate whether the dimension is required. */
isDimensionRequired?: boolean;
/** the resource identifier of the resource that emitted the metric. */
resourceId?: string;
/** the name of the metric */
name?: string;
/** Detailed description of this metric. */
displayDescription?: string;
/** Custom category name for this metric. */
category?: string;
/** the unit of the metric. */
unit?: MetricUnit;
/** the primary aggregation type value defining how to use the values for display. */
primaryAggregationType?: AggregationType;
/** the collection of what aggregation intervals are available to be queried. */
metricAvailabilities?: MetricAvailability[];
/** the resource identifier of the metric definition. */
id?: string;
/** the name of the dimension */
dimensions?: string[];
}
/**
* Metric definitions.
*/
export interface GetMetricDefinitionsResult {
/** the values for the metric definitions. */
definitions: MetricDefinition[];
}
/**
* Options used when getting metric namespaces.
*/
export interface GetMetricNamespacesOptions {
export interface ListMetricNamespacesOptions {
// track 2 copy of `MetricNamespacesListOptionalParams`
/** The ISO 8601 conform Date start time from which to query for metric namespaces. */
startTime?: string;
}
/**
* Metric namespaces.
*/
export interface GetMetricNamespacesResult {
// track 2 version of MetricNamespacesListResponse
/** The metric namespaces. */
namespaces: MetricNamespace[];
/** Metric namespace class specifies the metadata for a metric namespace. */
export interface MetricNamespace {
/** The ID of the metric namespace. */
id?: string;
/** The type of the namespace. */
type?: string;
/** The escaped name of the namespace. */
name?: string;
/** Kind of namespace */
classification?: NamespaceClassification;
/** The metric namespace name. */
metricNamespaceName?: string;
}
/**
* Metric definition.
*/
/** Metric definition class specifies the metadata for a metric. */
export interface MetricDefinition {
/** Flag to indicate whether the dimension is required. */
isDimensionRequired?: boolean;
@ -174,7 +156,7 @@ export interface MetricDefinition {
/** the name and the display name of the metric, i.e. it is a localizable string. */
name?: string;
/** Detailed description of this metric. */
displayDescription?: string;
description?: string;
/** Custom category name for this metric. */
category?: string;
/** The class of the metric. */

Просмотреть файл

@ -0,0 +1,81 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
/**
* Time Interval type for specifying timespan for querying logs and metrics.
* A time interval is the intervening time between two time points.
* The amount of intervening time is expressed by a duration The two time points (start and end) are expressed by either a combined date and time representation
* or just a date representation.There are four ways to express a time interval:
* - duration
* - start time, end time
* - start time, duration
* - duration, end time
*/
export type TimeInterval =
| {
/**
* Start time for time interval
*/
startTime: Date;
/**
* End time for time interval
*/
endTime: Date;
}
| {
/**
* Start time for time interval
*/
startTime: Date;
/**
* The duration from the start time. {@link Durations} helper contains aliases for some common ISO8601 durations.
* The duration is an ISO8601 duration value in the format P[n]Y[n]M[n]DT[n]H[n]M[n]S
* where P is the duration designator (for period) placed at the start of the duration representation.
* Y is the year designator that follows the value for the number of years.
* M is the month designator that follows the value for the number of months.
* W is the week designator that follows the value for the number of weeks.
* D is the day designator that follows the value for the number of days.
* T is the time designator that precedes the time components of the representation.
* H is the hour designator that follows the value for the number of hours.
* M is the minute designator that follows the value for the number of minutes.
* S is the second designator that follows the value for the number of seconds.
*/
duration: string;
}
| {
/**
* The duration until the end time. {@link Durations} helper contains aliases for some common ISO8601 durations.
* The duration is an ISO8601 duration value in the format P[n]Y[n]M[n]DT[n]H[n]M[n]S
* where P is the duration designator (for period) placed at the start of the duration representation.
* Y is the year designator that follows the value for the number of years.
* M is the month designator that follows the value for the number of months.
* W is the week designator that follows the value for the number of weeks.
* D is the day designator that follows the value for the number of days.
* T is the time designator that precedes the time components of the representation.
* H is the hour designator that follows the value for the number of hours.
* M is the minute designator that follows the value for the number of minutes.
* S is the second designator that follows the value for the number of seconds.
*/
duration: string;
/**
* end time for interval
*/
endTime: Date;
}
| {
/**
* The duration of a time span that ends at the time the operation is processed, e.g. events from the last 5 hours.
* {@link Durations} helper contains aliases for some common ISO8601 durations.
* The duration is an ISO8601 time period value in the format P[n]Y[n]M[n]DT[n]H[n]M[n]S
* where P is the duration designator (for period) placed at the start of the duration representation.
* Y is the year designator that follows the value for the number of years.
* M is the month designator that follows the value for the number of months.
* W is the week designator that follows the value for the number of weeks.
* D is the day designator that follows the value for the number of days.
* T is the time designator that precedes the time components of the representation.
* H is the hour designator that follows the value for the number of hours.
* M is the minute designator that follows the value for the number of minutes.
* S is the second designator that follows the value for the number of seconds.
*/
duration: string;
};

Просмотреть файл

@ -0,0 +1,69 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import { TimeInterval } from "./models/timeInterval";
export function convertTimespanToInterval(timespan: TimeInterval): string {
if (isObjectWithProperties(timespan, ["startTime", "endTime", "duration"])) {
throw new TypeError("Invalid Timespan - contains startTime, endTime, and duration.");
}
if (isObjectWithProperties(timespan, ["startTime", "endTime"])) {
return `${timespan.startTime.toISOString()}/${timespan.endTime.toISOString()}`;
} else if (isObjectWithProperties(timespan, ["startTime", "duration"])) {
return `${timespan.startTime.toISOString()}/${timespan.duration}`;
} else if (isObjectWithProperties(timespan, ["duration", "endTime"])) {
return `${timespan.duration}/${timespan.endTime.toISOString()}`;
} else if (isObjectWithProperties(timespan, ["duration"])) {
return timespan.duration;
}
throw new TypeError("Invalid Timespan - no valid fields assigned.");
}
/**
* Helper TypeGuard that checks if the input is an object with the specified property.
* Note: The property may be inherited.
* @param thing - Any object.
* @param property - The name of the property that should appear in the object.
* @internal
*/
export function objectHasProperty<Thing extends unknown, PropertyName extends string>(
thing: Thing,
property: PropertyName
): thing is Thing & Record<PropertyName, unknown> {
return typeof thing === "object" && property in (thing as Record<string, unknown>);
}
/**
* Helper TypeGuard that checks if something is defined or not.
* @param thing - Anything
* @internal
*/
export function isDefined<T>(thing: T | undefined | null): thing is T {
return typeof thing !== "undefined" && thing !== null;
}
/**
* Helper TypeGuard that checks if the input is an object with the specified properties.
* Note: The properties may be inherited.
* @param thing - Anything.
* @param properties - The name of the properties that should appear in the object.
* @internal
*/
export function isObjectWithProperties<Thing extends unknown, PropertyName extends string>(
thing: Thing,
properties: PropertyName[]
): thing is Thing & Record<PropertyName, unknown> {
if (!isDefined(thing) || typeof thing !== "object") {
return false;
}
for (const property of properties) {
if (!objectHasProperty(thing, property)) {
return false;
}
}
return true;
}

Просмотреть файл

@ -30,14 +30,16 @@ describe("LogsQueryClient unit tests", () => {
const client = new LogsQueryClient(tokenCredential, {
endpoint: "https://customEndpoint1",
scopes: "https://customscopes1/"
credentialOptions: {
credentialScopes: "https://customscopes1/"
}
});
assert.equal(client["_logAnalytics"].$host, "https://customEndpoint1");
assert.equal(client["_logAnalytics"]["_baseUri"], "https://customEndpoint1");
try {
await client.queryLogs("workspaceId", "query", Durations.last5Minutes);
await client.query("workspaceId", "query", { duration: Durations.FiveMinutes });
assert.fail("Should have thrown");
} catch (err) {
assert.deepNestedInclude(err, {

Просмотреть файл

@ -16,8 +16,7 @@ import {
convertRequestOptionsForMetricsDefinitions,
convertRequestForMetrics,
convertResponseForMetrics,
convertResponseForMetricsDefinitions,
convertResponseForMetricNamespaces
convertResponseForMetricsDefinitions
} from "../../../src/internal/modelConverters";
import {
OperationRequestOptions,
@ -27,26 +26,22 @@ import {
import { OperationTracingOptions } from "@azure/core-tracing";
import {
Durations,
GetMetricDefinitionsResult,
GetMetricNamespacesResult,
GetMetricDefinitionsOptions,
QueryMetricsOptions,
QueryMetricsResult
ListMetricDefinitionsOptions,
MetricsQueryOptions,
MetricsQueryResult
} from "../../../src";
import { AbortSignalLike } from "@azure/abort-controller";
describe("Model unit tests", () => {
describe("LogsClient", () => {
it("convertToBatchRequest (simple)", () => {
const generatedRequest = convertRequestForQueryBatch({
queries: [
{
query: "the kusto query",
workspaceId: "the primary workspace id",
timespan: Durations.last24Hours
}
]
});
const generatedRequest = convertRequestForQueryBatch([
{
query: "the kusto query",
workspaceId: "the primary workspace id",
timespan: { duration: Durations.TwentyFourHours }
}
]);
assert.deepEqual(generatedRequest, <GeneratedBatchRequest>{
requests: [
@ -56,7 +51,7 @@ describe("Model unit tests", () => {
headers: undefined,
body: {
query: "the kusto query",
timespan: Durations.last24Hours
timespan: Durations.TwentyFourHours
}
}
]
@ -64,23 +59,21 @@ describe("Model unit tests", () => {
});
it("convertToBatchRequest (complex)", () => {
const generatedRequest = convertRequestForQueryBatch({
queries: [
{
query: "<placeholder>",
workspaceId: "<placeholder>",
timespan: Durations.last24Hours
},
{
query: "the kusto query",
timespan: Durations.last5Minutes,
workspaceId: "the primary workspace id",
includeQueryStatistics: true,
serverTimeoutInSeconds: 100,
additionalWorkspaces: ["additionalWorkspace", "resourceId1"]
}
]
});
const generatedRequest = convertRequestForQueryBatch([
{
query: "<placeholder>",
workspaceId: "<placeholder>",
timespan: { duration: Durations.TwentyFourHours }
},
{
query: "the kusto query",
timespan: { duration: Durations.FiveMinutes },
workspaceId: "the primary workspace id",
includeQueryStatistics: true,
serverTimeoutInSeconds: 100,
additionalWorkspaces: ["additionalWorkspace", "resourceId1"]
}
]);
console.log(JSON.stringify(generatedRequest.requests?.[1]));
assert.deepEqual(generatedRequest.requests?.[1], <BatchQueryRequest>{
body: {
@ -108,30 +101,30 @@ describe("Model unit tests", () => {
const onResponse = {} as RawResponseCallback;
// (Required<T> just to make sure I don't forget a field)
const track2Model: Required<QueryMetricsOptions> = {
const track2Model: Required<MetricsQueryOptions> = {
abortSignal,
aggregations: ["agg1", "agg2"],
aggregations: ["Average", "Maximum"],
filter: "arbitraryFilter",
interval: "arbitraryInterval",
metricNames: ["name1", "name2"],
granularity: "arbitraryInterval",
metricNamespace: "myMetricNamespace",
orderBy: "orderByClause",
requestOptions,
resultType: "Data",
top: 10,
timespan: { duration: "arbitraryTimespan" },
tracingOptions,
serializerOptions,
onResponse
};
const actualMetricsRequest: GeneratedMetricsListOptionalParams = convertRequestForMetrics(
"arbitraryTimespan",
["name1", "name2"],
track2Model
);
const expectedMetricsRequest: GeneratedMetricsListOptionalParams = {
abortSignal,
aggregation: "agg1,agg2",
aggregation: "Average,Maximum",
filter: "arbitraryFilter",
interval: "arbitraryInterval",
metricnames: "name1,name2",
@ -150,11 +143,8 @@ describe("Model unit tests", () => {
});
it("convertRequestForMetrics (only required fields)", () => {
assert.deepEqual(convertRequestForMetrics(Durations.lastDay, undefined), {
timespan: Durations.lastDay
});
assert.deepEqual(convertRequestForMetrics(Durations.last2Days, {}), {
timespan: Durations.last2Days
assert.deepEqual(convertRequestForMetrics(["SuccessfulCalls", "TotalCalls"], {}), {
metricnames: "SuccessfulCalls,TotalCalls"
});
});
@ -208,12 +198,12 @@ describe("Model unit tests", () => {
};
const actualConvertedResponse = convertResponseForMetrics(generatedResponse);
const expectedResponse: QueryMetricsResult = {
const expectedResponse: MetricsQueryResult = {
timespan: "aTimespan",
metrics: [
{
id: "fakeMetric",
displayDescription: "displayDescription",
description: "displayDescription",
errorCode: "anErrorCode",
name: "fakeValue",
timeseries: [
@ -242,7 +232,7 @@ describe("Model unit tests", () => {
}
],
cost: 100,
interval: "anInterval",
granularity: "anInterval",
namespace: "aNamespace",
resourceRegion: "aResourceRegion"
// NOTE: _response is not returned as part of our track 2 response.
@ -258,7 +248,7 @@ describe("Model unit tests", () => {
const serializerOptions = {} as SerializerOptions;
const onResponse = {} as RawResponseCallback;
const track2: Required<GetMetricDefinitionsOptions> = {
const track2: Required<ListMetricDefinitionsOptions> = {
abortSignal,
requestOptions,
tracingOptions,
@ -287,68 +277,60 @@ describe("Model unit tests", () => {
});
it("convertResponseForMetricsDefinitions", () => {
const actualResponse = convertResponseForMetricsDefinitions({
value: [
{
dimensions: [
{
value: "the value",
localizedValue: "optional localized value but it's ignored"
}
],
name: {
value: "the name"
},
id: "anything"
}
]
});
const actualResponse = convertResponseForMetricsDefinitions([
{
dimensions: [
{
value: "the value",
localizedValue: "optional localized value but it's ignored"
}
],
name: {
value: "the name"
},
id: "anything"
}
]);
assert.deepEqual(
<GetMetricDefinitionsResult>{
definitions: [
{
id: "anything",
name: "the name",
dimensions: ["the value"]
}
]
},
[
{
id: "anything",
name: "the name",
dimensions: ["the value"]
}
],
actualResponse
);
});
it("convertResponseForMetricsDefinitions (optional fields removed)", () => {
const actualResponse = convertResponseForMetricsDefinitions({
value: [
const actualResponse = convertResponseForMetricsDefinitions([
{
id: "anything"
}
]);
assert.deepEqual(
[
// we don't add fields if they weren't in the original response (for instance, we don't add in an
// undefined 'name', or 'dimensions')
{
id: "anything"
}
]
});
assert.deepEqual(
<GetMetricDefinitionsResult>{
definitions: [
// we don't add fields if they weren't in the original response (for instance, we don't add in an
// undefined 'name', or 'dimensions')
{
id: "anything"
}
]
},
],
actualResponse
);
});
it("convertResponseForMetricNamespaces", () => {
const actualResponse = convertResponseForMetricNamespaces({
value: [{ id: "anything" } as any]
});
// it("convertResponseForMetricNamespaces", () => {
// const actualResponse = convertResponseForMetricNamespaces({
// value: [{ id: "anything" } as any]
// });
assert.deepEqual(actualResponse, <GetMetricNamespacesResult>{
namespaces: [{ id: "anything" } as any]
});
});
// assert.deepEqual(actualResponse, <GetMetricNamespacesResult>{
// namespaces: [{ id: "anything" } as any]
// });
// });
});
});

Просмотреть файл

@ -5,7 +5,7 @@ import { assert } from "chai";
import { Context } from "mocha";
import { env } from "process";
import { QueryLogsBatch, Durations, LogsQueryClient } from "../../src";
import { Durations, LogsQueryClient, QueryBatch } from "../../src";
import { runWithTelemetry } from "../setupOpenTelemetry";
import {
@ -38,7 +38,9 @@ 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().queryLogs(monitorWorkspaceId, kustoQuery, Durations.lastDay);
await createClient().query(monitorWorkspaceId, kustoQuery, {
duration: Durations.OneDay
});
assert.fail("Should have thrown an exception");
} catch (err) {
// eslint-disable-next-line @typescript-eslint/no-unused-vars -- eslint doesn't recognize that the extracted variables are prefixed with '_' and are purposefully unused.
@ -78,11 +80,13 @@ describe("LogsQueryClient live tests", function() {
// query has timed out on purpose.
it("serverTimeoutInSeconds", async () => {
try {
await createClient({ maxRetries: 0, retryDelayInMs: 0, maxRetryDelayInMs: 0 }).queryLogs(
await createClient({ maxRetries: 0, retryDelayInMs: 0, maxRetryDelayInMs: 0 }).query(
monitorWorkspaceId,
// slow query suggested by Pavel.
"range x from 1 to 10000000000 step 1 | count",
Durations.last24Hours,
{
duration: Durations.TwentyFourHours
},
{
// the query above easily takes longer than 1 second.
serverTimeoutInSeconds: 1
@ -119,10 +123,12 @@ describe("LogsQueryClient live tests", function() {
});
it("includeQueryStatistics", async () => {
const results = await createClient().queryLogs(
const results = await createClient().query(
monitorWorkspaceId,
"AppEvents | limit 1",
Durations.last24Hours,
{
duration: Durations.TwentyFourHours
},
{
includeQueryStatistics: true
}
@ -131,14 +137,16 @@ describe("LogsQueryClient live tests", function() {
// TODO: statistics are not currently modeled in the generated code but
// the executionTime field is pretty useful.
assert.isOk(results.statistics);
assert.isNumber(results.statistics?.query?.executionTime);
assert.isNumber((results.statistics?.query as any)?.executionTime);
});
it("includeRender/includeVisualization", async () => {
const results = await createClient().queryLogs(
const results = await createClient().query(
monitorWorkspaceId,
`datatable (s: string, i: long) [ "a", 1, "b", 2, "c", 3 ] | render columnchart with (title="the chart title", xtitle="the x axis title")`,
Durations.last24Hours,
{
duration: Durations.TwentyFourHours
},
{
includeVisualization: true
}
@ -166,11 +174,9 @@ describe("LogsQueryClient live tests", function() {
dynamiccolumn=print_6
`;
const results = await createClient().queryLogs(
monitorWorkspaceId,
constantsQuery,
Durations.last5Minutes
);
const results = await createClient().query(monitorWorkspaceId, constantsQuery, {
duration: Durations.FiveMinutes
});
const table = results.tables[0];
@ -250,22 +256,20 @@ describe("LogsQueryClient live tests", function() {
dynamiccolumn=print_6
`;
const result = await createClient().queryLogsBatch({
queries: [
{
workspaceId: monitorWorkspaceId,
query: constantsQuery,
timespan: Durations.last5Minutes
}
]
});
const result = await createClient().queryBatch([
{
workspaceId: monitorWorkspaceId,
query: constantsQuery,
timespan: { duration: Durations.FiveMinutes }
}
]);
if ((result as any)["__fixApplied"]) {
console.log(`TODO: Fix was required to pass`);
}
const table = result.results?.[0].tables?.[0];
console.log(JSON.stringify(result.results?.[0].tables));
if (table == null) {
throw new Error("No table returned for query");
}
@ -369,11 +373,9 @@ 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().queryLogs(
monitorWorkspaceId,
kustoQuery,
Durations.lastDay
);
const singleQueryLogsResult = await createClient().query(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.
@ -390,24 +392,22 @@ describe("LogsQueryClient live tests", function() {
});
it("queryLogsBatch", async () => {
const batchRequest: QueryLogsBatch = {
queries: [
{
workspaceId: monitorWorkspaceId,
query: `AppDependencies | where Properties['testRunId'] == '${testRunId}'| project Kind=Properties["kind"], Name, Target, TestRunId=Properties['testRunId']`,
timespan: Durations.last24Hours
},
{
workspaceId: monitorWorkspaceId,
query: `AppDependencies | where Properties['testRunId'] == '${testRunId}' | count`,
timespan: Durations.last24Hours,
includeQueryStatistics: true,
serverTimeoutInSeconds: 60 * 10
}
]
};
const batchRequest: QueryBatch[] = [
{
workspaceId: monitorWorkspaceId,
query: `AppDependencies | where Properties['testRunId'] == '${testRunId}'| project Kind=Properties["kind"], Name, Target, TestRunId=Properties['testRunId']`,
timespan: { duration: Durations.TwentyFourHours }
},
{
workspaceId: monitorWorkspaceId,
query: `AppDependencies | where Properties['testRunId'] == '${testRunId}' | count`,
timespan: { duration: Durations.TwentyFourHours },
includeQueryStatistics: true,
serverTimeoutInSeconds: 60 * 10
}
];
const result = await createClient().queryLogsBatch(batchRequest);
const result = await createClient().queryBatch(batchRequest);
if ((result as any)["__fixApplied"]) {
console.log(`TODO: Fix was required to pass`);
@ -449,7 +449,9 @@ describe("LogsQueryClient live tests", function() {
const client = createClient();
for (let i = 0; i < args.maxTries; ++i) {
const result = await client.queryLogs(monitorWorkspaceId, query, Durations.last24Hours);
const result = await client.query(monitorWorkspaceId, query, {
duration: Durations.TwentyFourHours
});
const numRows = result.tables?.[0].rows?.length;

Просмотреть файл

@ -17,56 +17,58 @@ describe("MetricsClient live tests", function() {
});
it("getMetricDefinitions -> queryMetrics", async () => {
const metricDefinitions = await metricsQueryClient.getMetricDefinitions(resourceId);
assert.isNotEmpty(metricDefinitions.definitions);
const iter = metricsQueryClient.listMetricDefinitions(resourceId);
// you can only query 20 metrics at a time.
for (const definition of metricDefinitions.definitions) {
const result = await metricsQueryClient.queryMetrics(resourceId, Durations.last24Hours, {
metricNames: [definition.name || ""]
});
assert.ok(result);
assert.ok(result.interval);
assert.isNotEmpty(result.metrics);
let result = await iter.next();
assert.isNotEmpty(result);
const firstMetricDefinition = result.value;
let metricDefinitionsLength = 0;
while (!result.done) {
// you can only query 20 metrics at a time.
const resultQuery = await metricsQueryClient.query(resourceId, [result.value.name || ""], {});
assert(resultQuery);
assert(resultQuery.granularity);
assert.isNotEmpty(resultQuery.metrics);
result = await iter.next();
metricDefinitionsLength++;
}
// do a quick run through of all the individual metrics, in groups of 20
// which is the max.
for (let i = 0; i < metricDefinitions.definitions.length; i += 20) {
const definitionNames = metricDefinitions.definitions
.slice(i, i + 20)
// TODO: I think the 'name' being optional is incorrect in the swagger
// but just in case I'll check until we fix it.
.map((definition) => definition.name!);
const metricDefinitions = iter;
let i = 0;
let definitionNames: Array<string> = [];
for (const definitionName of definitionNames) {
if (definitionName == null) {
throw new Error("Definition name for a metric was undefined/null");
}
for await (const metricDefinition of metricDefinitions) {
if (i % 20 === 0) {
definitionNames = [];
}
if (metricDefinition.name == null) {
throw new Error("Definition name for a metric was undefined/null");
}
definitionNames.push(metricDefinition.name);
const newResults = await metricsQueryClient.queryMetrics(resourceId, Durations.last24Hours, {
metricNames: definitionNames
});
assert.ok(newResults);
assert.isNotEmpty(newResults.metrics);
i++;
if (i % 20 === 0 || i === metricDefinitionsLength) {
const newResults = await metricsQueryClient.query(resourceId, definitionNames, {
timespan: {
duration: Durations.TwentyFourHours
}
});
assert.ok(newResults);
assert.isNotEmpty(newResults.metrics);
}
}
// pick the first query and use the namespace as well.
const firstMetricDefinition = metricDefinitions.definitions[0];
assert.isNotNull(firstMetricDefinition);
assert.isNotEmpty(firstMetricDefinition.name);
assert.isNotEmpty(firstMetricDefinition.namespace);
const individualMetricWithNamespace = metricsQueryClient.queryMetrics(
const individualMetricWithNamespace = metricsQueryClient.query(
resourceId,
Durations.last24Hours,
[firstMetricDefinition.name!],
{
metricNames: [firstMetricDefinition.name!],
timespan: { duration: Durations.TwentyFourHours },
metricNamespace: firstMetricDefinition.namespace
}
);
@ -75,11 +77,11 @@ describe("MetricsClient live tests", function() {
});
it("listNamespaces", async () => {
const result = await metricsQueryClient.getMetricNamespaces(resourceId);
const result = metricsQueryClient.listMetricNamespaces(resourceId);
assert.ok(result);
});
it("listDefinitions", async () => {
const result = await metricsQueryClient.getMetricDefinitions(resourceId);
const result = metricsQueryClient.listMetricDefinitions(resourceId);
assert.ok(result);
});
});

Просмотреть файл

@ -100,7 +100,7 @@ export function getMetricsArmResourceId(
export function getAppInsightsConnectionString(mochaContext: Pick<Context, "skip">): string {
let appInsightsConnectionString = getRequiredEnvVar(
mochaContext,
"APPLICATIONINSIGHTS_CONNECTION_STRING"
"MQ_APPLICATIONINSIGHTS_CONNECTION_STRING"
);
// TODO: this is a workaround for now - adding in an endpoint causes the Monitor endpoint to return a 308 (ie: permanent redirect)

Просмотреть файл

@ -35,9 +35,14 @@
"name": "[parameters('baseName')]",
"type": "Microsoft.Insights/components",
"location": "[parameters('location')]",
"apiVersion": "2015-05-01",
"apiVersion": "2020-02-02",
"kind": "web",
"properties": {
"Application_Type": "other"
"Application_Type": "web",
"WorkspaceResourceId": "[resourceId('Microsoft.OperationalInsights/workspaces', variables('workspaceName'))]",
"IngestionMode": "LogAnalytics",
"publicNetworkAccessForIngestion": "Enabled",
"publicNetworkAccessForQuery": "Enabled"
}
},
{
@ -129,6 +134,10 @@
"APPLICATIONINSIGHTS_CONNECTION_STRING": {
"value": "[reference(resourceId('Microsoft.Insights/components', variables('appInsightsName')), '2015-05-01').ConnectionString]",
"type": "string"
},
"MQ_APPLICATIONINSIGHTS_CONNECTION_STRING": {
"value": "[reference(resourceId('Microsoft.Insights/components', parameters('baseName')), '2015-05-01').ConnectionString]",
"type": "string"
}
}
}