simple-logger

A lightweight and minimal logging system for typescript projects.

View on GitHub

Simple Logger

A lightweight, flexible logging system for CourseBook that supports namespace-based logging with different log levels.

Features:

Installation

npm install @madooei/simple-logger

Usage

A lightweight, flexible logging system for CourseBook that supports namespace-based logging with different log levels.

Basic Usage

import { LogManagerImpl, type Logger } from "@madooei/simple-logger";

// Get the logger instance
const logManager = LogManagerImpl.getInstance();

// Create a logger for your component
const logger: Logger = logManager.getLogger("myapp:component");

// Log at different levels
logger.trace("Detailed debugging");
logger.info("General information");

Setting Log Levels

// Set level for specific namespace
logManager.setLogLevel("myapp:component", "info");

// Set level for all components in 'myapp'
logManager.setLogLevel("myapp:*", "info");

// Use regex pattern
logManager.setLogLevel(/test:\d+/, "trace");

// Set default level for everything
logManager.setLogLevel("*", "info");

// Disable logging for specific namespace
logManager.setLogLevel("myapp:debug", "none");

Namespace Patterns

Log Levels

  1. none - Disables all logging for the namespace
  2. trace - Verbose debugging information
  3. info - Informational messages and errors

When you set a log level, all levels of equal or higher severity will be logged:

Simple Log Level Design

The logging system uses a minimal three-level hierarchy: none, trace, and info.

This simple hierarchy keeps configuration straightforward while providing the flexibility to selectively disable noisy components or enable detailed debugging where needed.

Enable/Disable Logging

// Disable all logging globally
logManager.disable();

// Re-enable logging globally
logManager.enable();

// Disable logging for specific namespaces using "none" level
logManager.setLogLevel("myapp:debug", "none");
logManager.setLogLevel("noisy:*", "none");

// Re-enable by setting to a different level
logManager.setLogLevel("myapp:debug", "info");

Object Logging

Objects are automatically pretty-printed:

logger.info("Processing config", {
  server: "localhost",
  port: 3000,
});

// Output:
// [INFO] [myapp:component] Processing config {
//   "server": "localhost",
//   "port": 3000
// }

Example Component Integration

export class FileManager {
  private logger: Logger;

  constructor() {
    this.logger = LogManagerImpl.getInstance().getLogger("filemanager");
  }

  async readFile(path: string): Promise<Buffer> {
    this.logger.trace("Reading file:", path);
    try {
      const content = await readFile(path);
      this.logger.info("Successfully read file:", path);
      return content;
    } catch (error) {
      this.logger.info("Failed to read file:", path, error);
      throw error;
    }
  }
}

// Configure logging levels
const logManager = LogManagerImpl.getInstance();

// Enable trace logging for file operations during development
logManager.setLogLevel("filemanager", "trace");

// Disable logging for a noisy third-party component
logManager.setLogLevel("external:verbose-lib", "none");

// Keep default info level for everything else
logManager.setLogLevel("*", "info");

Custom Log Functions

You can customize how logs are output by providing a custom log function:

import { LogManagerImpl, type LogFunction } from "@madooei/simple-logger";

const logManager = LogManagerImpl.getInstance();

// Custom log function that formats differently
const customLogFunction: LogFunction = (level, namespace, ...args) => {
  const timestamp = new Date().toISOString();
  const message = `${timestamp} [${level.toUpperCase()}] ${namespace}: ${args.join(" ")}`;
  console.log(message);
};

// Set the custom log function
logManager.setLogFunction(customLogFunction);

// Now all loggers will use your custom function
const logger = logManager.getLogger("myapp");
logger.info("This will use custom formatting");

// Reset to default console.log behavior
logManager.resetLogFunction();

VSCode Extension Example

import * as vscode from "vscode";
import { LogManagerImpl, type LogFunction } from "@madooei/simple-logger";

const vscodeLogFunction: LogFunction = (level, namespace, ...args) => {
  const message = `[${level.toUpperCase()}] [${namespace}] ${args.join(" ")}`;
  vscode.window.showInformationMessage(message);
};

const logManager = LogManagerImpl.getInstance();
logManager.setLogFunction(vscodeLogFunction);

// Now logs appear as VSCode information messages
const logger = logManager.getLogger("extension:main");
logger.info("Extension activated!");

Custom Formatting Examples

// Colorized console output
const colorLogFunction: LogFunction = (level, namespace, ...args) => {
  const colors = { trace: "\x1b[36m", info: "\x1b[32m" };
  const reset = "\x1b[0m";
  const color = colors[level] || "";

  console.log(
    `${color}[${level.toUpperCase()}]${reset} ${namespace}:`,
    ...args,
  );
};

// JSON structured logging
const jsonLogFunction: LogFunction = (level, namespace, ...args) => {
  const logEntry = {
    timestamp: new Date().toISOString(),
    level: level.toUpperCase(),
    namespace,
    message: args.join(" "),
  };
  console.log(JSON.stringify(logEntry));
};

// Multiple outputs
const multiOutputLogFunction: LogFunction = (level, namespace, ...args) => {
  const message = `[${level.toUpperCase()}] [${namespace}] ${args.join(" ")}`;

  console.log(message); // Console
  sendToLogServer(message); // External logging
  writeToFile(message); // File logging
};

Features

Cloning the Repository

To make your workflow more organized, it’s a good idea to clone this repository into a directory named simple-logging-workspace. This helps differentiate the workspace from the simple-logger located in the packages directory.

git clone https://github.com/madooei/simple-logger simple-logging-workspace

cd simple-logging-workspace

Repository Structure

How to Use This Repo

Using a VSCode Multi-root Workspace

With Visual Studio Code, you can enhance your development experience by using a multi-root workspace to access packages, examples, and playgrounds simultaneously. This approach is more efficient than opening the root directory, or each package or example separately.

To set up a multi-root workspace:

  1. Open Visual Studio Code.
  2. Navigate to File > Open Workspace from File....
  3. Select the simple-logger.code-workspace file located at the root of the repository. This action will open all specified folders in one workspace.

The simple-logger.code-workspace file can be customized to include different folders or settings. Here’s a typical configuration:

{
  "folders": [
    {
      "path": "packages/simple-logger"
    },
    {
      "path": "examples/simple"
    },
    {
      "path": "playgrounds/empty"
    }
  ],
  "settings": {
    // Add any workspace-specific settings here, for example:
    "git.openRepositoryInParentFolders": "always"
  }
}

Developing the Package

Change to the package directory and install dependencies:

cd packages/simple-logger
npm install

Package Management

When you are ready to publish your package:

npm run release

This single command will:

[!TIP] For detailed information about package publishing, versioning, and local development workflows, see the NPM Package Management Guide.