Plugin development
A plugin patches a Node.js library so calls made by that library create SkyWalking spans. Read an existing plugin close to your target library before adding a new one.
Plugin contract
Each automatic plugin in src/plugins/ implements SwPlugin and exports one default instance:
class ExamplePlugin implements SwPlugin {
readonly module = 'example-library';
readonly versions = '^1.0.0';
install(installer: PluginInstaller): void {
const target = installer.require?.(this.module) ?? require(this.module);
// Patch the target API.
}
}
export default new ExamplePlugin();
Use a file name ending in Plugin.ts. The normal loader scans compiled files in lib/plugins/.
moduleis the npm module that must be installed in the application.versionsis a semantic version range checked by the loader.- Set
isBuiltIn = trueonly for a Node.js built-in module such ashttp. - Use
installer.requirewhen possible so the plugin loads the application’s copy of the module.
Choose a version range from real API support. Do not use * only to avoid checking versions.
Instrumentation rules
Keep library behavior unchanged apart from trace collection:
- Save the original function before replacing it.
- Preserve
this, arguments, return values, thrown errors, callbacks, events, and Promise results. - Create the correct entry, exit, or local span from
ContextManager.current. - Set the component, span layer, operation name, peer, and standard tags when the data exists.
- Record errors and stop every span on all completion paths.
- Use
span.async()andspan.resync()when work leaves and later returns to the active async path. - Do not record request bodies, database parameters, or other private values by default.
src/core/SwPlugin.ts provides helpers for common callback, Promise, and event-emitter completion
forms. Some libraries need a local helper because their API has different completion rules.
Use an existing component in src/trace/Component.ts when it matches. A new component ID must be
agreed with the SkyWalking project so it does not conflict with another agent or integration.
Add tests
Create tests/plugins/<module>/ by following a similar plugin suite. A normal suite contains:
test.tsto start Docker Compose and send expected data to the mock collector;docker-compose.ymlfor the collector, application, and target service;- client and server files that exercise the instrumented API;
expected.data.yamlwith the expected SkyWalking segment data.
Add the target package to devDependencies and update package-lock.json when the test needs it.
The CI plugin matrix finds each directory under tests/plugins/ except common, so a new directory
becomes a CI job without a manual matrix entry.
Run the suite:
npm run test tests/plugins/example-library/
Also run unit tests, lint, and build as described in Build and test.
Webpack support
The normal loader finds a compiled plugin automatically. The Webpack loader does not. If the target
package allows its package.json to be imported, add the plugin to
PluginInstaller.installBundled() and test a production bundle.
If this is not possible, state the limit in Webpack. Do not claim Webpack support based only on the normal plugin test.
Update documentation
For a new plugin:
- Add the library and current CI state to Supported libraries.
- Add configuration details if the plugin adds settings.
- Add important behavior changes, such as changed batching or payload data.
- Update troubleshooting when the plugin has a common setup limit.