Share via


Azure Monitor Query Logs client library for JavaScript - version 1.0.0

The Azure Monitor Query Logs client library is used to execute read-only queries against Azure Monitor's Logs data platform:

  • Logs - Collects and organizes log and performance data from monitored resources. Data from different sources such as platform logs from Azure services, log and performance data from virtual machines agents, and usage and performance data from apps can be consolidated into a single Azure Log Analytics workspace. The various data types can be analyzed together using the Kusto Query Language.

Migrating from @azure/monitor-query advisory ⚠️

Checkout the Migration Guide for detailed instructions on how to update your application code from the original @azure/monitor-query package to the @azure/monitor-query-logs library.

Resources:

Getting started

Supported environments

For more information, see our support policy.

Prerequisites

Install the package

Install the Azure Monitor Query client library for JavaScript with npm:

npm install --save @azure/monitor-query-logs

Create the client

An authenticated client is required to query Logs. To authenticate, the following example uses DefaultAzureCredential from the @azure/identity package.

import { DefaultAzureCredential } from "@azure/identity";
import { LogsQueryClient } from "@azure/monitor-query-logs";

const credential = new DefaultAzureCredential();

// Create a LogsQueryClient
const logsQueryClient = new LogsQueryClient(credential);

Configure client for Azure sovereign cloud

By default, the library's clients are configured to use the Azure Public Cloud. To use a sovereign cloud instead, provide the correct endpoint and audience value when instantiating a client. For example:

import { DefaultAzureCredential } from "@azure/identity";
import { LogsQueryClient } from "@azure/monitor-query-logs";

const credential = new DefaultAzureCredential();

// Create a LogsQueryClient
const logsQueryClient: LogsQueryClient = new LogsQueryClient(credential, {
  endpoint: "https://api.loganalytics.azure.cn/v1",
  audience: "https://api.loganalytics.azure.cn/.default",
});

Execute the query

For examples of Logs queries, see the Examples section.

Key concepts

Logs query rate limits and throttling

The Log Analytics service applies throttling when the request rate is too high. Limits, such as the maximum number of rows returned, are also applied on the Kusto queries. For more information, see Query API.

Examples

Logs query

The LogsQueryClient can be used to query a Log Analytics workspace using the Kusto Query Language. The timespan.duration can be specified as a string in an ISO 8601 duration format. You can use the Durations constants provided for some commonly used ISO 8601 durations.

You can query logs by Log Analytics workspace ID or Azure resource ID. The result is returned as a table with a collection of rows.

Workspace-centric logs query

To query by workspace ID, use the LogsQueryClient.queryWorkspace method:

import { LogsQueryClient, Durations, LogsQueryResultStatus } from "@azure/monitor-query-logs";
import { DefaultAzureCredential } from "@azure/identity";

const azureLogAnalyticsWorkspaceId = "<workspace_id>";
const logsQueryClient = new LogsQueryClient(new DefaultAzureCredential());

const kustoQuery = "AppEvents | limit 1";
const result = await logsQueryClient.queryWorkspace(azureLogAnalyticsWorkspaceId, kustoQuery, {
  duration: Durations.twentyFourHours,
});

if (result.status === LogsQueryResultStatus.Success) {
  const tablesFromResult = result.tables;

  if (tablesFromResult.length === 0) {
    console.log(`No results for query '${kustoQuery}'`);
    return;
  }
  console.log(`This query has returned table(s) - `);
  processTables(tablesFromResult);
} else {
  console.log(`Error processing the query '${kustoQuery}' - ${result.partialError}`);
  if (result.partialTables.length > 0) {
    console.log(`This query has also returned partial data in the following table(s) - `);
    processTables(result.partialTables);
  }
}

Resource-centric logs query

The following example demonstrates how to query logs directly from an Azure resource. Here, the queryResource method is used and an Azure resource ID is passed in. For example, /subscriptions/{subscription-id}/resourceGroups/{resource-group-name}/providers/{resource-provider}/{resource-type}/{resource-name}.

To find the resource ID:

  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.
import { DefaultAzureCredential } from "@azure/identity";
import { LogsQueryClient, Durations, LogsQueryResultStatus } from "@azure/monitor-query-logs";

const logsResourceId = "<the Resource Id for your logs resource>";

