JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 38
  • Score
    100M100P100Q102391F
  • License MIT

Centralized monitoring SDK for Node.js applications with Prometheus, Loki, and Grafana integration

Package Exports

  • @hemantwasthere/monitoring-sdk
  • @hemantwasthere/monitoring-sdk/dist/index.js

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (@hemantwasthere/monitoring-sdk) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

@hemantwasthere/monitoring-sdk

A comprehensive monitoring SDK for Node.js applications that provides seamless integration with Prometheus, Loki, and Grafana for metrics collection, logging, and observability.

Features

  • 🚀 Easy Integration: Drop-in SDK for NestJS, Express, and pure Node.js applications
  • 📊 Prometheus Metrics: Automatic HTTP request metrics, custom counters, gauges, and histograms
  • 📝 Centralized Logging: Structured logging with Loki integration using Winston
  • ⏱️ Cron Job Monitoring: Built-in decorators for monitoring scheduled tasks
  • 🏷️ Consistent Labeling: Standardized labels across all metrics and logs
  • 🔧 Global Configuration: Set common settings once and use across multiple services
  • 🎯 Technology Agnostic: Works with different Node.js frameworks

Installation

npm install @hemantwasthere/monitoring-sdk

Quick Start

There are three ways to initialize the monitoring SDK, from simplest to most customized:

Method 1: Zero Configuration (Simplest)

Just set environment variables and use initializeWithDefaults():

# Set these environment variables
export LOKI_URL=http://your-monitoring-server:3100
export NODE_ENV=production
export CLUSTER_NAME=prod-cluster
export AWS_REGION=us-east-1
import { MonitoringSDK } from '@hemantwasthere/monitoring-sdk';

// Auto-configures from environment variables
const monitoring = MonitoringSDK.initializeWithDefaults({
  projectName: 'my-project',
  serviceName: 'user-service',
  technology: 'nestjs'
});

Set up global configuration once at your application startup:

import { MonitoringSDK } from '@hemantwasthere/monitoring-sdk';

// Set global configuration once
MonitoringSDK.setGlobalConfig({
  lokiHost: 'http://your-monitoring-server:3100',
  environment: process.env.NODE_ENV || 'development',
  logLevel: 'info',
  customLabels: {
    region: 'us-east-1',
    cluster: 'prod-cluster'
  }
});

// Now initialize each service without repeating common configuration
const monitoring = MonitoringSDK.initialize({
  projectName: 'my-project',
  serviceName: 'user-service',
  technology: 'nestjs'
});

Method 3: Full Configuration (Most Control)

Configure everything explicitly for each service:

const monitoring = MonitoringSDK.initialize({
  projectName: 'my-project',
  serviceName: 'user-service',
  technology: 'nestjs',
  lokiHost: 'http://your-monitoring-server:3100',
  environment: 'production',
  logLevel: 'info',
  customLabels: { region: 'us-east-1' }
});

Summary:

  • Method 1: Perfect for microservices with consistent environment setup
  • Method 2: Best for applications where you want explicit control over global config
  • Method 3: Use when each service needs different configuration

Framework Integration

NestJS

import { MonitoringSDK, MonitoringInterceptor } from '@hemantwasthere/monitoring-sdk';
import { APP_INTERCEPTOR } from '@nestjs/core';

// In your main.ts
MonitoringSDK.setGlobalConfig({
  lokiHost: 'http://monitoring-server:3100',
  environment: process.env.NODE_ENV,
});

const monitoring = MonitoringSDK.initialize({
  projectName: 'ecommerce',
  serviceName: 'user-service',
  technology: 'nestjs'
});

// In your AppModule
@Module({
  providers: [
    {
      provide: APP_INTERCEPTOR,
      useClass: MonitoringInterceptor,
    },
  ],
})
export class AppModule {}

// Add metrics endpoint
app.getHttpAdapter().get('/metrics', async (req, res) => {
  const metrics = await monitoring.getMetrics().getMetrics();
  res.setHeader('Content-Type', monitoring.getMetrics().getRegistry().contentType);
  res.send(metrics);
});

// Add health endpoint
app.getHttpAdapter().get('/health', (req, res) => {
  res.json({ status: 'ok', timestamp: new Date().toISOString() });
});

Express

import { MonitoringSDK, expressMetricsMiddleware, MonitoringController } from '@hemantwasthere/monitoring-sdk';

MonitoringSDK.setGlobalConfig({
  lokiHost: 'http://monitoring-server:3100',
  environment: process.env.NODE_ENV,
});

const monitoring = MonitoringSDK.initialize({
  projectName: 'my-project',
  serviceName: 'payment-service',
  technology: 'express'
});

const app = express();

// Add metrics middleware
app.use(expressMetricsMiddleware());

