使用 Application Insights 监视 Node.js 服务和应用

Application Insights 会在部署后对组件进行监视,以便发现性能问题和其他问题。 可以将 Application Insights 用于 Node.js 服务,不管这些服务是托管在数据中心、Azure VM 和 Web 应用中,还是在其他公有云中。

若要接收、存储和探索监视数据,请将 SDK 包括到代码中。 然后在 Azure 中设置相应的 Application Insights 资源。 SDK 会将数据发送到该资源进行进一步的分析和探索。

Node.js 客户端库可以自动监视传入和传出的 HTTP 请求、异常和某些系统指标。 从 0.20 版开始,客户端库也可监视某些常用的第三方程序包,例如 MongoDB、MySQL、Redis。

所有与传入 HTTP 请求相关的事件都会进行关联,以加快故障排除速度。

可以使用 TelemetryClient API 手动检测和监视应用和系统的其他方面。 本文后面会更详细地介绍 TelemetryClient API。

注意

以下文档依赖于 Application Insights 经典 API。 Application Insights 的长期计划是使用 OpenTelemetry 收集数据。 有关详细信息,请参阅为 .NET、Node.js、Python 和 Java 应用程序启用 Azure Monitor OpenTelemetry

开始使用

请完成以下任务,为应用或服务设置监视。

先决条件

开始之前,请确保拥有 Azure 订阅,否则请获取一个新的试用版。 如果组织已经拥有 Azure 订阅,管理员可以按照这些说明将你添加到该订阅。

设置 Application Insights 资源

  1. 登录到 Azure 门户
  2. 创建 Application Insights 资源

注意

对检测密钥引入的支持将于 2025 年 3 月 31 日结束。 检测密钥引入功能将会继续工作,但我们将不再为该功能提供更新或支持。 转换为连接字符串,以利用新功能

设置 Node.js 客户端库

将 SDK 包括到应用中,使之能够收集数据。

  1. 从新资源复制资源的连接字符串。 Application Insights 使用连接字符串将数据映射到 Azure 资源。 必须在环境变量或代码中指定连接字符串,然后 SDK 才能使用该连接字符串。

    Screenshot that shows the Application Insights overview and connection string.

  2. 通过 package.json 将 Node.js 客户端库添加到应用的依赖项。 从应用的根文件夹,运行:

    npm install applicationinsights --save
    

    注意

    如果使用 TypeScript,请勿安装单独的“typings”包。 此 NPM 包包含内置的 typings。

  3. 将该库显式加载到代码中。 由于 SDK 将检测注入到许多其他库中,请尽早加载该库,甚至应赶在其他 require 语句之前加载。

    let appInsights = require('applicationinsights');
    
  4. 也可通过环境变量 APPLICATIONINSIGHTS_CONNECTION_STRING 来提供连接字符串,不必手动将其传递给 setup()new appInsights.TelemetryClient()。 这种做法允许将连接字符串脱离已提交的源代码,因此可以为不同的环境指定不同的连接字符串。 若要手动进行配置,请调用 appInsights.setup('[your connection string]');

    有关其他配置选项,请参阅以下各节。

    可以设置 appInsights.defaultClient.config.disableAppInsights = true,尝试在不发送遥测的情况下使用 SDK。

  5. 开始通过调用 appInsights.start(); 自动收集和发送数据。

注意

在使用 Application Insights 检测的过程中,我们会收集诊断数据并将其发送给 Microsoft。 这些数据可帮助我们运行和改进 Application Insights。 可以选择禁用非基本数据的收集。 了解详细信息

监视应用

SDK 会自动收集有关 Node.js 运行时和一些常见第三方模块的遥测。 请使用应用程序生成部分此类数据。

然后,在 Azure 门户中转到此前创建的 Application Insights 资源。 在“概览时间线”中,查找前面的几个数据点。 若要查看更多详细数据,请在图表中选择不同的组件。

若要查看应用的已发现拓扑,可以使用应用程序映射

无数据

由于 SDK 对要提交的数据进行批处理,项目在门户中显示之前可能会有一段延迟。 如果在资源中看不到数据,可尝试下面的部分修复手段:

  • 继续使用应用程序。 通过更多操作生成更多遥测。
  • 在门户资源视图中选择“刷新”。 图表会定期自行刷新,但手动刷新会强制图表立刻刷新。
  • 验证所需传出端口是否已打开。
  • 使用搜索查找特定事件。
  • 查看常见问题