const tokenCredential = new DefaultAzureCredential();
const logsQueryClient = new LogsQueryClient(tokenCredential);

const kustoQuery = `MyTable_CL | summarize count()`;

console.log(`Running '${kustoQuery}' over the last One Hour`);
const queryLogsOptions = {
  // explicitly control the amount of time the server can spend processing the query.
  serverTimeoutInSeconds: 600, // sets the timeout to 10 minutes
  // optionally enable returning additional statistics about the query's execution.
  // (by default, this is off)
  includeQueryStatistics: true,
};

const result = await logsQueryClient.queryResource(
  logsResourceId,
  kustoQuery,
  { duration: Durations.sevenDays },
  queryLogsOptions,
);

console.log(`Results for query '${kustoQuery}'`);

if (result.status === LogsQueryResultStatus.Success) {
  const tablesFromResult = result.tables;

  if (tablesFromResult.length === 0) {
    console.log(`No results for query '${kustoQuery}'`);
    return;
  }
  console.log(`This query has returned table(s) - `);
  processTables(tablesFromResult);
} else {
  console.log(`Error processing the query '${kustoQuery}' - ${result.partialError}`);
  if (result.partialTables.length > 0) {
    console.log(`This query has also returned partial data in the following table(s) - `);
    processTables(result.partialTables);
  }
}

Handle logs query response

The queryWorkspace function of LogsQueryClient returns a LogsQueryResult object. The object type can be LogsQuerySuccessfulResult or LogsQueryPartialResult. Here's a hierarchy of the response:

LogsQuerySuccessfulResult
|---statistics
|---visualization
|---status ("Success")
|---tables (list of `LogsTable` objects)
    |---name
    |---rows
    |---columnDescriptors (list of `LogsColumn` objects)
        |---name
        |---type

LogsQueryPartialResult
|---statistics
|---visualization
|---status ("PartialFailure")
|---partialError
    |--name
    |--code
    |--message
    |--stack
|---partialTables (list of `LogsTable` objects)
    |---name
    |---rows
    |---columnDescriptors (list of `LogsColumn` objects)
        |---name
        |---type

For example, to handle a response with tables:

function processTables(tablesFromResult) {
  for (const table of tablesFromResult) {
    const columnHeaderString = table.columnDescriptors
      .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);
    }
  }
}

A full sample can be found here.

Batch logs query

The following example demonstrates sending multiple queries at the same time using the batch query API. The queries can be represented as a list of BatchQuery objects.

import { DefaultAzureCredential } from "@azure/identity";
import { LogsQueryClient, LogsQueryResultStatus } from "@azure/monitor-query-logs";

const monitorWorkspaceId = "<workspace_id>";

const tokenCredential = new DefaultAzureCredential();
const logsQueryClient = new LogsQueryClient(tokenCredential);

const kqlQuery = "AppEvents | project TimeGenerated, Name, AppRoleInstance | limit 1";
const queriesBatch = [
  {
    workspaceId: monitorWorkspaceId,
    query: kqlQuery,
    timespan: { duration: "P1D" },
  },
  {
    workspaceId: monitorWorkspaceId,
    query: "AzureActivity | summarize count()",
    timespan: { duration: "PT1H" },
  },
  {
    workspaceId: monitorWorkspaceId,
    query:
      "AppRequests | take 10 | summarize avgRequestDuration=avg(DurationMs) by bin(TimeGenerated, 10m), _ResourceId",
    timespan: { duration: "PT1H" },
  },
  {
    workspaceId: monitorWorkspaceId,
    query: "AppRequests | take 2",
    timespan: { duration: "PT1H" },
    includeQueryStatistics: true,
  },
];

const result = await logsQueryClient.queryBatch(queriesBatch);

if (result == null) {
  throw new Error("No response for query");
}

let i = 0;
for (const response of result) {
  console.log(`Results for query with query: ${queriesBatch[i]}`);
  if (response.status === LogsQueryResultStatus.Success) {
    console.log(
      `Printing results from query '${queriesBatch[i].query}' for '${queriesBatch[i].timespan}'`,
    );
    processTables(response.tables);
  } else if (response.status === LogsQueryResultStatus.PartialFailure) {
    console.log(
      `Printing partial results from query '${queriesBatch[i].query}' for '${queriesBatch[i].timespan}'`,
    );
    processTables(response.partialTables);
    console.log(
      ` Query had errors:${response.partialError.message} with code ${response.partialError.code}`,
    );
  } else {
    console.log(`Printing errors from query '${queriesBatch[i].query}'`);
    console.log(` Query had errors:${response.message} with code ${response.code}`);
  }
  // next query
  i++;
}

