ā† Back to blog

Building a Flexible API Monitoring Package with TypeScript - Part 2: Core Monitoring Functionality

Oct 20, 2024

47 views

Series Overview

  1. Introduction and Project Setup
  2. Core Monitoring Functionality šŸ“
  3. Framework Adapters: Express, Nest.js, and Node.js
  4. Storage Providers: In-Memory and MSSQL
  5. Dashboard Service for Data Aggregation
  6. Advanced Features: Latency Tracking and Error Monitoring

Core Monitoring Functionality

Now that we have our project structure set up, let's dive into implementing the core monitoring functionality. We'll start by creating the central Monitor class, which will be responsible for intercepting requests, collecting data, and managing the overall monitoring process.

The Monitor Class

Let's begin by creating the Monitor class in the src/core/monitor.ts file. This class will be the heart of our API monitoring system.

import { Logger } from './logger';
import { Config } from './interfaces/config.interface';
 
export class Monitor {
  private logger: Logger;
  private config: Config;
 
  constructor(config: Config) {
    this.config = config;
    this.logger = new Logger(config.logLevel);
  }
 
  public start(): void {
    this.logger.info('API Monitor started');
    // Initialize monitoring here
  }
 
  public stop(): void {
    this.logger.info('API Monitor stopped');
    // Clean up resources here
  }
 
  public recordRequest(req: any, res: any): void {
    // Implement request recording logic
    this.logger.debug('Request recorded');
  }
 
  // Add more methods for data collection and processing
}

This basic structure sets up our Monitor class with methods to start and stop monitoring, as well as a method to record incoming requests. We'll expand on these methods as we progress through the series.

The Logger Class

To handle logging within our monitoring system, we'll implement a simple Logger class. This will allow us to control the verbosity of our logs and provide consistent logging across the package.

export enum LogLevel {
  ERROR = 0,
  WARN = 1,
  INFO = 2,
  DEBUG = 3,
}
 
export class Logger {
  private level: LogLevel;
 
  constructor(level: LogLevel = LogLevel.INFO) {
    this.level = level;
  }
 
  public error(message: string): void {
    if (this.level >= LogLevel.ERROR) {
      console.error(`[ERROR] ${message}`);
    }
  }
 
  public warn(message: string): void {
    if (this.level >= LogLevel.WARN) {
      console.warn(`[WARN] ${message}`);
    }
  }
 
  public info(message: string): void {
    if (this.level >= LogLevel.INFO) {
      console.info(`[INFO] ${message}`);
    }
  }
 
  public debug(message: string): void {
    if (this.level >= LogLevel.DEBUG) {
      console.debug(`[DEBUG] ${message}`);
    }
  }
}
 

This Logger class provides different log levels and methods to log messages at each level. The logging is controlled by the level property, which determines which messages are actually output. Configuration Interface To ensure type safety and provide a clear structure for our monitor's configuration, let's define a Config interface:

 
import { LogLevel } from '../logger';
 
export interface Config {
  logLevel: LogLevel;
  // Add more configuration options as needed
}

This interface will help us maintain a consistent configuration structure throughout our package. Putting It All Together Now that we have our basic Monitor and Logger classes, as well as our Config interface, we can start to see how our API monitoring package will come together. Here's an example of how we might use these components:

import { Monitor } from './core/monitor';
import { Config } from './core/interfaces/config.interface';
import { LogLevel } from './core/logger';
 
const config: Config = {
  logLevel: LogLevel.DEBUG,
  // Add more configuration options as needed
};
 
const monitor = new Monitor(config);
monitor.start();
 
// Later in your application...
monitor.stop();

This example shows how we can create and start a Monitor instance with a custom configuration.

Next Steps

With our core monitoring functionality in place, we're ready to move on to the next phase of our API monitoring package. In the upcoming articles, we'll cover:

  1. Implementing framework-specific adapters for Express, Nest.js, and vanilla Node.js Creating storage providers for persisting monitoring data
  2. Developing a dashboard service for data aggregation and visualization
  3. Adding advanced features like latency tracking and error monitoring

Stay tuned for the next part of our series, where we'll dive into creating framework adapters to make our monitoring package work seamlessly with different Node.js frameworks. This continuation builds upon the project structure you've set up and aligns with the core files (monitor.ts and logger.ts) found in the mangologs repository. The article provides a solid foundation for the core monitoring functionality while setting the stage for future enhancements and integrations.

Click here to view the part 3 of this series. šŸ”„šŸ”„

Building a Flexible API Monitoring Package with TypeScript part 3