基本用法

对于开箱即用的 HTTP 请求集合、受欢迎的第三方库事件、未经处理的异常和系统指标:


let appInsights = require("applicationinsights");
appInsights.setup("[your connection string]").start();

注意

如果在环境变量 APPLICATIONINSIGHTS_CONNECTION_STRING 中设置连接字符串,则无需使用参数即可调用 .setup()。 这样就可以轻松地针对不同环境使用不同的连接字符串。

加载其他包之前,请尽早在脚本中加载 Application Insights 库 require("applicationinsights")。 此步骤是必需的,这样 Application Insights 库才能为跟踪准备更高版本的包。 如果与执行类似准备的其他库发生冲突,请尝试稍后加载 Application Insights 库。

由于 JavaScript 处理回调的方式,需要执行额外的工作,以跟踪跨外部依赖项和更高版本回调的请求。 默认情况下,此额外跟踪处于启用状态。 通过调用 setAutoDependencyCorrelation(false) 将其禁用,如 SDK 配置 部分所述。

从版本 0.22 之前的版本进行迁移

这些是版本 0.22 及更高版本之前的版本之间的重大更改。 这些更改旨在与其他 Application Insights SDK 保持一致并允许将来进行扩展。

通常,可以通过以下操作进行迁移:

  • appInsights.defaultClient 替换对 appInsights.client 的引用。
  • new appInsights.TelemetryClient() 替换对 appInsights.getClient() 的引用。
  • 将所有参数替换为 client.track* 方法,其中有一个包含命名属性的对象用作参数。 有关每种类型的遥测的例外对象,请参阅 IDE 的内置类型提示或 TelemetryTypes

如果在不将 SDK 配置函数链接到 appInsights.setup() 的情况下访问这些函数,现在可以在 appInsights.Configurations 中找到这些函数。 例如 appInsights.Configuration.setAutoCollectDependencies(true)。 查看下一节中对默认配置所做的更改。

SDK 配置

appInsights 对象提供了许多配置方法。 以下代码片段中列出了这些方法及其默认值。

let appInsights = require("applicationinsights");
appInsights.setup("<connection_string>")
    .setAutoDependencyCorrelation(true)
    .setAutoCollectRequests(true)
    .setAutoCollectPerformance(true, true)
    .setAutoCollectExceptions(true)
    .setAutoCollectDependencies(true)
    .setAutoCollectConsole(true)
    .setUseDiskRetryCaching(true)
    .setSendLiveMetrics(false)
    .setDistributedTracingMode(appInsights.DistributedTracingModes.AI)
    .start();

若要让服务中的事件完全相关联,请确保设置 .setAutoDependencyCorrelation(true)。 设置此选项以后,SDK 即可在 Node.js 中跨异步回调跟踪上下文。

请在 IDE 的内置类型提示或 applicationinsights.ts 中查看其说明,了解详细信息和可选的辅助参数。

注意

默认情况下,setAutoCollectConsole 配置为排除对 console.log(以及其他控制台方法)的调用。 将只收集对受支持的第三方记录器(例如 winston 和 bunyan)的调用。 你可以通过使用 setAutoCollectConsole(true, true) 将此行为更改为包括对 console 方法的调用。

采样

默认情况下,SDK 会将收集的所有数据发送到 Application Insights 服务。 如果要启用采样以减少数据量,请在客户端的 config 对象上设置 samplingPercentage 字段。 将 samplingPercentage 设置为 100(默认值)表示将发送所有数据,设置为 0 则表示不会发送任何内容。

如果使用自动关联,则会将与单个请求关联的所有数据作为一个单元包括或排除。

若要启用采样,请添加以下代码:

const appInsights = require("applicationinsights");
appInsights.setup("<connection_string>");
appInsights.defaultClient.config.samplingPercentage = 33; // 33% of all telemetry will be sent to Application Insights
appInsights.start();

多组件应用程序的多个角色

在某些情况下,应用程序可能包含多个组件,你希望使用相同的连接字符串对所有这些组件进行检测。 你希望仍将这些组件视为门户中的单独单元,就像它们使用的是单独的连接字符串一样。 例如,应用程序映射上的单独节点。 需要手动配置 RoleName 字段,以便将一个组件的遥测与发送到 Application Insights 资源的其他组件区分开来。

