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 🙏

© 2024 – Pkg Stats / Ryan Hefner

@capitalone/stratum-observability

v1.1.0

Published

Library for defining and publishing observability events through plugin-based architecture

Downloads

127

Readme

Stratum Observability | standardization as you publish

A no-dependency library defining a framework for sending analytics and observability events in a standardized format. Stratum is a plugin-based framework that allows you to create your own custom plugins to define, validate, and publish events to your observability stack. We also offer community-driven plugins for popular integrations.

Common problems that Stratum helps solve:

  1. Standardized data for clean queries, clear ownership, and strongest possible signals for alerting/reporting
  2. Being the first to know when your app is down, up, or sideways (let alone determining what any of those mean to you)
  3. Clear cataloging of what your product is capable of and who's using what

Getting started

A typical Stratum implementation consists of:

  1. Stratum Catalog - single source of truth for the voice of your application
  2. Shared StratumService instance to load plugins and publish events from
  3. Functional code aka your application code! Any files containing logic you'd like to observe
  import { StratumService } from '@capitalone/stratum-observability';
  import { NewRelicPluginFactory } from '@capitalone/stratum-observability/plugins/new-relic';

  /**
   * Using enumerated keys afford the best chance of consistent references throughout your application. 
   * This replaces the need to hard code string values as reference.
   */
  export const EventKey = {
    LOADED: 'app-loaded'
  };

  /**
   * Initialize Stratum with required arguments, again 
   * typically within a shared file for re-use.
   * 
   * The StratumService is the engine for publishing.
   */
  export const stratumService = new StratumService({
    /**
     * 1+ plugins defining your standardized event schemas and how to
     * map these schemas when published to your data collectors
     * 
     * The NewRelicPlugin is available from the @capitalone/stratum-observability library
     */
    plugins: [NewRelicPluginFactory()],

    /**
     * The canonical name for referring to this capability
     */
    productName: 'stratumExampleApp',

    /**
     * Typically, this references the version of the application you're 
     * publishing observability events from
     */
    productVersion: 'REPLACE_WITH_PRODUCT_VERSION',

    /**
     * Your "catalog" or dictionary serves as the source-of-truth of events 
     * published by an application. This provides the structure for standardization.
     * 
     * Custom plugins allow you to define your own catalog events, attributes,
     * and custom validation rules.
     * 
     * We've added an example event for the sake of getting started.
     */
    catalog: {
      items: {
        [EventKey.LOADED]: {
          eventType: 'base', // The base event type for Stratum events
          description: 'This application has loaded for the first time',
          id: 1 // Very important reference identifier -- the key to simple queries
        }
      }
    }
  });

  /**
   * Publish your event via Stratum. In this example, Stratum will send your event
   * to New Relic's Browser Agent, if available on the webpage.
   * 
   * (see: https://docs.newrelic.com/docs/browser/browser-monitoring/getting-started/introduction-browser-monitoring/)
   */
  stratumService.publish(EventKey.LOADED);

Installation

Via npm:

npm install @capitalone/stratum-observability

Via yarn:

yarn add @capitalone/stratum-observability

Creating a custom plugin

Creating a new plugin

Plugins are composed of 3 pieces of data:

  1. Name as a string identifier (required)
  2. Map of eventTypes to the correspond EventModel class (optional)
  3. One or more instantiated publishers to handle specific event type(s) (optional)
import { BasePlugin } from '@capitalone/stratum-observability';

/**
 * For TypeScript support, BasePlugin accepts types for 
 */
export class SimplePlugin extends BasePlugin<never, never> {
  name: 'mySimplePlugin',
  eventTypes: {
    // Map catalog events with { eventType: 'simple' } to an instance of SimpleEventModel
    simple: SimpleEventModel
  },
  publishers: [ new SimplePublisher() ]
}

Each of the concepts above are explained in further detail in the following sections.

Plugin factories

If you have a configurable plugin that can be customized based on context, define your plugin as a PluginFactory instead of a static object. Plugin factories are a function that (optionally) take in arguments and return a new plugin instance on each execution.

