Biblioteca cliente de consultas de Azure Monitor para JavaScript: versión 1.1.1
La biblioteca cliente de consultas de Azure Monitor se usa para ejecutar consultas de solo lectura en las dos plataformas de datos de Azure Monitor:
- Registros: recopila y organiza los datos de registro y rendimiento de los recursos supervisados. Los datos de diferentes orígenes, como los registros de plataforma de los servicios de Azure, los datos de registro y rendimiento de los agentes de máquinas virtuales, y los datos de uso y rendimiento de las aplicaciones se pueden consolidar en un único área de trabajo de Azure Log Analytics. Los distintos tipos de datos se pueden analizar conjuntamente mediante el Lenguaje de consulta Kusto.
- Métricas : recopila datos numéricos de recursos supervisados en una base de datos de serie temporal. Las métricas son valores numéricos que se recopilan a intervalos regulares y describen algún aspecto de un sistema en un momento determinado. Las métricas son ligeras y capaces de admitir escenarios casi en tiempo real, lo que les hace especialmente útil para alertar y detectar rápidamente problemas.
Recursos:
- Código fuente
- Paquete (npm)
- Documentación de referencia de API
- Documentación del servicio
- Muestras
- Registro de cambios
Introducción
Entornos admitidos
- Versiones de LTS de Node.js
- Versiones más recientes de Safari, Chrome, Edge y Firefox
Para más información, consulte nuestra directiva de soporte técnico.
Requisitos previos
- Una suscripción de Azure
- Una implementación de TokenCredential, como un tipo de credencial de la biblioteca de Azure Identity.
- Para consultar los registros, necesita un área de trabajo de Azure Log Analytics.
- Para consultar las métricas, necesita un recurso de Azure de cualquier tipo (cuenta de almacenamiento, Key Vault, Cosmos DB, etc.).
Instalar el paquete
Instale la biblioteca cliente de consultas de Azure Monitor para JavaScript con npm:
npm install @azure/monitor-query
Creación del cliente
Se requiere un cliente autenticado para consultar registros o métricas. Para autenticarse, en el ejemplo siguiente se usa DefaultAzureCredential del paquete @azure/identity .
import { DefaultAzureCredential } from "@azure/identity";
import { LogsQueryClient, MetricsQueryClient } from "@azure/monitor-query";
const credential = new DefaultAzureCredential();
const logsQueryClient = new LogsQueryClient(credential);
// or
const metricsQueryClient = new MetricsQueryClient(credential);
Configuración de clientes para nubes de Azure no públicas
De forma predeterminada, LogsQueryClient
y MetricsQueryClient
están configurados para conectarse a la nube pública de Azure. Se pueden configurar para conectarse a nubes de Azure no públicas pasando el argumento correcto endpoint
. Por ejemplo:
import { DefaultAzureCredential } from "@azure/identity";
import { LogsQueryClient, MetricsQueryClient } from "@azure/monitor-query";
const credential = new DefaultAzureCredential();
const logsQueryClient = new LogsQueryClient(credential, {
endpoint: "https://api.loganalytics.azure.cn/v1",
});
// or
const metricsQueryClient = new MetricsQueryClient(credential{
endpoint: "https://management.chinacloudapi.cn",
});
Nota: Actualmente, MetricsQueryClient
usa el punto de conexión de Azure Resource Manager (ARM) para consultar métricas, por lo que necesitará el punto de conexión de administración correspondiente para la nube al usar este cliente. Esto está sujeto a cambios en el futuro.
Ejecute la consulta.
Para obtener ejemplos de consultas de registros y métricas, consulte la sección Ejemplos .
Conceptos clave
Registra los límites de frecuencia de consulta y la limitación
El servicio Log Analytics aplica la limitación cuando la tasa de solicitudes es demasiado alta. Los límites, como el número máximo de filas devueltas, también se aplican en las consultas de Kusto. Para más información, consulte Query API.
Estructura de datos de métricas
Cada conjunto de valores de métricas es una serie temporal con las siguientes características:
- Hora en que se recopiló el valor.
- Recurso asociado al valor
- Espacio de nombres que actúa como una categoría para la métrica.
- Nombre de la métrica.
- El propio valor.
- Algunas métricas pueden tener varias dimensiones, como se describe en métricas multidimensionales. Las métricas personalizadas pueden tener hasta 10 dimensiones.
Ejemplos
- consulta de registros
- Consulta de registros de Batch
- Escenarios de consulta de registros avanzados
- Consulta de métricas
consulta de registros
LogsQueryClient
se puede usar para consultar un área de trabajo de Log Analytics mediante el Lenguaje de consulta Kusto. timespan.duration
se puede especificar como una cadena en un formato de duración ISO 8601. Puede usar las Durations
constantes proporcionadas para algunas duraciones ISO 8601 usadas habitualmente.
import { DefaultAzureCredential } from "@azure/identity";
import { Durations, LogsQueryClient, LogsQueryResultStatus, LogsTable } from "@azure/monitor-query";
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.queryWorkspace(azureLogAnalyticsWorkspaceId, kustoQuery, {
duration: Durations.twentyFourHours,
});
if (result.status === LogsQueryResultStatus.Success) {
const tablesFromResult: LogsTable[] = 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);
}
}
}
async function processTables(tablesFromResult: LogsTable[]) {
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);
}
}
}
run().catch((err) => console.log("ERROR:", err));
Control de la respuesta de consulta de registros
La queryWorkspace
función de LogsQueryClient
devuelve un LogsQueryResult
objeto . El tipo de objeto puede ser LogsQuerySuccessfulResult
o LogsQueryPartialResult
. Esta es una jerarquía de la respuesta:
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
Por ejemplo, para controlar una respuesta con tablas:
async function processTables(tablesFromResult: LogsTable[]) {
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);
}
}
}
Puede encontrar un ejemplo completo aquí.
Consulta de registros de Batch
En el ejemplo siguiente se muestra cómo enviar varias consultas al mismo tiempo mediante la API de consulta por lotes. Las consultas se pueden representar como una lista de BatchQuery
objetos.
export async function main() {
if (!monitorWorkspaceId) {
throw new Error("MONITOR_WORKSPACE_ID must be set in the environment for this sample");
}
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++;
}
}
async function processTables(tablesFromResult: LogsTable[]) {
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);
}
}
}
Control de la respuesta de consultas por lotes de registros
La queryBatch
función de LogsQueryClient
devuelve un LogsQueryBatchResult
objeto . LogsQueryBatchResult
contiene una lista de objetos con los siguientes tipos posibles:
LogsQueryPartialResult
LogsQuerySuccessfulResult
LogsQueryError
Esta es una jerarquía de la respuesta:
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")
Por ejemplo, el código siguiente controla una respuesta de consulta de registros por lotes:
async function processBatchResult(result: LogsQueryBatchResult) {
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++;
}
}
async function processTables(tablesFromResult: LogsTable[]) {
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);
}
}
}
Puede encontrar un ejemplo completo aquí.
Escenarios de consulta de registros avanzados
Establecimiento del tiempo de espera de la consulta de registros
Algunas consultas de registros tardan más de 3 minutos en ejecutarse. El tiempo de espera predeterminado del servidor es de 3 minutos. Puede aumentar el tiempo de espera del servidor a un máximo de 10 minutos. En el ejemplo siguiente, la LogsQueryOptions
propiedad del objeto se usa para aumentar el tiempo de espera del serverTimeoutInSeconds
servidor a 10 minutos:
// setting optional parameters
const queryLogsOptions: LogsQueryOptions = {
// 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,
kustoQuery,
{ duration: Durations.twentyFourHours },
queryLogsOptions
);
const tablesFromResult = result.tables;
Consulta de varias áreas de trabajo
La misma consulta de registros se puede ejecutar en varias áreas de trabajo de Log Analytics. Además de la consulta de Kusto, se requieren los parámetros siguientes:
workspaceId
: el primer identificador del área de trabajo (principal).additionalWorkspaces
- Una lista de áreas de trabajo, excepto el área de trabajo proporcionada en elworkspaceId
parámetro . Los elementos de lista del parámetro pueden constar de los siguientes formatos de identificador:- Nombres de área de trabajo calificados
- Identificadores de área de trabajo
- Identificadores de recursos de Azure
Por ejemplo, la siguiente consulta se ejecuta en tres áreas de trabajo:
const queryLogsOptions: LogsQueryOptions = {
additionalWorkspaces: ["<workspace2>", "<workspace3>"],
};
const kustoQuery = "AppEvents | limit 10";
const result = await logsQueryClient.queryWorkspace(
azureLogAnalyticsWorkspaceId,
kustoQuery,
{ duration: Durations.twentyFourHours },
queryLogsOptions
);
Para ver los resultados de cada área de trabajo, use la TenantId
columna para ordenar los resultados o filtrarlos en la consulta de Kusto.
Ordenar los resultados por TenantId
AppEvents | order by TenantId
Filtrar los resultados por TenantId
AppEvents | filter TenantId == "<workspace2>"
Puede encontrar un ejemplo completo aquí.
Incluir estadísticas
Para obtener las estadísticas de ejecución de consultas de registros, como el consumo de CPU y memoria:
- Establezca la propiedad
LogsQueryOptions.includeQueryStatistics
entrue
. - Acceda al
statistics
campo dentro delLogsQueryResult
objeto .
En el ejemplo siguiente se imprime el tiempo de ejecución de la consulta:
const workspaceId = "<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,
}
);
const executionTime =
result.statistics && result.statistics.query && result.statistics.query.executionTime;
console.log(
`Results for query '${kustoQuery}', execution time: ${
executionTime == null ? "unknown" : executionTime
}`
);
Dado que la estructura de la carga varía según la statistics
consulta, se usa un Record<string, unknown>
tipo de valor devuelto. Contiene la respuesta JSON sin formato. Las estadísticas se encuentran dentro de la query
propiedad de JSON. Por ejemplo:
{
"query": {
"executionTime": 0.0156478,
"resourceUsage": {...},
"inputDatasetStatistics": {...},
"datasetStatistics": [{...}]
}
}
Incluir visualización
Para obtener datos de visualización de consultas de registros mediante el operador render:
- Establezca la propiedad
LogsQueryOptions.includeVisualization
entrue
. - Acceda al
visualization
campo dentro delLogsQueryResult
objeto .
Por ejemplo:
const workspaceId = "<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);
Dado que la estructura de la carga varía según la visualization
consulta, se usa un Record<string, unknown>
tipo de valor devuelto. Contiene la respuesta JSON sin formato. Por ejemplo:
{
"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
}
Consulta de métricas
En el ejemplo siguiente se obtienen métricas de una suscripción de Azure Metrics Advisor .
El URI del recurso debe ser el del recurso para el que se consultan las métricas. Normalmente es del formato /subscriptions/<id>/resourceGroups/<rg-name>/providers/<source>/topics/<resource-name>
.
Para buscar el URI del recurso:
- Vaya a la página del recurso en el Azure Portal.
- En la hoja Información general , seleccione el vínculo Vista JSON .
- En el JSON resultante, copie el valor de la
id
propiedad .
import { DefaultAzureCredential } from "@azure/identity";
import { Durations, Metric, MetricsQueryClient } from "@azure/monitor-query";
import * as dotenv from "dotenv";
dotenv.config();
const metricsResourceId = process.env.METRICS_RESOURCE_ID;
export async function main() {
const tokenCredential = new DefaultAzureCredential();
const metricsQueryClient = new MetricsQueryClient(tokenCredential);
if (!metricsResourceId) {
throw new Error("METRICS_RESOURCE_ID must be set in the environment for this sample");
}
const iterator = metricsQueryClient.listMetricDefinitions(metricsResourceId);
let result = await iterator.next();
let metricNames: string[] = [];
for await (const result of iterator) {
console.log(` metricDefinitions - ${result.id}, ${result.name}`);
if (result.name) {
metricNames.push(result.name);
}
}
const firstMetricName = metricNames[0];
const secondMetricName = metricNames[1];
if (firstMetricName && secondMetricName) {
console.log(`Picking an example metric to query: ${firstMetricName} and ${secondMetricName}`);
const metricsResponse = await metricsQueryClient.queryResource(
metricsResourceId,
[firstMetricName, secondMetricName],
{
granularity: "PT1M",
timespan: { duration: Durations.fiveMinutes },
}
);
console.log(
`Query cost: ${metricsResponse.cost}, interval: ${metricsResponse.granularity}, time span: ${metricsResponse.timespan}`
);
const metrics: Metric[] = metricsResponse.metrics;
console.log(`Metrics:`, JSON.stringify(metrics, undefined, 2));
const metric = metricsResponse.getMetricByName(firstMetricName);
console.log(`Selected Metric: ${firstMetricName}`, JSON.stringify(metric, undefined, 2));
} else {
console.error(`Metric names are not defined - ${firstMetricName} and ${secondMetricName}`);
}
}
main().catch((err) => {
console.error("The sample encountered an error:", err);
process.exit(1);
});
En el ejemplo anterior, los resultados metricsResponse
de la métrica se ordenan según el orden en que el usuario especifica los nombres de métrica en el metricNames
argumento de matriz de la queryResource
función. Si el usuario especifica [firstMetricName, secondMetricName]
, el resultado firstMetricName
de aparecerá antes del resultado de secondMetricName
en metricResponse
.
Control de la respuesta de consulta de métricas
La función metrics queryResource
devuelve un QueryMetricsResult
objeto . El QueryMetricsResult
objeto contiene propiedades como una lista de Metric
objetos con tipo , interval
namespace
, y timespan
. Se Metric
puede tener acceso a la lista de objetos mediante la metrics
propiedad . Cada Metric
objeto de esta lista contiene una lista de TimeSeriesElement
objetos . Cada TimeSeriesElement
contiene data
las propiedades y metadataValues
. En forma visual, la jerarquía de objetos de la respuesta es similar a la estructura siguiente:
QueryMetricsResult
|---cost
|---timespan (of type `QueryTimeInterval`)
|---granularity
|---namespace
|---resourceRegion
|---metrics (list of `Metric` objects)
|---id
|---type
|---name
|---unit
|---displayDescription
|---errorCode
|---timeseries (list of `TimeSeriesElement` objects)
|---metadataValues
|---data (list of data points represented by `MetricValue` objects)
|---timeStamp
|---average
|---minimum
|---maximum
|---total
|---count
|---getMetricByName(metricName): Metric | undefined (convenience method)
Ejemplo de control de la respuesta
import { DefaultAzureCredential } from "@azure/identity";
import { Durations, Metric, MetricsQueryClient } from "@azure/monitor-query";
import * as dotenv from "dotenv";
dotenv.config();
const metricsResourceId = process.env.METRICS_RESOURCE_ID;
export async function main() {
const tokenCredential = new DefaultAzureCredential();
const metricsQueryClient = new MetricsQueryClient(tokenCredential);
if (!metricsResourceId) {
throw new Error(
"METRICS_RESOURCE_ID for an Azure Metrics Advisor subscription must be set in the environment for this sample"
);
}
console.log(`Picking an example metric to query: MatchedEventCount`);
const metricsResponse = await metricsQueryClient.queryResource(
metricsResourceId,
["MatchedEventCount"],
{
timespan: {
duration: Durations.fiveMinutes,
},
granularity: "PT1M",
aggregations: ["Count"],
}
);
console.log(
`Query cost: ${metricsResponse.cost}, granularity: ${metricsResponse.granularity}, time span: ${metricsResponse.timespan}`
);
const metrics: Metric[] = metricsResponse.metrics;
for (const metric of metrics) {
console.log(metric.name);
for (const timeseriesElement of metric.timeseries) {
for (const metricValue of timeseriesElement.data!) {
if (metricValue.count !== 0) {
console.log(`There are ${metricValue.count} matched events at ${metricValue.timeStamp}`);
}
}
}
}
}
main().catch((err) => {
console.error("The sample encountered an error:", err);
process.exit(1);
});
Puede encontrar un ejemplo completo aquí.
Solución de problemas
Registro
La habilitación del registro puede ayudar a descubrir información útil sobre los errores. Para ver un registro de solicitudes y respuestas HTTP, establezca la AZURE_LOG_LEVEL
variable info
de entorno en . Como alternativa, el registro se puede habilitar en tiempo de ejecución llamando a setLogLevel
en @azure/logger
:
import { setLogLevel } from "@azure/logger";
setLogLevel("info");
Para obtener instrucciones detalladas sobre cómo habilitar los registros, consulte la documentación del paquete de @azure/registrador.
Pasos siguientes
Para más información sobre Azure Monitor, consulte la documentación del servicio Azure Monitor.
Contribuciones
Si desea contribuir a esta biblioteca, lea la guía de contribución para obtener más información sobre cómo compilar y probar el código.
Las pruebas de este módulo son una combinación de pruebas dinámicas y unitarias, que requieren que tenga una instancia de Azure Monitor. Para ejecutar las pruebas, deberá ejecutar:
rush update
rush build -t @azure/monitor-query
cd into sdk/monitor/monitor-query
- Copiar el
sample.env
archivo en.env
- Abra el
.env
archivo en un editor y rellene los valores. npm run test
.
Para obtener más información, consulte nuestra carpeta de pruebas .
Proyectos relacionados
Azure SDK for JavaScript
Comentarios
https://aka.ms/ContentUserFeedback.
Próximamente: a lo largo de 2024, eliminaremos gradualmente los problemas de GitHub como mecanismo de comentarios para el contenido y lo reemplazaremos por un nuevo sistema de comentarios. Para obtener más información, consulte:Enviar y ver comentarios de