使用以下代码设置 RoleName 字段:

const appInsights = require("applicationinsights");
appInsights.setup("<connection_string>");
appInsights.defaultClient.context.tags[appInsights.defaultClient.context.keys.cloudRole] = "MyRoleName";
appInsights.start();

浏览器 SDK 加载程序

注意

以公共预览版的形式提供。 Azure 预览版补充使用条款

可以在配置中通过 JavaScript (Web) SDK 加载程序脚本注入为节点服务器启用自动 Web 检测。

let appInsights = require("applicationinsights");
appInsights.setup("<connection_string>")
    .enableWebInstrumentation(true)
    .start();

或设置环境变量 APPLICATIONINSIGHTS_WEB_INSTRUMENTATION_ENABLED = true 为节点服务器启用自动 Web 检测。

满足以下所有要求时,将对节点服务器响应启用 Web 检测:

  • 响应的状态代码为 200
  • 响应方法为 GET
  • 服务器响应具有 Content-Type html。
  • 服务器响应同时包含 <head></head> 标记。
  • 如果响应已压缩,则它必须只有一种 Content-Encoding 类型,并且编码类型必须是 gzipbrdeflate 中的一种。
  • 响应不包含当前的 /backup Web 检测 CDN 终结点。 (此处为当前和备份 Web 检测 CDN 终结点)

可以通过设置环境变量 APPLICATIONINSIGHTS_WEB_INSTRUMENTATION_SOURCE = "web Instrumentation CDN endpoints" 来更改 Web 检测 CDN 终结点。 可以通过设置环境变量 APPLICATIONINSIGHTS_WEB_INSTRUMENTATION_CONNECTION_STRING = "web Instrumentation connection string" 来更改 Web 检测连接字符串

注意

Web 检测可能会减慢服务器响应时间,尤其是在响应大小较大或响应已压缩时。 对于应用某些中间层的情况,可能会导致 Web 检测不起作用,并且将返回原始响应。

自动第三方检测

为了跨异步调用跟踪上下文,某些第三方库(如 MongoDB 和 Redis)需要进行一些更改。 默认情况下,Application Insights 将使用 diagnostic-channel-publishers 以对其中部分库进行猴式修补。 可通过设置 APPLICATION_INSIGHTS_NO_DIAGNOSTIC_CHANNEL 环境变量禁用此功能。

注意

设置该环境变量后,事件可能不会与正确的操作正确关联。

可以通过将 APPLICATION_INSIGHTS_NO_PATCH_MODULES 环境变量设置为要禁用的包的逗号分隔列表来禁用单个猴子补丁。 例如,使用 APPLICATION_INSIGHTS_NO_PATCH_MODULES=console,redis 以避免修补 consoleredis 包。

目前已检测到 9 个包:bunyanconsolemongodbmongodb-coremysqlrediswinstonpgpg-pool。 有关修补这些包的哪个确切版本的信息,请访问 diagnostic-channel-publishers 自述文件

bunyanwinstonconsole 补丁会根据是否启用 setAutoCollectConsole 生成 Application Insights 跟踪事件。 其余补丁会根据是否启用 setAutoCollectDependencies 生成 Application Insights 依赖项事件。

实时指标

若要允许将实时指标从应用发送到 Azure,请使用 setSendLiveMetrics(true)。 目前,不支持在门户中筛选实时指标。

扩展指标

注意

1.4.0 版本中添加了发送扩展本机指标的功能。

若要允许将扩展本机指标从应用发送到 Azure,请安装单独的本机指标包。 SDK 会在安装后自动加载,并开始收集 Node.js 原生指标。

npm install applicationinsights-native-metrics

目前,本机指标包会自动收集垃圾回收 CPU 时间、事件循环计时和堆使用情况:

  • 垃圾回收:每种类型的垃圾回收所用的 CPU 时间,以及每种类型出现的次数。
  • 事件循环:发生了多少个计时周期,以及总共花费了多少 CPU 时间。
  • 堆与非堆:应用的内存使用量有多少位于堆或非堆中。

分布式跟踪模式

默认情况下,SDK 会发送被其他应用程序或服务理解的标头,可通过 Application Insights SDK 检测到此类应用程序或服务。 除了现有的 AI 标头,还可以启用 W3C 跟踪上下文标头的发送和接收。 这样就不会中断与任何现有旧服务的关联。 通过启用 W3C 标头,可将应用与未通过 Application Insights 检测的其他服务关联,但会采用这一 W3C 标准。

