如何为Angular Universal项目集成Open Telemetry?
问题背景
想给Node.js Angular Universal应用添加OpenTelemetry追踪与指标功能,但官方文档里的启动命令 node --require ./instrumentation.js app.js 没法直接用——因为项目的构建、运行流程被@nguniversal/builders:ssr-dev-server(开发环境)和@angular-devkit/build-angular:server(生产构建)封装了。直接在项目里导入instrumentation.js还会触发以下错误:
./node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/instrumentation/build/esm/platform/node/instrumentation.js:89:29-50 - Warning: Critical dependency: the request of a dependency is an expression
./node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/instrumentation/build/esm/platform/node/instrumentation.js:102:20-63 - Warning: Critical dependency: the request of a dependency is an expression
Error: ENOENT: no such file or directory, open '/Users/USERNAME/projects/project/dist/apps/project/server/jaeger-idl/thrift/jaeger.thrift'
解决方法
1. 绕过Webpack打包,直接在Node启动时加载Instrumentation
Angular Universal的SSR服务本质还是Node.js应用,我们可以修改启动逻辑,让Node在加载Angular构建后的服务端代码前先加载instrumentation:
开发环境
修改package.json里的开发启动脚本,替换原有serve-ssr命令:
{ "scripts": { "serve-ssr-with-otel": "ng build && ng run project:server:dev && node --require ./instrumentation.js dist/apps/project/server/main.js" } }
执行时直接运行npm run serve-ssr-with-otel即可完成构建+带OpenTelemetry的SSR启动。
生产环境
生产构建完成后,直接用Node命令启动服务端文件并加载instrumentation:
node --require ./instrumentation.js dist/apps/project/server/main.js
2. 修复Webpack打包依赖错误(若需在代码中导入instrumentation)
如果必须在Angular服务端代码中导入instrumentation,需调整Webpack配置避免处理OpenTelemetry的动态依赖:
- 在项目根目录创建
webpack.server.config.js:
module.exports = { externals: { '@opentelemetry/instrumentation': 'commonjs @opentelemetry/instrumentation', '@opentelemetry/sdk-node': 'commonjs @opentelemetry/sdk-node', // 所有OpenTelemetry相关包都设为external,跳过Webpack打包 }, resolve: { extensions: ['.js', '.ts'] } };
- 修改
angular.json中的server builder配置,指定自定义Webpack文件:
{ "projects": { "project": { "architect": { "server": { "builder": "@angular-devkit/build-angular:server", "options": { "outputPath": "dist/apps/project/server", "main": "projects/project/server.ts", "tsConfig": "projects/project/tsconfig.server.json", "webpackConfig": "webpack.server.config.js" } } } } } }
- 针对
jaeger.thrift找不到的问题,改用Jaeger的HTTP exporter替代Thrift:
// instrumentation.js const { NodeSDK } = require('@opentelemetry/sdk-node'); const { HttpExporter } = require('@opentelemetry/exporter-jaeger'); const sdk = new NodeSDK({ traceExporter: new HttpExporter({ url: 'http://你的Jaeger采集地址:14268/api/traces' }), // 其他OpenTelemetry配置 }); sdk.start();
3. 用环境变量自动加载Instrumentation
利用Node.js的NODE_OPTIONS环境变量,在启动Angular SSR命令前注入--require参数,无需修改原有构建流程:
NODE_OPTIONS="--require ./instrumentation.js" ng run project:serve-ssr
也可以把这个命令写到package.json的脚本里:
"serve-ssr-otel": "NODE_OPTIONS='--require ./instrumentation.js' ng run project:serve-ssr"
内容的提问来源于stack exchange,提问作者Syperia