Handle logs batch query response

The queryBatch function of LogsQueryClient returns a LogsQueryBatchResult object. LogsQueryBatchResult contains a list of objects with the following possible types:

  • LogsQueryPartialResult
  • LogsQuerySuccessfulResult
  • LogsQueryError

Here's a hierarchy of the response:

LogsQuerySuccessfulResult
|---statistics
|---visualization
|---status ("Success")
|---tables (list of `LogsTable` objects)
    |---name
    |---rows
    |---columnDescriptors (list of `LogsColumn` objects)
        |---name
        |---type

LogsQueryPartialResult
|---statistics
|---visualization
|---status ("PartialFailure")
|---partialError
    |--name
    |--code
    |--message
    |--stack
|---partialTables (list of `LogsTable` objects)
    |---name
    |---rows
    |---columnDescriptors (list of `LogsColumn` objects)
        |---name
        |---type

LogsQueryError
|--name
|--code
|--message
|--stack
|--status ("Failure")

For example, the following code handles a batch logs query response:

import { LogsQueryResultStatus } from "@azure/monitor-query-logs";

async function processBatchResult(result, queriesBatch) {
  let i = 0;
  for (const response of result) {
    console.log(`Results for query with query: ${queriesBatch[i]}`);
    if (response.status === LogsQueryResultStatus.Success) {
      console.log(
        `Printing results from query '${queriesBatch[i].query}' for '${queriesBatch[i].timespan}'`,
      );
      processTables(response.tables);
    } else if (response.status === LogsQueryResultStatus.PartialFailure) {
      console.log(
        `Printing partial results from query '${queriesBatch[i].query}' for '${queriesBatch[i].timespan}'`,
      );
      processTables(response.partialTables);
      console.log(
        ` Query had errors:${response.partialError.message} with code ${response.partialError.code}`,
      );
    } else {
      console.log(`Printing errors from query '${queriesBatch[i].query}'`);
      console.log(` Query had errors:${response.message} with code ${response.code}`);
    }
    // next query
    i++;
  }
}
function processTables(tablesFromResult) {
  for (const table of tablesFromResult) {
    const columnHeaderString = table.columnDescriptors
      .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);
    }
  }
}

A full sample can be found here.

Advanced logs query scenarios

Set logs query timeout

Some logs queries take longer than 3 minutes to execute. The default server timeout is 3 minutes. You can increase the server timeout to a maximum of 10 minutes. In the following example, the LogsQueryOptions object's serverTimeoutInSeconds property is used to increase the server timeout to 10 minutes:

import { DefaultAzureCredential } from "@azure/identity";
import { LogsQueryClient, Durations } from "@azure/monitor-query-logs";

const azureLogAnalyticsWorkspaceId = "<workspace_id>";

const tokenCredential = new DefaultAzureCredential();
const logsQueryClient = new LogsQueryClient(tokenCredential);

const kqlQuery = "AppEvents | project TimeGenerated, Name, AppRoleInstance | limit 1";

// setting optional parameters
const queryLogsOptions = {
  // explicitly control the amount of time the server can spend processing the query.
  serverTimeoutInSeconds: 600, // 600 seconds = 10 minutes
};

const result = await logsQueryClient.queryWorkspace(
  azureLogAnalyticsWorkspaceId,
  kqlQuery,
  { duration: Durations.twentyFourHours },
  queryLogsOptions,
);

const status = result.status;

Query multiple workspaces

The same logs query can be executed across multiple Log Analytics workspaces. In addition to the Kusto query, the following parameters are required:

  • workspaceId - The first (primary) workspace ID.
  • additionalWorkspaces - A list of workspaces, excluding the workspace provided in the workspaceId parameter. The parameter's list items can consist of the following identifier formats:
    • Qualified workspace names
    • Workspace IDs
    • Azure resource IDs

For example, the following query executes in three workspaces:

import { DefaultAzureCredential } from "@azure/identity";
import { LogsQueryClient, Durations } from "@azure/monitor-query-logs";

const azureLogAnalyticsWorkspaceId = "<workspace_id>";

const tokenCredential = new DefaultAzureCredential();
const logsQueryClient = new LogsQueryClient(tokenCredential);

const kqlQuery = "AppEvents | project TimeGenerated, Name, AppRoleInstance | limit 1";

// setting optional parameters
const queryLogsOptions = {
  additionalWorkspaces: ["<workspace2>", "<workspace3>"],
};

const result = await logsQueryClient.queryWorkspace(
  azureLogAnalyticsWorkspaceId,
  kqlQuery,
  { duration: Durations.twentyFourHours },
  queryLogsOptions,
);

const status = result.status;

To view the results for each workspace, use the TenantId column to either order the results or filter them in the Kusto query.

Order results by TenantId

AppEvents | order by TenantId

Filter results by TenantId

AppEvents | filter TenantId == "<workspace2>"

A full sample can be found here.

Include statistics

To get logs query execution statistics, such as CPU and memory consumption:

  1. Set the LogsQueryOptions.includeQueryStatistics property to true.
  2. Access the statistics field inside the LogsQueryResult object.

The following example prints the query execution time:

import { LogsQueryClient, Durations } from "@azure/monitor-query-logs";
import { DefaultAzureCredential } from "@azure/identity";

const monitorWorkspaceId = "<workspace_id>";
const logsQueryClient = new LogsQueryClient(new DefaultAzureCredential());
const kustoQuery = "AzureActivity | top 10 by TimeGenerated";

const result = await logsQueryClient.queryWorkspace(
  monitorWorkspaceId,
  kustoQuery,
  { duration: Durations.oneDay },
  {
    includeQueryStatistics: true,
  },
);

console.log(`Results for query '${kustoQuery}'`);

Because the structure of the statistics payload varies by query, a Record<string, unknown> return type is used. It contains the raw JSON response. The statistics are found within the query property of the JSON. For example:

{
  "query": {
    "executionTime": 0.0156478,
    "resourceUsage": {...},
    "inputDatasetStatistics": {...},
    "datasetStatistics": [{...}]
  }
}

Include visualization

To get visualization data for logs queries using the render operator:

  1. Set the LogsQueryOptions.includeVisualization property to true.
  2. Access the visualization field inside the LogsQueryResult object.

For example:

import { LogsQueryClient, Durations } from "@azure/monitor-query-logs";
import { DefaultAzureCredential } from "@azure/identity";

const monitorWorkspaceId = "<workspace_id>";
const logsQueryClient = new LogsQueryClient(new DefaultAzureCredential());

const result = await logsQueryClient.queryWorkspace(
  monitorWorkspaceId,
  `StormEvents
        | summarize event_count = count() by State
        | where event_count > 10
        | project State, event_count
        | render columnchart`,
  { duration: Durations.oneDay },
  {
    includeVisualization: true,
  },
);

console.log("visualization result:", result.visualization);

Because the structure of the visualization payload varies by query, a Record<string, unknown> return type is used. It contains the raw JSON response. For example:

{
  "visualization": "columnchart",
  "title": "the chart title",
  "accumulate": false,
  "isQuerySorted": false,
  "kind": null,
  "legend": null,
  "series": null,
  "yMin": "NaN",
  "yMax": "NaN",
  "xAxis": null,
  "xColumn": null,
  "xTitle": "x axis title",
  "yAxis": null,
  "yColumns": null,
  "ySplit": null,
  "yTitle": null,
  "anomalyColumns": null
}

Troubleshooting

To diagnose various failure scenarios, see the troubleshooting guide.

Next steps

To learn more about Azure Monitor, see the Azure Monitor service documentation.

Contributing

If you'd like to contribute to this library, please read the contributing guide to learn more about how to build and test the code.

This module's tests are a mixture of live and unit tests, which require you to have an Azure Monitor instance. To execute the tests, you'll need to run:

  1. rush update
  2. rush build -t @azure/monitor-query-logs
  3. cd into sdk/monitor/monitor-query
  4. Copy the sample.env file to .env
  5. Open the .env file in an editor and fill in the values.
  6. npm run test.

For more details, view our tests folder.