@rachelallyson/stratum-event-counter-plugin
v1.0.11
Published
A Stratum plugin for event counting and file logging.
Downloads
38
Readme
@rachelallyson/stratum-event-counter-plugin
A development and testing plugin for Stratum that tracks event counts and provides a real-time dashboard.
Quick Start
1. Install the Plugin
npm install @rachelallyson/stratum-event-counter-plugin2. Start the Dashboard Server
# Start on default port (41321)
npx @rachelallyson/stratum-event-counter-plugin
# Or start on a custom port
EVENT_COUNTER_PORT=3000 npx @rachelallyson/stratum-event-counter-plugin3. Add the Plugin to Your App
import { StratumService } from "@capitalone/stratum-observability";
import { EventCounterPluginFactory } from "@rachelallyson/stratum-event-counter-plugin";
// Create your event catalog
const eventCatalog = {
"user-login": { description: "User logs in" },
"user-logout": { description: "User logs out" },
"page-view": { description: "User views a page" }
};
// Create the plugin
const plugin = EventCounterPluginFactory({
catalog: eventCatalog,
dashboardUrl: 'http://localhost:41321' // Match your dashboard port
});
// Register with Stratum
const stratumService = new StratumService({
plugins: [plugin],
catalog: eventCatalog,
productName: 'myApp',
productVersion: '1.0.0'
});
// Publish events
stratumService.publish('user-login');4. View the Dashboard
Open your browser to http://localhost:41321 (or your custom port) to see:
- Event counts and usage statistics
- First and last usage timestamps
- Search and filtering capabilities
- Export to CSV/JSON
- Automatic cleanup of old run files
- Manual cleanup controls
5. Testing Integration (Optional)
For coordinated event tracking during tests, use the test utilities:
// For Node.js tests (Jest, Vitest)
import { startTestRun, endTestRun } from '@rachelallyson/stratum-event-counter-plugin/test-utils';
// For browser tests (Cypress, Playwright)
import { startTestRun, endTestRun } from '@rachelallyson/stratum-event-counter-plugin/test-utils-browser';
beforeEach(async () => {
await startTestRun({ prefix: 'my-test' });
});
afterEach(async () => {
await endTestRun();
});This ensures all events from your app during testing are tracked under coordinated run IDs.
Configuration Options
Plugin Options
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| dashboardUrl | string | 'http://localhost:41321' | URL where dashboard server is running |
| catalog | object | {} | Your event catalog (required for dashboard) |
| enableLogging | boolean | false | Enable debug logging for publisher |
| allowedEvents | string[] | 'all' | 'all' | Filter which eventTypes to track. Use 'all' to track any eventType, or provide an array of specific eventTypes (like ['base', 'error']) that match the eventType property in your catalog |
Dashboard Server Environment Variables
| Variable | Type | Default | Description |
|----------|------|---------|-------------|
| EVENT_COUNTER_PORT | number | 41321 | Dashboard server port |
| EVENT_COUNTER_MAX_RUNS | number | 25 | Maximum number of runs to keep (oldest are automatically removed) |
📖 For detailed configuration options and advanced patterns, see Configuration Guide
Event Filtering
The plugin supports filtering which eventTypes to track using the allowedEvents configuration option. This filters events based on the eventType property defined in your Stratum catalog. This is useful for focusing on specific event types during development or testing.
Note: The plugin accesses the eventType from the Stratum BaseEventModel's direct
eventTypeproperty, which is automatically set from your catalog'seventTypedefinition.
Track All Event Types (Default)
// Track any eventType (default behavior)
const plugin = EventCounterPluginFactory({
catalog: {
'user-login': { eventType: 'base', description: 'User logs in', id: 1 },
'api-error': { eventType: 'error', description: 'API error occurred', id: 2 },
'debug-info': { eventType: 'debug', description: 'Debug information', id: 3 }
},
allowedEvents: 'all' // or omit this option entirely
});
// All these eventTypes will be tracked
stratumService.publish('user-login'); // ✅ Tracked (eventType: 'base')
stratumService.publish('api-error'); // ✅ Tracked (eventType: 'error')
stratumService.publish('debug-info'); // ✅ Tracked (eventType: 'debug')Track Specific Event Types Only
// Only track specific eventTypes from your catalog
const plugin = EventCounterPluginFactory({
catalog: {
'user-login': { eventType: 'base', description: 'User logs in', id: 1 },
'api-error': { eventType: 'error', description: 'API error occurred', id: 2 },
'debug-info': { eventType: 'debug', description: 'Debug information', id: 3 },
'trace-data': { eventType: 'trace', description: 'Trace information', id: 4 }
},
allowedEvents: ['base', 'error'] // Only track base and error eventTypes
});
// Only allowed eventTypes will be tracked
stratumService.publish('user-login'); // ✅ Tracked (eventType: 'base')
stratumService.publish('api-error'); // ✅ Tracked (eventType: 'error')
stratumService.publish('debug-info'); // ❌ Not tracked (eventType: 'debug')
stratumService.publish('trace-data'); // ❌ Not tracked (eventType: 'trace')Use Cases for Event Type Filtering
Development Focus:
// Focus on base application events during feature development
const plugin = EventCounterPluginFactory({
catalog: eventCatalog,
allowedEvents: ['base'] // Only track core application events
});Error Tracking:
// Track only errors and warnings during debugging
const plugin = EventCounterPluginFactory({
catalog: eventCatalog,
allowedEvents: ['error', 'warning'] // Only track error conditions
});Production Monitoring:
// Track only critical events in production
const plugin = EventCounterPluginFactory({
catalog: eventCatalog,
allowedEvents: ['base', 'error', 'performance'] // Essential events only
});Common Usage Patterns
Development with Custom Port
// Plugin posts to port 3000
const plugin = EventCounterPluginFactory({
dashboardUrl: 'http://localhost:3000',
catalog: eventCatalog
});
// Start dashboard on port 3000
// Terminal: EVENT_COUNTER_PORT=3000 npx @rachelallyson/stratum-event-counter-pluginBrowser Testing (Cypress/Playwright)
// Plugin posts to test server
const plugin = EventCounterPluginFactory({
dashboardUrl: 'http://localhost:3001',
catalog: eventCatalog
});
// Test server runs dashboard on port 3001
// Your test framework controls the test serverDefault Configuration
// Uses default dashboard URL (http://localhost:41321)
const plugin = EventCounterPluginFactory({
catalog: eventCatalog
});
// Start dashboard with default port
// Terminal: npx @rachelallyson/stratum-event-counter-pluginTesting with Automatic Coordination
// App configuration (no run ID management needed)
const plugin = EventCounterPluginFactory({
dashboardUrl: 'http://localhost:41321',
catalog: eventCatalog
});
// Test setup - coordinates with app automatically
import { startTestRun, endTestRun } from '@rachelallyson/stratum-event-counter-plugin/test-utils';
beforeEach(async () => {
await startTestRun({ prefix: 'test' });
});
// All app events during tests automatically use the test run ID
// No manual coordination required!Event Catalog Format
Your event catalog should be an object where each key is an event name:
{
"user-login": {
"description": "User logs in to the application"
},
"user-logout": {
"description": "User logs out of the application"
},
"page-view": {
"description": "User views a page"
}
}Data Management
The plugin automatically manages data files to prevent the data folder from getting cluttered:
Automatic Cleanup
- Startup cleanup: Old run files are automatically removed when the server starts
- Runtime cleanup: When posting new events, if the number of runs exceeds
EVENT_COUNTER_MAX_RUNS, the oldest runs are removed - Catalog cleanup: When a run is removed, its corresponding catalog file is also removed
Manual Cleanup
- Dashboard button: Use the "Cleanup Old Runs" button in the dashboard
- API endpoint: Call
POST /api/cleanupto manually trigger cleanup - Status check: Call
GET /api/cleanupto check if cleanup is needed
File Organization
- Per-run storage: Each run gets its own stats and catalog files
- Default run: The default run uses
event-stats.jsonandevent-catalog.json - Named runs: Other runs use
event-stats-{runId}.jsonandevent-catalog-{runId}.json
Test Integration
The plugin provides comprehensive test utilities for coordinating run IDs across your tests and application, enabling seamless event tracking during test execution.
Quick Setup for Testing
npm install @rachelallyson/stratum-event-counter-pluginFor Node.js environments (Jest, Vitest, etc.):
import { startTestRun, endTestRun } from '@rachelallyson/stratum-event-counter-plugin/test-utils';
describe('My Tests', () => {
beforeEach(async () => {
await startTestRun({ prefix: 'jest' });
});
afterEach(async () => {
await endTestRun();
});
it('should track events automatically', async () => {
// Your app events are automatically tracked with the test run ID
await myApp.doSomething(); // Events published here are coordinated
});
});For browser environments (Cypress, Playwright, etc.):
import { startTestRun, endTestRun } from '@rachelallyson/stratum-event-counter-plugin/test-utils-browser';
describe('My Tests', () => {
beforeEach(async () => {
await startTestRun({ prefix: 'cypress' });
});
afterEach(async () => {
await endTestRun();
});
});Cross-Process Run Coordination
The plugin automatically coordinates run IDs between your tests and application:
- Set active run ID from your tests using test utilities
- App events automatically use the active run ID - no manual coordination needed
- No run ID passing required in your application code
- Each test run gets isolated data automatically
// Your application code - no changes needed!
const plugin = EventCounterPluginFactory({
dashboardUrl: 'http://localhost:41321',
catalog: eventCatalog
});
// Events automatically use the active run ID set by tests
stratumService.publish('user-login'); // Tracked under test run IDTesting Framework Examples
Cypress Global Run ID (all tests share same ID):
// cypress.config.ts
import { defineConfig } from 'cypress';
export default defineConfig({
e2e: {
setupNodeEvents(on, config) {
let currentRunId = null;
on('before:run', async () => {
const { startTestRun } = await import('@rachelallyson/stratum-event-counter-plugin/test-utils');
currentRunId = await startTestRun({ prefix: 'cypress' });
});
on('after:run', async () => {
if (currentRunId) {
const { endTestRun } = await import('@rachelallyson/stratum-event-counter-plugin/test-utils');
await endTestRun();
}
});
}
}
});Jest/Vitest Setup:
// jest.setup.js or vitest.setup.js
import { startTestRun, endTestRun } from '@rachelallyson/stratum-event-counter-plugin/test-utils';
beforeEach(async () => {
await startTestRun({ prefix: 'jest' });
});
afterEach(async () => {
await endTestRun();
});Playwright Setup:
// playwright.config.js
import { test } from '@playwright/test';
import { startTestRun, endTestRun } from '@rachelallyson/stratum-event-counter-plugin/test-utils-browser';
test.beforeEach(async () => {
await startTestRun({ prefix: 'playwright' });
});
test.afterEach(async () => {
await endTestRun();
});Available Test Utility Functions
Simple Functions (Recommended):
// Start a test run (generates ID, sets it active, resets stats)
const runId = await startTestRun({
prefix: 'my-test', // Optional: prefix for run ID (default: 'test')
resetStats: true, // Optional: reset stats (default: true)
dashboardUrl: 'http://localhost:41321' // Optional: dashboard URL
});
// End the test run (clears active run ID)
await endTestRun();Manual Functions (Advanced):
// Generate a run ID
const runId = generateRunId('my-prefix');
// Set active run ID (all events without explicit run ID will use this)
await setActiveRunId(runId);
// Get current active run ID
const currentRunId = await getActiveRunId(); // returns string or null
// Reset stats for a run
await resetRunStats(runId);
// Clear active run ID
await clearActiveRunId();API Endpoints
The dashboard server provides these endpoints:
Core Dashboard
GET /- Dashboard HTML
Event Statistics
GET /api/events-stats- Get event statistics (uses active run ID if no statsId provided)POST /api/events-stats- Update event statistics (uses active run ID if no statsId provided)PUT /api/events-stats- Reset event statistics
Run Coordination
GET /api/active-run-id- Get current active run IDPOST /api/active-run-id- Set active run ID for cross-process coordinationDELETE /api/active-run-id- Clear active run ID
Catalog Management
GET /api/catalog- Get event catalog for a runPOST /api/catalog- Update event catalog for a run
Run Management
GET /api/runs- List available runsGET /api/cleanup- Get cleanup statusPOST /api/cleanup- Manually trigger cleanup of old runs
Development
# Install dependencies
npm install
# Build the project
npm run build
# Start dashboard server
npm run server
# Run in development mode
npm run dev
# Run tests
npm testTesting
# Unit tests
npm run test:unit
# E2E tests
npm run test:e2e
# Watch mode
npm run test:watchProduction Considerations
Note: This plugin is designed for development and testing. For production:
- Use standard plugin integration without dashboard features
- Consider separate monitoring solutions for production observability
- The dashboard server is not intended for production deployment
Troubleshooting
Dashboard Not Loading
- Check the port: Make sure your plugin's
dashboardUrlmatches the dashboard server port - Start the server: Ensure the dashboard server is running via CLI
- Check for conflicts: Make sure the port isn't used by another application
Events Not Appearing
- Check logging: Enable
enableLogging: trueto see debug output - Verify URL: Ensure
dashboardUrlpoints to the correct server - Check network: Verify the plugin can reach the dashboard server
Port Conflicts
- Use different ports: Set
EVENT_COUNTER_PORTto an available port - Update plugin config: Change
dashboardUrlto match the new port - Check running processes: Make sure no other service is using the port
Test Integration Issues
- Fetch not available: For Node.js < 18, install
npm install node-fetch - Test utilities not found: Ensure you're using the correct import path:
- Node.js:
from '@rachelallyson/stratum-event-counter-plugin/test-utils' - Browser:
from '@rachelallyson/stratum-event-counter-plugin/test-utils-browser'
- Node.js:
- Run ID not coordinating: Make sure the dashboard server is running before starting tests
- Events not tracked: Verify your app's
dashboardUrlmatches the test dashboard server
Philosophy
For detailed information about the plugin's design principles and architectural decisions, see PHILOSOPHY.md.
Debugging Event Type Filtering
If eventType filtering isn't working in your live app, enable logging to debug:
const plugin = EventCounterPluginFactory({
catalog: yourCatalog,
allowedEvents: ['authentication', 'business'], // Your desired filter
enableLogging: true // Enable debug logging
});Check the browser console for messages like:
[EventCounterPublisher] shouldPublishEvent called with: BaseEventModel {...}
[EventCounterPublisher] event.eventType: authentication
[EventCounterPublisher] allowedEvents setting: ['authentication', 'business']
[EventCounterPublisher] EventType 'authentication' allowed: trueCommon Issues
- eventType not found: Check that your catalog has
eventTypedefined - shouldPublishEvent not called: Verify the plugin is registered with Stratum
- Wrong eventType values: Ensure
allowedEventsmatches your catalog'seventTypevalues
Test Your Setup
// Minimal test setup
const testCatalog = {
'test-event': { eventType: 'business', description: 'Test event', id: 1 }
};
const plugin = EventCounterPluginFactory({
catalog: testCatalog,
allowedEvents: ['business'],
enableLogging: true
});
// This should trigger filtering logic
stratumService.publish('test-event');Building Rich Catalogs with Multiple Event Types
The plugin supports any eventTypes you define in your Stratum catalog. Here's an example of a comprehensive catalog with many different eventTypes:
// Example catalog with various eventTypes for different purposes
const comprehensiveCatalog = {
// User interaction events
'user-login': { eventType: 'authentication', description: 'User successfully logs in', id: 1 },
'user-logout': { eventType: 'authentication', description: 'User logs out', id: 2 },
'password-reset': { eventType: 'authentication', description: 'User requests password reset', id: 3 },
// Business logic events
'order-created': { eventType: 'business', description: 'New order is created', id: 10 },
'payment-processed': { eventType: 'business', description: 'Payment successfully processed', id: 11 },
'invoice-generated': { eventType: 'business', description: 'Invoice generated for order', id: 12 },
// System performance events
'api-response-time': { eventType: 'performance', description: 'API response time measurement', id: 20 },
'database-query': { eventType: 'performance', description: 'Database query execution', id: 21 },
'cache-hit': { eventType: 'performance', description: 'Cache hit occurred', id: 22 },
// Error and warning events
'api-error': { eventType: 'error', description: 'API request failed', id: 30 },
'validation-error': { eventType: 'error', description: 'Data validation failed', id: 31 },
'timeout-warning': { eventType: 'warning', description: 'Operation timeout warning', id: 32 },
// Debug and diagnostic events
'debug-trace': { eventType: 'debug', description: 'Debug trace information', id: 40 },
'state-change': { eventType: 'debug', description: 'Application state change', id: 41 },
'config-loaded': { eventType: 'debug', description: 'Configuration loaded', id: 42 },
// Analytics and tracking
'page-view': { eventType: 'analytics', description: 'Page view tracked', id: 50 },
'button-click': { eventType: 'analytics', description: 'Button click tracked', id: 51 },
'feature-usage': { eventType: 'analytics', description: 'Feature usage tracked', id: 52 },
// Security events
'security-alert': { eventType: 'security', description: 'Security alert triggered', id: 60 },
'failed-login': { eventType: 'security', description: 'Failed login attempt', id: 61 },
'suspicious-activity': { eventType: 'security', description: 'Suspicious activity detected', id: 62 }
};
// Configure plugin to track specific eventTypes
const plugin = EventCounterPluginFactory({
catalog: comprehensiveCatalog,
allowedEvents: ['business', 'error', 'security'] // Only track critical eventTypes
});Filtering Examples with Multiple Event Types
// Track all business and authentication events
const businessPlugin = EventCounterPluginFactory({
catalog: comprehensiveCatalog,
allowedEvents: ['business', 'authentication']
});
// Track only error and security events for monitoring
const monitoringPlugin = EventCounterPluginFactory({
catalog: comprehensiveCatalog,
allowedEvents: ['error', 'warning', 'security']
});
// Track performance and debug events for optimization
const performancePlugin = EventCounterPluginFactory({
catalog: comprehensiveCatalog,
allowedEvents: ['performance', 'debug']
});
// Track user-facing events for analytics
const analyticsPlugin = EventCounterPluginFactory({
catalog: comprehensiveCatalog,
allowedEvents: ['analytics', 'authentication', 'business']
});
// Development mode - track everything
const developmentPlugin = EventCounterPluginFactory({
catalog: comprehensiveCatalog,
allowedEvents: 'all'
});Dynamic Event Type Selection
// Environment-based eventType filtering
const getEventTypesForEnvironment = (env) => {
switch (env) {
case 'production':
return ['business', 'error', 'security']; // Critical events only
case 'staging':
return ['business', 'error', 'warning', 'performance']; // Add performance monitoring
case 'development':
return 'all'; // Track everything during development
case 'testing':
return ['business', 'error']; // Focus on core functionality
default:
return ['error']; // Minimal fallback
}
};
const plugin = EventCounterPluginFactory({
catalog: comprehensiveCatalog,
allowedEvents: getEventTypesForEnvironment(process.env.NODE_ENV)
});Custom Event Types for Your Domain
// E-commerce specific eventTypes
const ecommerceCatalog = {
'product-viewed': { eventType: 'product', description: 'Product page viewed', id: 1 },
'cart-updated': { eventType: 'cart', description: 'Shopping cart updated', id: 2 },
'checkout-started': { eventType: 'checkout', description: 'Checkout process started', id: 3 },
'payment-failed': { eventType: 'payment', description: 'Payment processing failed', id: 4 },
'order-shipped': { eventType: 'fulfillment', description: 'Order shipped to customer', id: 5 }
};
// SaaS application eventTypes
const saasCatalog = {
'feature-enabled': { eventType: 'feature', description: 'Feature flag enabled', id: 1 },
'subscription-upgraded': { eventType: 'subscription', description: 'User upgraded subscription', id: 2 },
'api-key-generated': { eventType: 'integration', description: 'API key generated', id: 3 },
'usage-limit-reached': { eventType: 'billing', description: 'Usage limit reached', id: 4 },
'webhook-sent': { eventType: 'notification', description: 'Webhook notification sent', id: 5 }
};