This is a quick reference guide for adding new plugins to the telemetry SDK. For detailed explanations, see CONTRIBUTING.md.
File: src/plugins/YourPluginName.ts
Purpose: Main plugin logic and event capture
import { BasePlugin } from "./BasePlugin";
import type { TelemetryEvent } from "../types";
export class YourPluginName extends BasePlugin {
protected isSupported(): boolean {
return typeof window !== "undefined";
}
protected setup(): void {
/* Initialize your plugin */
}
teardown(): void {
/* Clean up resources */
}
}File: src/plugins/index.ts
Purpose: Make plugin available for import
export { YourPluginName } from "./YourPluginName"; // Add this lineFile: src/index.ts
Purpose: Make plugin available to users
import { YourPluginName } from "./plugins/YourPluginName";
export { YourPluginName }; // Add to exportsFile: src/types/TelemetryConfig.ts
Purpose: Define enable/disable option
export type TelemetryConfig = {
enableYourPlugin?: boolean; // Add this line
// ... other options
};File: src/utils/initialTelemetryConfig.ts
Purpose: Set default value
export const initialTelemetryConfig: TelemetryConfig = {
enableYourPlugin: false, // Add this line (usually false by default)
// ... other defaults
};File: src/TelemetryManager/PluginManager.ts
Purpose: Auto-initialize when enabled
import { YourPluginName } from "../plugins"; // Add import
const pluginConfigs = [
{
enabled: config.enableYourPlugin, // Add this block
plugin: YourPluginName,
name: "YourPluginName",
},
// ... other plugins
];File: src/TelemetryManager/index.ts
Purpose: Log plugin status
this.logger.info("TelemetryManager initialized", {
enableYourPlugin: config.enableYourPlugin, // Add this line
// ... other config
});File: examples/your-plugin-example.ts
Purpose: Show usage to users
import { initTelemetry } from "../src/index";
const telemetry = initTelemetry({
enableYourPlugin: true, // Enable your plugin
});File: README.md
Purpose: Document for users
- Add to configuration table
- Add to plugin system section
Commands: Build and verify
pnpm run build
pnpm test
node examples/your-plugin-example.tsprotected isSupported(): boolean {
// Check if plugin works in current environment
return typeof window !== "undefined";
}
protected setup(): void {
// Initialize plugin (event listeners, timers, etc.)
// Called when plugin is enabled
}
teardown(): void {
// Clean up resources (remove listeners, clear timers)
// Called when plugin is disabled or SDK shuts down
}private captureEvent = () => {
try {
const evt: TelemetryEvent = {
eventType: "your_type",
eventName: "your_name",
payload: { /* your data */ },
timestamp: new Date().toISOString(),
};
this.safeCapture(evt); // Always use safeCapture!
} catch (error) {
this.logger.error("Failed to capture event", { error });
}
};- Use
this.safeCapture()for event capture - Clean up resources in
teardown() - Check environment in
isSupported() - Log setup/teardown for debugging
- Wrap event capture in try-catch
- Use meaningful event names and payloads
- Don't use
this.capture()directly (usesafeCapture) - Don't forget to clean up event listeners
- Don't assume browser APIs are available
- Don't let plugin errors crash the SDK
- Don't store DOM element references
- Don't forget to handle SSR environments
// src/plugins/ExamplePlugin.ts
import { BasePlugin } from "./BasePlugin";
import type { TelemetryEvent } from "../types";
export class ExamplePlugin extends BasePlugin {
private handler: (() => void) | null = null;
protected isSupported(): boolean {
return typeof window !== "undefined";
}
private captureEvent = () => {
try {
const evt: TelemetryEvent = {
eventType: "example",
eventName: "event_captured",
payload: {
timestamp: new Date().toISOString(),
data: "example data",
},
timestamp: new Date().toISOString(),
};
this.logger.debug("Example event captured");
this.safeCapture(evt);
} catch (error) {
this.logger.error("Failed to capture example event", {
error: error instanceof Error ? error.message : String(error),
});
}
};
protected setup(): void {
if (!this.isSupported()) {
this.logger.warn("ExamplePlugin not supported");
this.isEnabled = false;
return;
}
try {
this.handler = this.captureEvent.bind(this);
window.addEventListener("example", this.handler);
this.logger.info("ExamplePlugin setup complete");
} catch (error) {
this.logger.error("Failed to setup ExamplePlugin", { error });
this.isEnabled = false;
}
}
teardown(): void {
try {
if (this.handler) {
window.removeEventListener("example", this.handler);
this.handler = null;
}
this.logger.info("ExamplePlugin teardown complete");
} catch (error) {
this.logger.error("Failed to teardown ExamplePlugin", { error });
}
}
}Copy this template and replace YourPluginName with your plugin name:
import { BasePlugin } from "./BasePlugin";
import type { TelemetryEvent } from "../types";
export class YourPluginName extends BasePlugin {
protected isSupported(): boolean {
return typeof window !== "undefined";
}
protected setup(): void {
if (!this.isSupported()) {
this.logger.warn("YourPluginName not supported");
this.isEnabled = false;
return;
}
try {
// Your initialization code here
this.logger.info("YourPluginName setup complete");
} catch (error) {
this.logger.error("Failed to setup YourPluginName", { error });
this.isEnabled = false;
}
}
teardown(): void {
try {
// Your cleanup code here
this.logger.info("YourPluginName teardown complete");
} catch (error) {
this.logger.error("Failed to teardown YourPluginName", { error });
}
}
}- Read the detailed guide in CONTRIBUTING.md
- Look at existing plugins for examples
- Test your plugin thoroughly
- Update documentation
- Submit a pull request
Happy plugin development! 🚀