Vercel Serverless Functions集成Elastic APM无数据接收问题求助
问题详情
我把NextJS应用和Elastic APM做了集成,核心逻辑是在每个API请求里初始化apm对象,收集请求链路并发送到Elastic APM。这套方案在本地开发和Docker部署环境都能正常工作,但部署到Vercel转为Serverless Functions后,Elastic APM始终收不到数据。
Serverless函数日志最后一行显示APM在尝试发送span,但数据没到APM服务器:
{ "log.level": "debug", "@timestamp": "2024-04-18T08:45:47.694Z", "log.logger": "elastic-apm-node", "ecs.version": "8.10.0", "message": "sending span {\"span\":\"08ffc510e6b2a80d\",\"parent\":\"42b99f30dbacb024\",\"trace\":\"f03e53c3d6846a888f8f69c753b3aa81\",\"name\":\"POST xxxx.ingest.sentry.io\",\"type\":\"external\"}" }
我的APM初始化文件apm.ts代码:
import apm from 'elastic-apm-node'; if (!apm.isStarted()) { apm.start({ // 配置信息 }); } export default apm;
API处理文件apiHandler.ts中设置上下文的代码:
apm.setUserContext({ email: session.user.email, id: session.user.id, }); apm.setCustomContext({});
本地环境的APM能正常显示应用数据,但Vercel部署后完全没数据。
核心原因
Vercel Serverless Functions是短生命周期的无状态函数,函数执行完成后会立刻被销毁。而Elastic APM Node.js agent默认是异步发送数据的,这就导致函数结束时,APM的上报请求还没发完就被终止,数据根本传不到服务器。
解决步骤
强制等待APM数据上报完成
在API请求处理的最后,手动调用apm.flush()并等待它执行完毕,确保所有未发送的APM数据都提交成功。修改apiHandler.ts:// 放在请求响应返回前的最后一步 await apm.flush();如果用的是App Router的Server Components或者
getServerSideProps,一定要保证在请求生命周期结束前执行这个操作。核对Vercel环境下的APM配置
确保APM的serverUrl、secretToken、serviceName这些核心配置是通过Vercel环境变量传递的(别硬编码),并且在初始化时明确指定环境标识:apm.start({ serviceName: 'your-service-name', serverUrl: process.env.ELASTIC_APM_SERVER_URL, secretToken: process.env.ELASTIC_APM_SECRET_TOKEN, environment: process.env.NODE_ENV || 'production', logLevel: 'debug' // 开启调试方便排查 });检查Vercel网络权限
Vercel Serverless Functions对外请求有默认限制,要确认Elastic APM的服务地址在Vercel的出站白名单里。如果是私有部署的APM服务,可能需要配置Vercel的VPC访问或者使用代理。调整APM Agent的适配参数
针对Serverless的短生命周期特性,调整Agent的超时和队列设置,避免函数超时:apm.start({ // 其他配置 apiRequestTime: 5000, // 上报请求超时时间,单位毫秒 apiRequestSize: 768 * 1024, queueLimit: 1000 });验证函数执行时长
查看Vercel函数的执行日志,确认函数是在apm.flush()完成后才结束的。如果函数执行时间太短,可以加一点微小延迟,但别太长,避免影响性能。
内容的提问来源于stack exchange,提问作者Ilham Fadhilah