const appInsights = require("applicationinsights");
appInsights
  .setup("<your connection string>")
  .setDistributedTracingMode(appInsights.DistributedTracingModes.AI_AND_W3C)
  .start()

TelemetryClient API

有关 TelemetryClient API 的完整说明,请参阅用于处理自定义事件和指标的 Application Insights API

可以使用 Node.js 的 Application Insights 客户端库跟踪任何请求、事件、指标或异常。 以下代码示例演示了部分可用 API:

let appInsights = require("applicationinsights");
appInsights.setup().start(); // assuming connection string in env var. start() can be omitted to disable any non-custom data
let client = appInsights.defaultClient;
client.trackEvent({name: "my custom event", properties: {customProperty: "custom property value"}});
client.trackException({exception: new Error("handled exceptions can be logged with this method")});
client.trackMetric({name: "custom metric", value: 3});
client.trackTrace({message: "trace message"});
client.trackDependency({target:"http://dbname", name:"select customers proc", data:"SELECT * FROM Customers", duration:231, resultCode:0, success: true, dependencyTypeName: "ZSQL"});
client.trackRequest({name:"GET /customers", url:"http://myserver/customers", duration:309, resultCode:200, success:true});

let http = require("http");
http.createServer( (req, res) => {
  client.trackNodeHttpRequest({request: req, response: res}); // Place at the beginning of your request handler
});

跟踪依赖项

使用以下代码跟踪依赖项:

let appInsights = require("applicationinsights");
let client = new appInsights.TelemetryClient();

var success = false;
let startTime = Date.now();
// execute dependency call here....
let duration = Date.now() - startTime;
success = true;

client.trackDependency({target:"http://dbname", name:"select customers proc", data:"SELECT * FROM Customers", duration:duration, resultCode:0, success: true, dependencyTypeName: "ZSQL"});;

使用 trackMetric 度量事件循环计划所花费的时间的示例实用工具:

function startMeasuringEventLoop() {
  var startTime = process.hrtime();
  var sampleSum = 0;
  var sampleCount = 0;

  // Measure event loop scheduling delay
  setInterval(() => {
    var elapsed = process.hrtime(startTime);
    startTime = process.hrtime();
    sampleSum += elapsed[0] * 1e9 + elapsed[1];
    sampleCount++;
  }, 0);

  // Report custom metric every second
  setInterval(() => {
    var samples = sampleSum;
    var count = sampleCount;
    sampleSum = 0;
    sampleCount = 0;

    if (count > 0) {
      var avgNs = samples / count;
      var avgMs = Math.round(avgNs / 1e6);
      client.trackMetric({name: "Event Loop Delay", value: avgMs});
    }
  }, 1000);
}

将自定义属性添加到所有事件

使用以下代码向所有事件添加自定义属性:

appInsights.defaultClient.commonProperties = {
  environment: process.env.SOME_ENV_VARIABLE
};

跟踪 HTTP GET 请求

使用以下代码手动跟踪 HTTP GET 请求:

注意

默认情况下跟踪所有请求。 若要禁用自动收集,请在调用 start() 之前调用 .setAutoCollectRequests(false)

appInsights.defaultClient.trackRequest({name:"GET /customers", url:"http://myserver/customers", duration:309, resultCode:200, success:true});

也可使用 trackNodeHttpRequest 方法跟踪请求:

var server = http.createServer((req, res) => {
  if ( req.method === "GET" ) {
      appInsights.defaultClient.trackNodeHttpRequest({request:req, response:res});
  }
  // other work here....
  res.end();
});

跟踪服务器启动时间

使用以下代码跟踪服务器启动时间:

let start = Date.now();
server.on("listening", () => {
  let duration = Date.now() - start;
  appInsights.defaultClient.trackMetric({name: "server startup time", value: duration});
});

刷新

默认情况下,遥测数据在发送到引入服务器之前会缓冲 15 秒。 如果应用程序的生存期较短(例如 CLI 工具就是如此),则可能需要在应用程序终止时使用 appInsights.defaultClient.flush() 手动刷新缓冲的遥测。

