A wrapper service around o11y and o11y_schema for telemetry reporting.
npm install @salesforce/o11y-reporterA lightweight telemetry reporting service for Salesforce extensions that enables sending metrics and events to Salesforce's observability platform.
The O11y Reporter service provides a simple way to send telemetry events and metrics to Salesforce's observability platform. Here's how to use it:
``typescript
import { O11yService } from "@salesforce/o11y-reporter";
// Get the singleton instance
const o11yService = O11yService.getInstance(extensionName);
// Initialize with your extension name and upload endpoint
await o11yService.initialize(
"your-extension-name",
"https://your-upload-endpoint",
);
`
#### Using Default Schema
`typescript
// Send a telemetry event with properties (uses default sf_a4dInstrumentation schema)
o11yService.logEvent({
name: "extension/eventName",
properties: {
// Add your custom properties here
customProperty: "value",
},
measurements: {
// Optional measurements
duration: 100,
},
});
// Send an exception event
o11yService.logEvent({
exception: new Error("Error message"),
properties: {
// Add your custom properties here
errorType: "RuntimeError",
},
measurements: {
// Optional measurements
errorCount: 1,
},
});
`
#### Using Custom Schema
The service supports consumer-provided O11y schemas. This allows you to use custom schemas from the o11y_schema package instead of the default sf_a4dInstrumentation schema.
Step 1: Add o11y_schema to your package.json:
`json`
{
"dependencies": {
"o11y_schema": "^256.154.0"
}
}
Step 2: Import and use the schema with logEventWithSchema():
`typescript
import { O11yService } from "@salesforce/o11y-reporter";
// Import the schema object from o11y_schema
// @ts-expect-error - o11y_schema package doesn't provide TypeScript declarations
import { a4dInstrumentationSchema } from "o11y_schema/sf_a4dInstrumentation";
const o11yService = O11yService.getInstance("your-extension");
await o11yService.initialize("your-extension", "https://your-endpoint");
// Log events with custom schema
o11yService.logEventWithSchema(
{
name: "extension/eventName",
properties: {
customProperty: "value",
},
},
a4dInstrumentationSchema, // Pass the schema object
);
// You can also use different schemas for different events
// @ts-expect-error - o11y_schema package doesn't provide TypeScript declarations
import { anotherSchema } from "o11y_schema/another_schema";
o11yService.logEventWithSchema(
{
name: "extension/anotherEvent",
properties: { foo: "bar" },
},
anotherSchema,
);
`
Note: When using logEventWithSchema(), you must provide a valid schema object. The schema must be a Record type. If you don't provide a schema, use logEvent() which uses the default schema.
Note: The o11y_schema package doesn't provide TypeScript declarations. You may need to add @ts-expect-error comments or configure your TypeScript with skipLibCheck: true in tsconfig.json.
With automatic batching enabled, events are automatically uploaded based on threshold (50KB) or periodic flush (30 seconds). You can also manually flush if needed:
`typescript`
await o11yService.forceFlush();
The service supports automatic batching of events for efficient telemetry collection. Events are automatically buffered and uploaded based on size threshold or periodic flush intervals.
`typescript
// Enable automatic batching with default settings (30-second flush interval)
const cleanup = o11yService.enableAutoBatching();
// Or customize the batching behavior
const cleanup = o11yService.enableAutoBatching({
flushInterval: 30_000, // 30 seconds (default)
enableShutdownHook: true, // Enable shutdown hooks (default: true)
enableBeforeExitHook: true, // Enable beforeExit hook (default: true)
});
// Later, if you need to stop batching
cleanup();
`
Batching Behavior:
- Events are buffered in memory until upload conditions are met
- Threshold-based upload: Events are uploaded when buffer size reaches 50KB
- Periodic flush: Events are automatically flushed every 30 seconds (configurable)
- Shutdown hooks: Events are automatically flushed on application shutdown (SIGINT, SIGTERM, beforeExit)
Benefits:
- Reduces network overhead by batching multiple events
- Improves performance by avoiding per-event uploads
- Ensures events are not lost on application shutdown
You can manually flush buffered events at any time:
`typescript
// Force an immediate flush of all buffered events
await o11yService.forceFlush();
// Or use the upload method (alias for forceFlush when batching is enabled)
await o11yService.upload();
`
Monitor the current batch status:
`typescriptBuffer size: ${status.estimatedByteSize} bytes
const status = o11yService.getBatchStatus();
console.log();Has data: ${status.hasData}
console.log();Over threshold: ${status.isOverThreshold}
console.log();`
The service can be configured with the following options:
- o11yUploadEndpoint: The endpoint URL for uploading telemetry data
When enabling automatic batching, you can configure the following options:
`typescript`
interface BatchingOptions {
/* Periodic flush interval in milliseconds (default: 30000) /
flushInterval?: number;
/* Enable shutdown hooks (default: true) /
enableShutdownHook?: boolean;
/* Enable beforeExit hook (default: true). Note: beforeExit won't fire for STDIO servers where stdin stays open /
enableBeforeExitHook?: boolean;
}
Configuration Examples:
`typescript
// Default configuration (30-second flush, shutdown hooks enabled)
o11yService.enableAutoBatching();
// Custom flush interval (60 seconds)
o11yService.enableAutoBatching({ flushInterval: 60_000 });
// Disable shutdown hooks (not recommended)
o11yService.enableAutoBatching({ enableShutdownHook: false });
// Disable beforeExit hook (useful for STDIO servers)
o11yService.enableAutoBatching({ enableBeforeExitHook: false });
`
1. Initialize Early: Initialize the service as early as possible in your extension's lifecycle.
2. Error Handling: Always wrap telemetry calls in try-catch blocks to prevent them from affecting your main application flow.
3. Property Naming: Use consistent property names and avoid sending sensitive information.
4. Enable Automatic Batching: Use enableAutoBatching() to automatically batch and upload events efficiently. This is recommended for most use cases.
5. Manual Flush for Critical Events: For critical events that need immediate upload, call forceFlush() after logging the event.
Here's a complete example of how to use the O11y Reporter in your extension:
`typescript
import { O11yService } from "@salesforce/o11y-reporter";
class YourExtension {
private o11yService: O11yService;
constructor() {
this.o11yService = O11yService.getInstance(extensionName);
}
async initialize() {
await this.o11yService.initialize(
"your-extension",
"https://your-endpoint",
);
// Enable automatic batching for efficient telemetry collection
this.o11yService.enableAutoBatching({
flushInterval: 30_000, // 30 seconds
enableShutdownHook: true, // Flush on shutdown
});
}
async trackUserAction(actionName: string, properties: Record
try {
// Using default schema
this.o11yService.logEvent({
name: user/${actionName},
properties: {
...properties,
timestamp: new Date().toISOString(),
},
});
// With batching enabled, events are automatically uploaded
// For critical events, you can force an immediate flush:
await this.o11yService.forceFlush();
} catch (error) {
// Log error but don't throw
console.error("Failed to send telemetry:", error);
}
}
async trackUserActionWithSchema(
actionName: string,
properties: Record
schema: Record
) {
try {
// Using custom schema
this.o11yService.logEventWithSchema(
{
name: user/${actionName},
properties: {
...properties,
timestamp: new Date().toISOString(),
},
},
schema,
);
// With batching enabled, events are automatically uploaded
await this.o11yService.forceFlush();
} catch (error) {
console.error("Failed to send telemetry:", error);
}
}
async trackError(error: Error, context: Record
try {
this.o11yService.logEvent({
exception: error,
properties: {
...context,
timestamp: new Date().toISOString(),
},
});
await this.o11yService.upload();
} catch (err) {
console.error("Failed to send error telemetry:", err);
}
}
}
``
This project is licensed under the Terms of Use. See the LICENSE.txt file for details.