// Add monitoring endpoints
const controller = new MonitoringController();
app.get('/metrics', (req, res) => controller.getMetrics(req, res));
app.get('/health', (req, res) => controller.getHealth(req, res));

Cron Job Monitoring

import { CronMonitor } from '@hemantwasthere/monitoring-sdk';

class DataProcessingService {
  @CronMonitor.monitor('daily-report-generation')
  async generateDailyReports() {
    // Your cron job logic here
    // Metrics will be automatically collected:
    // - Execution duration
    // - Success/failure counts
    // - Error details if job fails
  }

  @CronMonitor.monitor('cleanup-old-data', { timeout: 30000 })
  async cleanupOldData() {
    // Job with custom timeout
  }
}

Custom Metrics

const monitoring = MonitoringSDK.getInstance();
const metrics = monitoring.getMetrics();

// Counter
const orderCounter = metrics.createCounter('orders_total', 'Total orders processed', ['status', 'payment_method']);
orderCounter.inc({ status: 'completed', payment_method: 'credit_card' });

// Gauge
const activeUsers = metrics.createGauge('active_users', 'Number of active users');
activeUsers.set(150);

// Histogram
const responseTime = metrics.createHistogram('api_response_time', 'API response time', ['endpoint']);
responseTime.observe({ endpoint: '/api/users' }, 0.25);

Logging

const monitoring = MonitoringSDK.getInstance();
const logger = monitoring.getLogger();

logger.info('User logged in', { 
  userId: '12345', 
  correlationId: 'abc-123' 
});

logger.error('Database connection failed', { 
  error: 'Connection timeout',
  database: 'users-db' 
});

Configuration Options

Global Configuration

interface GlobalMonitoringConfig {
  lokiHost: string;                    // Loki server URL
  environment?: string;                // Environment name (dev, prod, etc.)
  logLevel?: string;                   // Log level (info, debug, error)
  customLabels?: Record<string, string>; // Labels added to all metrics/logs
}

Service Configuration

interface MonitoringConfig {
  projectName: string;                 // Project/application name
  serviceName: string;                 // Service name within the project
  technology: string;                  // Technology stack (nestjs, express, nodejs)
  environment?: string;                // Override global environment
  lokiHost?: string;                   // Override global Loki host
  metricsPath?: string;                // Custom metrics endpoint path
  logLevel?: string;                   // Override global log level
  enableDefaultMetrics?: boolean;      // Enable Node.js default metrics
  prefixDefaultMetrics?: boolean;      // Prefix default metrics with project_service_
  customLabels?: Record<string, string>; // Additional service-specific labels
}

Production Deployment

1. Docker Compose (Monitoring Stack)

Deploy the centralized monitoring stack:

# Clone the monitoring setup
git clone https://github.com/unwrap-labs/monitoring-setup.git
cd monitoring-setup/centralized-stack

# Start the monitoring stack
docker-compose up -d

This provides:

2. Application Configuration

// Production configuration
MonitoringSDK.setGlobalConfig({
  lokiHost: process.env.LOKI_URL || 'http://monitoring-cluster:3100',
  environment: 'production',
  logLevel: 'info',
  customLabels: {
    cluster: process.env.CLUSTER_NAME,
    region: process.env.AWS_REGION,
    version: process.env.APP_VERSION
  }
});

3. Environment Variables

# .env
LOKI_URL=http://your-monitoring-cluster:3100
NODE_ENV=production
LOG_LEVEL=info
CLUSTER_NAME=prod-cluster
AWS_REGION=us-east-1
APP_VERSION=1.2.3

Collected Metrics

HTTP Metrics

  • http_request_duration_milliseconds - Request response times
  • http_requests_total - Total request count by method, route, status

Cron Job Metrics

  • cron_job_duration_seconds - Job execution time
  • cron_job_executions_total - Total job executions
  • cron_job_failures_total - Failed job count

System Metrics (when enabled)

  • Node.js process metrics (memory, CPU, GC)
  • Event loop lag
  • Heap usage

Best Practices

  1. Set Global Config Once: Use setGlobalConfig() at application startup
  2. Consistent Naming: Use kebab-case for project and service names
  3. Meaningful Labels: Add relevant labels to metrics for better filtering
  4. Error Handling: Always handle monitoring errors gracefully
  5. Resource Cleanup: Monitoring shouldn't impact application performance

Troubleshooting

Common Issues

  1. Loki Connection Failed: Ensure Loki host is accessible and port 3100 is open
  2. Metrics Not Appearing: Check if /metrics endpoint is properly exposed
  3. High Memory Usage: Reduce metric cardinality by limiting label values

Debug Mode

MonitoringSDK.setGlobalConfig({
  logLevel: 'debug',
  // ... other config
});

Contributing

We welcome contributions! Please see our Contributing Guide for details.

License

MIT - see LICENSE file for details.

Support