拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Artillery 自定义插件开发实战:以 artillery-plugin-hello-world 为例剖析插件接口与扩展机制

性能测试接口测试CLI【免费下载链接】artilleryThe complete load testing platform. Everything you need for production-grade load tests. Serverless distributed. Load test with Playwright. Load test HTTP APIs, GraphQL, WebSocket, and more. Use any Node.js module.项目地址https://gitcode.com/gh_mirrors/ar/artillery点击查看免费下载本指南以仓库内 examples/artillery-plugin-hello-world 示例插件为主线完整讲解 Artillery 的插件接口v1/v2 两种形态、插件包的命名与加载约定、如何读取测试脚本配置、如何为所有场景挂载自定义请求钩子beforeRequest、如何通过事件机制上报自定义计数器以及插件的清理钩子cleanup。读完本文你将具备从零编写一个可被 Artillery 自动发现、加载并生效的 Node.js 插件的能力并理解插件从解析到实例化的底层调用链。一、这个示例插件展示了什么artillery-plugin-hello-world是一个刻意保持“最小可用”的 Artillery 插件其 README 明确列出了它要演示的四件事Artillery 的插件接口长什么样一个骨架级barebones插件是如何构建起来的如何在插件内部读取测试脚本test script的属性如何为场景挂载自定义 hook从而在压测过程中做一些“有趣”的事。换句话说它不依赖任何外部服务也不实现复杂的指标采集而是把插件开发的最小完整闭环——定义、加载、配置读取、钩子注入、事件上报、清理——一次性走通是理解 Artillery 扩展体系的最佳入门样本。二、插件的两种形态v1 构造函数与 v2{ Plugin }导出从 Artillery 的插件加载源码 packages/artillery/lib/load-plugins.ts 可以看到插件包在加载时会按导出形状被识别为不同版本v1 插件模块直接导出一个构造函数typeof PluginExport function实例化时接收script.config和事件总线v2 插件模块导出一个对象其中含Plugin构造函数typeof PluginExport.Plugin function实例化时接收完整的script、事件总线与运行选项。本示例采用 v2 形态在 index.js 中通过一行代码完成导出module.exports.Plugin ArtilleryHelloWorldPlugin;在本地运行器 packages/artillery/lib/platform/local/worker.ts 中两种形态的实例化方式对应为// v1传 script.config result.plugin new result.PluginExport(script.config, stubEE); // v2传整个 script result.plugin new result.PluginExport.Plugin(script, stubEE, options);从源码结构看v2 之所以能拿到整个script是为了让插件有更大的自由度去修改脚本对象例如注入处理器函数而 v1 只拿到配置部分。本示例使用的 v2 接口正是当前主推的形态。三、插件包命名与加载路径约定Artillery 默认会到 Node.js 的包查找路径中寻找插件包且要求包名带artillery-plugin-前缀——因此hello-world插件对应的包名必须是artillery-plugin-hello-world这一点同时体现在 package.json 的name字段与加载逻辑中。加载顺序在 load-plugins.ts 中定义得非常明确先按裸包名bare specifier从标准node_modules解析用户安装的副本优先其次查找 Artillery 内置包目录最后才尝试ARTILLERY_PLUGIN_PATH环境变量中冒号:分隔的各个路径。let requirePaths [, BUILTIN_PACKAGES_DIR]; if (process.env.ARTILLERY_PLUGIN_PATH) { requirePaths requirePaths.concat(process.env.ARTILLERY_PLUGIN_PATH.split(:)); }因此当你在开发插件、尚未把包发布安装到node_modules时用ARTILLERY_PLUGIN_PATH指向上级目录即可让 Artillery 找到它。原文档在 README 中也明确提示了这一点ARTILLERY_PLUGIN_PATH正是为“开发中的插件”提供的额外查找位置。除路径外还可以通过环境变量ARTILLERY_PLUGINSJSON 字符串附加额外的插件配置详见 load-plugins.ts 中的loadPluginsConfig实现。四、剖析插件实现构造函数里做了什么打开 index.js整个插件只有三部分构造函数、一个处理器函数、一个cleanup钩子。下面逐段拆解。4.1 保存 script 与 eventsfunction ArtilleryHelloWorldPlugin(script, events) { this.script script; this.events events; // ... }构造函数接收两个参数script完整的测试脚本对象即 YAML 解析后的configscenarios结构events一个 EventEmitter插件可以订阅stats新一批指标产生时触发、done所有虚拟用户完成时触发事件也可以用它发出自定义指标。从 worker.ts 的调用来看v2 插件实例化时传入的正是完整script、事件桩stubEE与options。注释中还特别说明v1/v2 插件不会从每个 runner 实例直接订阅stats/done而是在launch-platform层统一订阅聚合后的结果避免插件收到未聚合的零散事件。4.2 读取插件自身的配置const pluginConfig script.config.plugins[hello-world]; this.greeting pluginConfig.greeting || hello, world;插件可以直接访问script.config.plugins[hello-world]拿到自己在测试脚本中的配置块并给出默认值兜底。这正是原文档所说的“如何检查测试脚本属性”——配置、target、phases 等一切脚本内容对插件都是可见的例如debug(target is:, script.config.target);4.3 向所有场景注入 beforeRequest 钩子script.config.processor script.config.processor || {}; script.config.processor.pluginHelloWorldBeforeRequestHook (_req, _vuContext, events, next) { console.log(this.greeting); events.emit(counter, greeting_count, 1); return next(); }; script.scenarios.forEach((scenario) { scenario.beforeRequest scenario.beforeRequest || []; scenario.beforeRequest.push(pluginHelloWorldBeforeRequestHook); });这段代码做了三件事正是插件“动手术”的典型手法在script.config.processor对象中注册一个自定义函数Artillery 的处理器机制该函数的签名符合beforeRequest钩子约定接收请求对象_req、虚拟用户上下文_vuContext、events事件总线以及next回调调用next()表示钩子结束、继续后续流程遍历script.scenarios把钩子名追加到每个场景的beforeRequest列表末尾——由此实现对所有场景生效无需用户在 YAML 里逐个声明。HTTP 引擎在 packages/artillery/lib/core/engine_http.ts 中会在每次请求发出前依次执行这些beforeRequest处理器包括场景级与请求级这也是“在请求前打印问候语”之所以能落地的底层机制。4.4 上报自定义计数器钩子内部通过events.emit(counter, greeting_count, 1)上报一个名为greeting_count的自定义计数器。控制台报告器 packages/artillery/lib/console-reporter.ts 会读取report.counters并按名称排序打印最终在测试报告尾部以greeting_count: N的形式呈现无需任何额外配置即可看到插件产生的新指标。4.5 清理钩子 cleanupArtilleryHelloWorldPlugin.prototype.cleanup (done) { debug(cleaning up); done(null); };Artillery 在退出前会调用每个插件的cleanup给插件一次冲刷在途数据、写盘等收尾机会。在 packages/artillery/lib/launch-platform.ts 与 packages/artillery/lib/platform/local/worker.ts 中都有对plugin.cleanup的调用且在done回调中传入错误对象null表示无错。本示例只打印一条调试日志实际插件常在此处刷新缓存、关闭连接或写报告文件。五、配套的测试脚本与运行方式示例自带的 test.yml 是验证插件的完整测试脚本config: target: http://asciiart.artillery.io:8080 phases: - arrivalRate: 1 duration: 10 plugins: hello-world: greeting: Hello world! scenarios: - flow: - get: url: /要点解读config.plugins.hello-world.greeting是插件的配置块会被插件构造函数读取并覆盖默认问候语phases以每秒 1 个新虚拟用户的速率持续 10 秒场景只有一个 HTTPGET /请求用于触发beforeRequest钩子。在示例目录下运行注意需先安装 Artillery 本体示例插件作为本地包由ARTILLERY_PLUGIN_PATH指向ARTILLERY_PLUGIN_PATHpwd/.. DEBUGplugin:hello-world artillery run test.yml命令说明ARTILLERY_PLUGIN_PATHpwd/..把插件包所在目录示例的上级目录即examples/其中包含名为artillery-plugin-hello-world的包目录加入插件查找路径DEBUGplugin:hello-world开启debug库中该插件命名空间的调试输出对应 index.js 中的require(debug)(plugin:hello-world)artillery run test.yml以本地模式运行测试。运行后终端会依次出现插件初始化时的调试信息如target is:与cleaning up、每条请求前的问候语打印以及报告尾部由插件上报的greeting_count计数器见上文两张截图。loadPlugins的单元测试 packages/artillery/test/unit/load-plugins.test.js 与 CLI 测试 packages/artillery/test/cli/custom-plugin.test.js 均演示了通过ARTILLERY_PLUGIN_PATH加载本地插件这一方式的自动化验证。六、插件的加载与初始化调用链把上面的零散证据串起来一个插件从被识别到生效的完整链路是解析插件规格loadPluginsConfig合并脚本内的config.plugins与环境变量ARTILLERY_PLUGINSload-plugins.ts按序查找包依次在裸包路径、内置包目录、ARTILLERY_PLUGIN_PATH中require.resolve再通过import()加载兼容 CJS 与 ESM见 load-plugins.ts识别版本按导出形状判定 v1/v2load-plugins.ts实例化在本地 worker 中按版本调用构造函数worker.ts在平台层如 Fargate/Lambda 场景则先给一个深拷贝的dummyScript做事件订阅注册避免在分发阶段就修改真实脚本对象launch-platform.ts钩子生效插件修改script.config.processor与各scenario.beforeRequestHTTP 引擎在每次请求前执行这些处理器engine_http.ts指标呈现插件通过events.emit(counter, ...)上报的计数器由控制台报告器汇总打印console-reporter.ts退出清理cleanup被依次调用launch-platform.ts。值得一提的是平台层在初始化时给 v1/v2 插件传递的是深拷贝的 dummyScript源码注释明确指出如果让插件直接操作真实脚本对象并在其中附加处理器会导致派发 worker 时失败launch-platform.ts——这是插件开发中容易踩坑、但示例这种“单机运行”场景不会触发的细节。七、在此基础上还能做什么原文档在 README 的 “Learn more” 一节推荐了更多成熟插件作为参考这些参考实现大多已在当前仓库中开源可以直接对照阅读packages/artillery-plugin-publish-metrics向 Datadog、Prometheus、CloudWatch、New Relic、Splunk、Mixpanel 等后端发布指标展示了订阅stats事件做指标转发的能力packages/artillery-plugin-expect在测试中对响应做断言展示了在请求层面深度拦截与校验的模式packages/artillery-plugin-apdex基于响应时间计算 Apdex 评分展示了利用聚合指标派生新指标的做法packages/artillery-plugin-metrics-by-endpoint按端点拆分指标展示了结合 URL 模板场景的处理方式packages/artillery-plugin-fake-data生成随机测试数据展示了在脚本中注入数据生成能力packages/artillery-plugin-slack测试结束后推送通知展示了订阅done事件的典型用法。此外Artillery 的官方扩展 API 文档与《创建自定义插件》博客是深入了解插件机制的权威补充资料原文已给出链接此处不再罗列外部地址。核心要点可以归纳为插件接口 Node.js 生态“任何需求几乎都有对应的 npm 包”是 Artillery 扩展能力的双引擎——你的插件完全可以调用任意 Node.js 模块来完成指标入库、消息通知、数据加工等任何定制逻辑。八、小结通过artillery-plugin-hello-world这个最小示例我们完整走通了 Artillery 插件开发的全部关键环节能力示例中的落点源码依据v2 插件导出module.exports.Pluginindex.js、worker.ts读取脚本配置script.config.plugins[hello-world]index.js注入全局钩子改写scenario.beforeRequestindex.js、engine_http.ts自定义指标events.emit(counter, ...)index.js、console-reporter.ts退出清理prototype.cleanupindex.js、launch-platform.ts开发期加载ARTILLERY_PLUGIN_PATHload-plugins.ts对任何希望扩展 Artillery 的团队或个人而言这个示例提供了可复制的最小骨架定义{ Plugin }导出 → 读取配置 → 注入处理器 → 上报指标 → 实现清理。后续只需按需求替换业务逻辑就能把它升级为功能完备的生产级插件。赞分享性能测试接口测试CLI【免费下载链接】artilleryThe complete load testing platform. Everything you need for production-grade load tests. Serverless distributed. Load test with Playwright. Load test HTTP APIs, GraphQL, WebSocket, and more. Use any Node.js module.项目地址https://gitcode.com/gh_mirrors/ar/artillery点击查看免费下载相关推荐深入解析 Artillery 自定义引擎开发以 artillery-engine-example 为例掌握引擎 API 与实战接入深入解析 Artillery 自定义引擎开发以 artillery engine example 为例掌握引擎 API 与实战接入 导读 本指南以仓库内 ar性能测试接口测试CLIEclipse Theia 无头插件Headless Plugin与自定义插件 API 实战以 plugin-gotd 示例插件为例Eclipse Theia 无头插件Headless Plugin与自定义插件 API 实战以 plugin gotd 示例插件为例 本篇技术指南围绕 EIDE代码编辑器开发工具前端桌面应用插件系统后端AI 应用Kubebuilder 插件扩展实战从自定义 Plugin 接口到构建专属 CLIKubebuilder 插件扩展实战从自定义 Plugin 接口到构建专属 CLI Kubebuilder 不仅是开箱即用的 CRD 脚手架工具更提供了一套开发者工具代码生成CLI云原生后端上一篇SymPy 特殊函数专题指南从 Dirac Delta 到超几何函数的内置特殊函数库下一篇Rails Girls Guides终极翻译指南搭建跨文化交流的编程教育桥梁创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门