创建和上传源映射 (RUM)
Elastic Stack
在生产环境中压缩 JavaScript 包是一种常见的做法;它可以大大提高应用程序的加载时间和网络延迟。压缩代码的问题在于它可能难以调试。
为了获得最佳效果,上传 Source Map 应成为部署流程的一部分,而不是等到看到无用的错误时才进行。这是因为在错误发生后上传 Source Map 无法让旧错误神奇地变得可读——错误必须再次发生,Source Map 才能生效。
当使用压缩后的代码时,这是 Applications UI 中异常堆栈跟踪的一个示例。正如您所见,它并没有太大帮助。
通过 Source Map,压缩后的文件可以映射回原始源代码,让您在保持压缩代码的性能优势的同时,又不损失快速轻松调试应用程序的能力。这是之前相同的示例,但上传并应用了 Source Map
请按照以下步骤在 Applications UI 中启用 Source Map 来处理错误堆栈跟踪
在初始化 RUM Agent 时设置应用程序的服务名称和版本。为了更轻松地上传后续的 Source Map,您选择的 serviceVersion 可以是 package.json 中的 version。例如:
import { init as initApm } from '@elastic/apm-rum'
const serviceVersion = require("./package.json").version
const apm = initApm({
serviceName: 'myService',
serviceVersion: serviceVersion
})
或者,serviceVersion 可以是一个 git 提交引用。例如:
const git = require('git-rev-sync')
const serviceVersion = git.short()
它也可以是任何其他表示应用程序特定版本的唯一字符串。APM 集成使用服务名称和版本来匹配正确的 Source Map 文件到每个堆栈跟踪。
为了与 Elastic APM 兼容,Source Map 必须遵循 Source Map Revision 3 Proposal 规范。
Source Map 的生成和配置方式有很多种。例如,parcel 默认会自动生成 Source Map。如果您使用的是 webpack,可能需要一些配置来生成 Source Map。
const webpack = require('webpack')
const serviceVersion = require("./package.json").version
const TerserPlugin = require('terser-webpack-plugin');
module.exports = {
entry: 'app.js',
output: {
filename: 'app.min.js',
path: './dist'
},
devtool: 'source-map',
plugins: [
new webpack.DefinePlugin({'serviceVersion': JSON.stringify(serviceVersion)}),
new TerserPlugin({
sourceMap: true
})
]
}
- 如果您使用其他方法定义
serviceVersion,可以在此处设置。
上传 Source Map 时,请确保 APM 集成中启用了 RUM 支持。
Kibana 暴露了一个用于上传 Source Map 的 Source Map 端点。Source Map 可以作为字符串上传,也可以作为文件上传。
让我们看看上传 Source Map 的两种不同方式:curl 和自定义应用程序。每个示例都包含 APM Server 稍后将压缩的代码映射到其源所需的四个字段
service_name:应与第一步中的serviceName匹配。service_version:应与第一步中的serviceVersion匹配。bundle_filepath:Web 应用程序中使用的最终 bundle 的绝对路径。sourcemap:Source Map 的位置。
如果您有多个 Source Map,则需要单独上传每个 Source Map。
这是一个 curl 请求示例,用于上传上一步创建的 Source Map 文件。此请求使用 API 密钥进行身份验证。
SERVICEVERSION=`node -e "console.log(require('./package.json').version);"` && \ <1> curl -X POST "https://:5601/api/apm/sourcemaps" \
-H 'Content-Type: multipart/form-data' \
-H 'kbn-xsrf: true' \
-H 'Authorization: ApiKey ${YOUR_API_KEY}' \
-F 'service_name=foo' \
-F 'service_version=$SERVICEVERSION' \
-F 'bundle_filepath=/test/e2e/general-usecase/app.min.js' \
-F 'sourcemap=@./dist/app.min.js.map'
- 此示例使用了
package.json中的版本 - 此处使用的 API 密钥需要具有适当的权限。请参考 Elastic Stack 或 Serverless API 文档。
为了确保上传 Source Map 成为部署流程的一部分,请考虑通过自定义应用程序来自动化该过程。这是一个 Node.js 应用程序示例,用于上传上一步创建的 Source Map 文件
console.log('Uploading sourcemaps!')
var request = require('request')
var filepath = './dist/app.min.js.map'
var formData = {
headers: {
Content-Type: 'multipart/form-data',
kbn-xsrf: 'true',
Authorization: 'ApiKey ${YOUR_API_KEY}'
},
service_name: 'service-name’,
service_version: require("./package.json").version,
bundle_filepath: 'https:///app.min.js',
sourcemap: fs.readFileSync(filepath, { encoding: 'utf-8' })
}
request.post({url: 'https://:5601/api/apm/sourcemaps',formData: formData}, function (err, resp, body) {
if (err) {
console.log('Error while uploading sourcemaps!', err)
} else {
console.log('Sourcemaps uploaded!')
}
})
- 或者使用 'git-rev-sync' 来获取 git 提交哈希
Source Map 存储在 Elasticsearch 中。当您上传 Source Map 时,会创建一个新的 Elasticsearch 文档,其中包含 Source Map 的内容。当 RUM 请求到来时,APM Server 将利用这些 Source Map 文档来将 Source Map 逻辑应用于事件的堆栈跟踪。