Plugin factory options are good way to dynamically define plugins or pass initialization data to publishers at run-time. Use this in cases where your plugin needs to behave differently based on what application or environment is using it.

import type { PluginFactory } from '@capitalone/stratum-observability';
const SimplePluginFactory: PluginFactory<SimplePlugin> = () => new SimplePlugin();
const myPluginInstance = SimplePluginFactory();
import type { PluginFactory } from '@capitalone/stratum-observability';

interface MyOptions {
  isLoggedIn: boolean
}

const SimplePluginFactoryWithOptions: PluginFactory<SimplePlugin> = (options) => {
  return options?.isLoggedIn ? new SimplePluginWAuthentication() : new SimplePlugin();
}

/**
 * In the above, options is optional so both of the
 * following implementations are allowed by the compiler.
 */
const myPluginInstance = SimplePluginFactoryWithOptions(); // Valid
const myPluginInstanceWithOptions = SimplePluginFactoryWithOptions({ isLoggedIn: true }); // Also valid

Catalog entries

Through plugins, you may define custom event type which are referenced by the eventType property on your catalog items. Any events loaded into your StratumService must have a corresponding eventType to EventModel relation defined via a plugin.

import { StratumCatalog, CatalogEvent } from '@capitalone/stratum-observability';

const SimpleEventType = 'my-simple-event';

/**
 * Creates a new event type with the base stratum event fields
 * and an additional "simpleValue" number attribute
 */
interface SimpleEvent extends StratumEvent<SimpleEventType> {
  simpleValue: number;
}

/**
 * A catalog composed of SimpleEvents can then
 * be defined.
 * 
 * If you do not provide your custom event type interface as a generic
 * to the StratumCatalog type, ype-hinting for required properties
 * will not be available. 
 * 
 * Multiple custom event type interfaces can be added as a union:
 * `StratumCatalog<SimpleEvent | ComplexEvent>`
 */
const catalog: StratumCatalog<SimpleEvent> = {
  {
    eventType: SimpleEventType,

    // Implement the required base properties required by Stratum
    description: 'My simple event that fires from the "mySimplePlugin" plugin',
    id: 1,

    // Additional fields defined by SimpleEvent
    simpleValue: 12345
  }
}

Event models

import { BaseEventModel } from '@capitalone/stratum-observability';

// Pass your SimpleEvent interface into the base EventModel
export class SimpleEventModel extends BaseEventModel<SimpleEvent> {
  // Override to include any custom run-time validation rules
  protected checkValidity(): boolean {
    let isValid = super.checkValidity();

    if(!this.item.simpleValue || typeof this.item.simpleValue === 'number') {
      this.addValidationError('The "simpleValue" value provided is in an invalid format');
      isValid = false;
    }

    return isValid;
  }
}

Publisher models

import { BasePublisher, EventOptions } from '@capitalone/stratum-observability';

interface ExternalEventSchema {
  id: number,
  simpleValue: number
}

export class SimplePublisher extends BasePublisher<ExternalEventSchema> {
  // Required
  name = 'SimplePublisher';

  /**
   * Required
   * Check if your publisher source is available (aka scripts installed, environment
   * is set up, etc.)
   * 
   * In this case, we make sure that console.log() is accessible.
   */
  async isAvailable(_model: SimpleEventModel) {
    return typeof console !== 'undefined';
  }

  /**
   * Required
   * Map the contents of your event model instance to your event schema
   */
  getModelOutput(model: SimpleEventModel, options?: Partial<EventOptions>): ExternalEventSchema {
    const data = model.getData(options);
    return {
      id: data.id,
      simpleValue: data.simpleValue
    };
  }

  /**
   * Required
   * Send your simple event content to the external publisher
   * 
   * In this, case we publish the event to the console log
   */
  async publish(event: ExternalEventSchema) {
    console.log('publishing simple event!', { id: event.id, simpleValue: event.simpleValue });
  }
}

Contributing

We welcome and appreciate your contributions!

If you have suggestions or find a bug, please open an issue.

If you want to contribute, visit the contributing page.