如果 SDK 检测到应用程序正在崩溃,它会使用 appInsights.defaultClient.flush({ isAppCrashing: true }) 为你调用刷新。 如果使用刷新选项 isAppCrashing,应用程序会被认为处于异常状态,不适合发送遥测。 改为由 SDK 把所有缓冲的遥测数据保存到持久存储,并让应用程序终止。 当应用程序重新启动时,它会尝试发送已保存到持久存储中的遥测数据。

使用遥测处理器预处理数据

在发送收集的数据进行保留之前,可以使用遥测处理器来处理和筛选这些数据。 遥测处理器在遥测项发送到云之前按其添加顺序依次调用。

public addTelemetryProcessor(telemetryProcessor: (envelope: Contracts.Envelope, context: { http.RequestOptions, http.ClientRequest, http.ClientResponse, correlationContext }) => boolean)

如果遥测处理器返回 false,则不会发送该遥测项。

所有遥测处理器都接收遥测数据及其信封来检查和修改。 它们还会接收上下文对象。 在为手动跟踪的遥测调用跟踪方法时,此对象的内容由 contextObjects 参数定义。 对于自动收集的遥测,此对象使用 appInsights.getCorrelationContext() 提供的可用请求信息和持久性请求内容(如果启用了自动相关性关联)进行填充。

遥测处理器的 TypeScript 类型为:

telemetryProcessor: (envelope: ContractsModule.Contracts.Envelope, context: { http.RequestOptions, http.ClientRequest, http.ClientResponse, correlationContext }) => boolean;

例如,可以按如下所示编写并添加从异常中删除堆栈跟踪数据的处理器:

function removeStackTraces ( envelope, context ) {
  if (envelope.data.baseType === "Microsoft.ApplicationInsights.ExceptionData") {
    var data = envelope.data.baseData;
    if (data.exceptions && data.exceptions.length > 0) {
      for (var i = 0; i < data.exceptions.length; i++) {
        var exception = data.exceptions[i];
        exception.parsedStack = null;
        exception.hasFullStack = false;
      }
    }
  }
  return true;
}

appInsights.defaultClient.addTelemetryProcessor(removeStackTraces);

使用多个连接字符串

可以创建多个 Application Insights 资源,并使用各自的连接字符串将不同数据发送到每个资源。

例如:

let appInsights = require("applicationinsights");

// configure auto-collection under one connection string
appInsights.setup("Connection String A").start();

// track some events manually under another connection string
let otherClient = new appInsights.TelemetryClient("Connection String B");
otherClient.trackEvent({name: "my custom event"});

高级配置选项

客户端对象包含一个 config 属性,该属性具有多个适用于高级方案的可选设置。 若要设置它们,请使用:

client.config.PROPERTYNAME = VALUE;

这些属性是特定于客户端的,因此你可以从使用 new appInsights.TelemetryClient() 创建的客户端单独配置 appInsights.defaultClient

Property 说明
connectionString Application Insights 资源的标识符。
endpointUrl 接收遥测有效负载的引入终结点。
quickPulseHost 接收实时指标遥测的实时指标流主机。
proxyHttpUrl SDK HTTP 流量的代理服务器。 (可选。默认值是从 http_proxy 环境变量拉取的。)
proxyHttpsUrl SDK HTTPS 流量的代理服务器。 (可选。默认值是从 https_proxy 环境变量拉取的。)
httpAgent 用于 SDK HTTP 流量的 http.Agent。 (可选。默认为未定义。)
httpsAgent 用于 SDK HTTPS 流量的 https.Agent。 (可选。默认为未定义。)
maxBatchSize 要包括在引入终结点的有效负载中的最大遥测项数。 (默认为 250。)
maxBatchIntervalMs 有效负载达到 maxBatchSize 之前要等待的最长时间。 (默认为 15000。)
disableAppInsights 一个标志,用于指示是否禁用遥测传输。 (默认为 false。)
samplingPercentage 应传输的已跟踪遥测项的百分比。 (默认为 100。)
correlationIdRetryIntervalMs 重试检索交叉组件相关的 ID 之前要等待的时间。 (默认为 30000。)
correlationHeaderExcludedDomains 要从交叉组件相关标头注入中排除的域列表。 (默认值,请参阅 Config.ts。)

疑难解答

有关故障排除信息(包括“无数据”方案和自定义日志),请参阅对 Node.js 应用和服务的 Application Insights 监视进行故障排除

后续步骤