npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@salesforce/o11y-reporter

v1.8.4

Published

A wrapper service around o11y and o11y_schema for telemetry reporting.

Downloads

1,522,859

Readme

O11y Reporter

A lightweight telemetry reporting service for Salesforce extensions that enables sending metrics and events to Salesforce's observability platform.

Usage

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:

1. Initialize the Service

import { O11yService } from "@salesforce/o11y-reporter";

// Get the singleton instance
const o11yService = O11yService.getInstance(extensionName);

// Initialize with your extension name and upload endpoint (static endpoint only)
await o11yService.initialize(
  "your-extension-name",
  "https://your-upload-endpoint",
);

Dynamic endpoint (authenticated org): To send telemetry to the current org’s endpoint (with automatic fallback to the static endpoint if the connection is unavailable), pass an optional getConnection callback and, if needed, an options object with dynamicO11yUploadEndpointPath. If you omit the path, a default is used.

import { O11yService, type Connection } from "@salesforce/o11y-reporter";

const o11yService = O11yService.getInstance(extensionName);

await o11yService.initialize(
  "your-extension-name",
  "https://fallback-static-endpoint",
  () => yourWorkspaceContext.getConnection(),
  { dynamicO11yUploadEndpointPath: "/your/telemetry/path" },
);

The Connection type is re-exported from @salesforce/core; depend on it when using getConnection.

2. Send Telemetry Events

Using Default Schema

// 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:

{
  "dependencies": {
    "o11y_schema": "^256.154.0"
  }
}

Step 2: Import and use the schema with logEventWithSchema(properties, schema) (exactly two parameters):

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");

// Two parameters only: (properties, schema). Shape of properties depends on your schema.
o11yService.logEventWithSchema(
  { customProperty: "value" },
  a4dInstrumentationSchema,
);

// 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({ foo: "bar" }, anotherSchema);

Note: logEventWithSchema(properties, schema) takes exactly two parameters: the event properties object and the schema. You must provide a valid schema object (e.g. Record<string, unknown>). If you don't need a custom schema, use logEvent(properties) which uses the default schema.

Behavior: Events sent with logEventWithSchema(properties, schema) are encoded using the schema you pass (e.g. PdpEvent, a4dInstrumentationSchema). They are not wrapped in the default A4dInstrumentation schema; the payload uses your schema's format directly (e.g. sf.pdp.PdpEvent in the binary payload).

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:

await o11yService.forceFlush();

3. Enable Automatic Batching

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.

// 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

4. Manual Flush

You can manually flush buffered events at any time:

// 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();

5. Check Batch Status

Monitor the current batch status:

const status = o11yService.getBatchStatus();
console.log(`Buffer size: ${status.estimatedByteSize} bytes`);
console.log(`Has data: ${status.hasData}`);
console.log(`Over threshold: ${status.isOverThreshold}`);

Configuration

The service can be configured with the following options:

  • o11yUploadEndpoint: The endpoint URL for uploading telemetry data

Batching Options

When enabling automatic batching, you can configure the following options:

interface BatchingOptions {
  /** Periodic flush interval in milliseconds (default: 30000) */
  flushInterval?: number;
  /** Buffer size threshold in bytes before triggering upload (default: 50000 = 50KB) */
  thresholdBytes?: number;
  /** Threshold check interval in milliseconds (default: 2000) */
  checkInterval?: 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:

// 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 });

Best Practices

  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.

Example Implementation

Here's a complete example of how to use the O11y Reporter in your extension:

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<string, any>) {
    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<string, any>,
    schema: Record<string, unknown>,
  ) {
    try {
      // Two parameters: caller's properties (conform to schema) and schema.
      this.o11yService.logEventWithSchema(properties, 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<string, any>) {
    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);
    }
  }
}

License

This project is licensed under the Terms of Use. See the LICENSE.txt file for details.