
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
A TypeScript class-aware logging library that provides clear context in log outputs with flexible configuration options.
The name is inspired by Hog Rider, the best Clash of Clans troop. Also, the name Log was already taken. Don't worry though, I named everything else normally!
A TypeScript class-aware logging library that provides clear context in log outputs with flexible configuration options.
Log is designed for object-oriented codebases where understanding the source of a log message is critical. It's lightweight, performant, and easy to integrate into any project.
error, warn, info, debug, and traceInstall Log using your favorite package manager:
npm install logrider
npm install logrider
# or
pnpm add logrider
pnpm add logrider
# or
yarn add logrider
yarn add logrider
Here's how to get started with Log in your TypeScript project.
Instantiate Log directly in your class, providing the class name as a string.
import { Log } from "Log";
class UserService {
private log = new Log("UserService");
getUser(id: string) {
this.log.info(`Fetching user with id: ${id}`);
if (!id) {
this.log.error("User ID is missing!");
return;
}
// ...
this.log.debug("User data processed successfully.");
}
}
const userService = new UserService();
userService.getUser("123");
The code above will produce the following output in your console:
[INFO] [UserService] Fetching user with id: 123
[DEBUG] [UserService] User data processed successfully.
If you have multiple instances of a class and need to differentiate their logs, you can provide an optional instanceId as the second argument.
import { Log } from "Log";
class Worker {
private log: Log;
constructor(id: string) {
this.log = new Log("Worker", id);
}
processTask(task: string) {
this.log.info(`Starting task: ${task}`);
// ...
this.log.info(`Finished task: ${task}`);
}
}
const worker1 = new Worker("worker-1");
const worker2 = new Worker("worker-2");
worker1.processTask("process-images");
worker2.processTask("send-emails");
This will result in a clear, instance-specific log output:
[INFO] [Worker:worker-1] Starting task: process-images
[INFO] [Worker:worker-1] Finished task: process-images
[INFO] [Worker:worker-2] Starting task: send-emails
[INFO] [Worker:worker-2] Finished task: send-emails
Log supports file-based configuration through a logrider.config.json file. The library automatically searches for this file starting from the current working directory up to the root directory.
Create a logrider.config.json file in your project root:
{
"level": "INFO",
"timestamp": false,
"colors": true,
"includeLevel": true,
"includeName": true,
"transports": {
"console": {
"type": "console"
},
"errors": {
"type": "file",
"path": "./logs/errors.log",
"levels": {
"include": ["ERROR", "WARN"]
}
},
"audit": {
"type": "json",
"path": "./logs/audit.json",
"levels": {
"exclude": ["DEBUG", "TRACE"]
}
}
},
"defaultTransports": ["console", "audit"]
}
| Option | Type | Default | Description |
|---|---|---|---|
level | string | "INFO" | Minimum log level to output |
timestamp | boolean | false | Include timestamps in log output |
colors | boolean | true | Enable colored output |
includeLevel | boolean | true | Include [LEVEL] in log output |
includeName | boolean | true | Include [ClassName] in log output |
transports | object | - | Named transport configurations |
defaultTransports | string[] | ["console"] | Default transports to use |
| Option | Type | Default | Description |
| ------------------- | -------- | ------------- | ----------------------------------- |
level | string | "INFO" | Minimum log level to output |
timestamp | boolean | false | Include timestamps in log output |
colors | boolean | true | Enable colored output |
includeLevel | boolean | true | Include [LEVEL] in log output |
includeName | boolean | true | Include [ClassName] in log output |
transports | object | - | Named transport configurations |
defaultTransports | string[] | ["console"] | Default transports to use |
LogRider supports environment-specific configurations using the LOGRIDER_ENV environment variable. This allows you to have different logging configurations for development, staging, and production environments.
Create a logrider.config.json file with environment-specific sections:
{
"level": "INFO",
"timestamp": false,
"colors": true,
"transports": {
"console": {
"type": "console"
}
},
"defaultTransports": ["console"],
"development": {
"level": "DEBUG",
"timestamp": true,
"colors": true,
"transports": {
"console": {
"type": "console"
},
"debug": {
"type": "file",
"path": "./logs/debug.log"
}
},
"defaultTransports": ["console", "debug"]
},
"production": {
"level": "WARN",
"timestamp": true,
"colors": false,
"transports": {
"console": {
"type": "console",
"colors": false
},
"app-logs": {
"type": "log",
"path": "./logs/app.log",
"method": "size",
"maxSize": "50MB",
"maxFiles": 10,
"archive": {
"enabled": true,
"directory": "./logs/archive",
"compress": true,
"retentionDays": 90
}
},
"error-logs": {
"type": "log",
"path": "./logs/errors.log",
"method": "date",
"dateFormat": "YYYY-MM-DD",
"maxFiles": 365,
"levels": {
"include": ["ERROR", "WARN"]
},
"archive": {
"enabled": true,
"directory": "./logs/archive/errors",
"compress": true,
"retentionDays": 365
}
}
},
"defaultTransports": ["console", "app-logs", "error-logs"]
}
}
Set the LOGRIDER_ENV environment variable to specify which environment configuration to use:
# Use development configuration
export LOGRIDER_ENV=development
node app.js
# Use production configuration
export LOGRIDER_ENV=production
node app.js
# Use root configuration (default behavior)
unset LOGRIDER_ENV
node app.js
LOGRIDER_ENV environment variableDevelopment Environment:
Production Environment:
Staging Environment:
{
"staging": {
"level": "INFO",
"timestamp": true,
"colors": false,
"transports": {
"console": {
"type": "console"
},
"staging-logs": {
"type": "log",
"path": "./logs/staging.log",
"method": "size",
"maxSize": "25MB",
"maxFiles": 5
}
},
"defaultTransports": ["console", "staging-logs"]
}
}
This environment-based configuration system allows you to:
{
"type": "console",
"colors": true,
"levels": {
"include": ["ERROR", "WARN", "INFO"]
}
}
{
"type": "file",
"path": "./logs/app.log",
"colors": false,
"levels": {
"exclude": ["DEBUG", "TRACE"]
}
}
{
"type": "json",
"path": "./logs/structured.json",
"colors": false,
"levels": {
"include": ["ERROR", "WARN"]
}
}
The log transport provides automatic file rotation, archiving, and intelligent log management - perfect for production applications.
Size-based Rotation:
{
"type": "log",
"path": "./logs/app.log",
"method": "size",
"maxSize": "10MB",
"maxFiles": 5,
"colors": false,
"archive": {
"enabled": true,
"directory": "./logs/archive",
"compress": true,
"retentionDays": 30
}
}
Date-based Rotation:
{
"type": "log",
"path": "./logs/daily.log",
"method": "date",
"dateFormat": "YYYY-MM-DD",
"maxFiles": 30,
"colors": false,
"archive": {
"enabled": true,
"directory": "./logs/archive/daily",
"compress": true,
"retentionDays": 90
}
}
Log Transport Options:
| Option | Type | Default | Description |
|---|---|---|---|
method | "size" | "date" | - | Required. Rotation strategy |
maxSize | string | "10MB" | Maximum file size (for size method) |
maxFiles | number | 5 | Number of rotated files to keep |
dateFormat | string | "YYYY-MM-DD" | Date format for rotation ("YYYY-MM-DD", "YYYY-MM-DD-HH", "YYYY-MM") |
archive.enabled | boolean | true | Enable archiving of rotated files |
archive.directory | string | "./logs/{transport-name}" | Directory for archived files |
archive.compress | boolean | true | Compress archived files with gzip |
archive.retentionDays | number | 30 | Days to keep archived files (0 = forever) |
Why Use Log Transport?
Each transport can have its own level filtering:
include: Only output these levelsexclude: Output all levels except theseNote: include and exclude are mutually exclusive.
Each transport can have its own color configuration, allowing you to enable colors for console output while disabling them for file outputs:
{
"transports": {
"console": {
"type": "console",
"colors": true
},
"file": {
"type": "file",
"path": "./logs/app.log",
"colors": false
},
"coloredFile": {
"type": "file",
"path": "./logs/debug.log",
"colors": true
}
}
}
Default Color Settings:
colors: true (enabled by default)colors: false (disabled by default)colors: false (disabled by default)colors: false (disabled by default)Custom Color Configuration: You can also specify custom colors for each log level:
{
"transports": {
"console": {
"type": "console",
"colors": {
"ERROR": "red",
"WARN": "yellow",
"INFO": "blue",
"DEBUG": "green",
"TRACE": "gray"
}
}
}
}
You can override configuration at runtime using the setConfig method:
const log = new Log("MyClass");
// Override configuration for this logger instance
log.setConfig({
includeLevel: false,
includeName: false,
timestamp: true,
timestamp: true,
});
log.info("This is a minimal log"); // Output: 2025-07-07T12:00:00.000Z This is a minimal log
new Log(className: string, instanceId?: string, configPath?: string)Creates a new logger instance.
className: The name of the class or context for the loggerinstanceId (optional): A unique identifier for the instanceconfigPath (optional): Custom path to configuration fileAll log methods have the same signature: (message: string, options?: LogOptions) => void.
log.error(message, options)log.warn(message, options)log.info(message, options)log.debug(message, options)log.trace(message, options)You can pass an options object as the second argument to any log method.
interface LogOptions {
timestamp?: boolean;
metadata?: Record<string, any>;
level?: LogLevel; // Override minimum level check
colors?: boolean; // Override color usage
transports?: (Transport | string)[]; // Override transports
format?: string; // Override message format
includeLevel?: boolean; // Override includeLevel from config
includeName?: boolean; // Override includeName from config
}
With Timestamp:
const log = new Log("MyClass");
log.info("This is a timed log entry.", { timestamp: true });
// Output: 2025-07-07T12:00:00.000Z [INFO] [MyClass] This is a timed log entry.
With Metadata:
log.error("Database connection failed", {
metadata: { host: "localhost", port: 5432, retries: 3 },
});
With Custom Format:
log.info("Custom message", {
format: "{timestamp} - {level}: {message} ({context})",
});
With Specific Transports:
log.error("Critical error", {
transports: ["console", "errors"], // Only output to these transports
});
// Get current configuration
const config = log.getConfig();
// Update configuration
log.setConfig({ includeLevel: false });
// Set default transports
log.setDefaultTransports(["console", "file"]);
// Get transport names
const transports = log.getTransportNames();
[INFO] [UserService] Fetching user data
2025-07-07T12:00:00.000Z [INFO] [UserService] Fetching user data
[INFO] [Worker:thread-1] Processing task
[UserService] Fetching user data
[INFO] Fetching user data
Fetching user data
Here's a comprehensive configuration suitable for production applications:
{
"level": "INFO",
"timestamp": true,
"colors": false,
"transports": {
"console": {
"type": "console",
"colors": true,
"levels": {
"include": ["ERROR", "WARN", "INFO"]
}
},
"app-logs": {
"type": "log",
"path": "./logs/app.log",
"method": "size",
"maxSize": "50MB",
"maxFiles": 10,
"colors": false,
"archive": {
"enabled": true,
"directory": "./logs/archive",
"compress": true,
"retentionDays": 90
}
},
"error-logs": {
"type": "log",
"path": "./logs/errors.log",
"method": "date",
"dateFormat": "YYYY-MM-DD",
"maxFiles": 365,
"colors": false,
"levels": {
"include": ["ERROR", "WARN"]
},
"archive": {
"enabled": true,
"directory": "./logs/archive/errors",
"compress": true,
"retentionDays": 365
}
},
"audit": {
"type": "json",
"path": "./logs/audit.json",
"colors": false,
"levels": {
"exclude": ["DEBUG", "TRACE"]
}
}
},
"defaultTransports": ["console", "app-logs", "error-logs"]
}
const log = new Log("PaymentService");
// Critical errors go to multiple destinations
log.error("Payment processing failed", {
transports: ["console", "errors", "audit"],
metadata: { orderId: "12345", amount: 99.99 },
});
// Debug info only to console
log.debug("Payment validation passed", {
transports: ["console"],
});
import { Log, ConsoleTransport, FileTransport } from "Log";
// Create transports with different color settings
const consoleTransport = new ConsoleTransport("console", undefined, true);
const fileTransport = new FileTransport("./app.log", "file", undefined, false);
const coloredFileTransport = new FileTransport(
"./debug.log",
"coloredFile",
undefined,
true
);
const log = new Log("MyService");
// Update configuration to use custom transports
log.setConfig({
...log.getConfig(),
transports: {
console: consoleTransport,
file: fileTransport,
coloredFile: coloredFileTransport,
},
});
// Console output will have colors, file output won't
log.setDefaultTransports(["console", "file"]);
log.info("This message shows colors in console but not in file");
Log is built with TypeScript and provides full type safety:
import { Log, LogLevel, LogOptions, LogTransport, RotationMethod } from "Log";
const log = new Log("TypedService");
// All methods are fully typed
const options: LogOptions = {
timestamp: true,
metadata: { userId: 123 },
level: LogLevel.DEBUG,
level: LogLevel.DEBUG,
};
log.info("Typed message", options);
// You can also use LogTransport directly for programmatic configuration
const rotatingTransport = new LogTransport("./logs/app.log", {
method: RotationMethod.SIZE,
maxSize: "10MB",
maxFiles: 5,
archiveDir: "./logs/archive",
compress: true,
retentionDays: 30,
});
When testing code that uses Log, you can easily mock the logger:
import { Log } from "Log";
// Mock all log methods
const mockLog = {
error: jest.fn(),
warn: jest.fn(),
info: jest.fn(),
debug: jest.fn(),
trace: jest.fn(),
} as unknown as Log;
// Use in your tests
class TestService {
constructor(private log: Log = mockLog) {}
}
ISC
FAQs
A TypeScript class-aware logging library that provides clear context in log outputs with flexible configuration options.
We found that logrider demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.