Simple Logger
A lightweight, flexible logging system for CourseBook that supports namespace-based logging with different log levels.
Features:
- Written in TypeScript
- Builds to both modern ES modules and CommonJS formats
- Provides TypeScript type definitions
- ESLint for code linting
- Prettier for code formatting
- Vitest for testing
- Tsup for building
- Minimal dependencies
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
component:
- Matches all loggers starting with ‘component:’component:submodule
- Matches exact namespace/component:\d+/
- Matches using regex pattern*
- Matches all namespaces
Log Levels
none
- Disables all logging for the namespacetrace
- Verbose debugging informationinfo
- Informational messages and errors
When you set a log level, all levels of equal or higher severity will be logged:
- Setting level to ‘none’ disables all logging for that namespace
- Setting level to ‘trace’ shows trace and info logs
- Setting level to ‘info’ shows only info logs
Simple Log Level Design
The logging system uses a minimal three-level hierarchy: none
, trace
, and info
.
none
allows you to completely disable logging for specific namespaces while keeping others activeinfo
is the default level for regular logging, covering everything you would normally output withconsole.log
, including warnings and errors that should be visible in productiontrace
is solely for debugging and is typically enabled only for specific namespaces during development
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
- Namespace-based Logging: Organize logs by component and operation
- Pattern Matching: Control log levels using string prefixes or regex patterns
- Log Level Hierarchy: none → trace → info
- Object Serialization: Automatically pretty-print objects
- Global Enable/Disable: Quickly toggle all logging
- Singleton Pattern: Centralized logging control
- Custom Log Functions: Replace default console.log with custom output handlers
- Flexible Output: Support for VSCode messages, file logging, external services, and more
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
packages
— Contains the primary package(s) for this repository (e.g.,simple-logger
). Each package is self-contained and can be copied out and used independently.examples
— Contains examples of how to use the packages. Each example is a minimal, standalone project.playgrounds
— Contains demos of the dependencies of the primary package(s). Each playground is a minimal, standalone project.docs
— Contains various documentation for users and developers..github
— Contains GitHub-specific files, such as workflows and issue templates.
How to Use This Repo
- To work on a package, go to
packages/<package-name>
and follow its README. - To try an example, go to
examples/<example-name>
and follow its README. - To run the playground, go to
playground/<package-name>
and follow its README. - For documentation, see the
docs
folder.
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:
- Open Visual Studio Code.
- Navigate to
File > Open Workspace from File...
. - 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
- Read the Project Roadmap for project goals, status, evolution, and development guidelines.
- Read the Development Guide for detailed information on the package architecture, build configuration, and implementation patterns.
- Follow the Contributing Guide for contribution guidelines, coding standards, and best practices.
Package Management
When you are ready to publish your package:
npm run release
This single command will:
- Validate your code with the full validation pipeline
- Analyze commits to determine version bump
- Update package.json version and changelog
- Build the package
- Create and push git tag
- Create GitHub release
- Publish to NPM
[!TIP] For detailed information about package publishing, versioning, and local development workflows, see the NPM Package Management Guide.