npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@laigma/logger

v1.0.1

Published

Logger utility for back/front apps

Readme

@laigma's logger

A lightweight logging library for Node.js and browser apps

npm version License: ISC TypeScript


📋 Overview

@laigma/logger is a lightweight logging library with four independent plugins:

| Plugin | Target | Purpose | |---|---|---| | createBackendLogger | Node.js | Colorized dev logs + structured JSON for production | | createBackendApiLogger | Node.js | Axios interceptor that logs HTTP requests/responses | | createFrontendLogger | Browser | Styled console.debug logs via CSS %c | | createFrontendApiLogger | Browser | Axios interceptor that logs HTTP requests/responses |


🚀 Installation

npm install @laigma/logger
yarn add @laigma/logger
pnpm add @laigma/logger

🖥️ Backend output preview

Dev mode — colorized ANSI, human-readable:

*** Something went wrong ***
Error: disk full

*** Record saved successfully ***
{"id":42,"name":"item"}

*** Retrying connection... ***
{"attempt":3,"maxRetries":5}

*** Server started ***
    3/6/2026, 13:40:40

Dev mode — API interceptor:

*** ✔  SUCCESS - /v1 ***
[GET] https://api.example.com/v1/users
Payload: {"page":1}
Status: 200 | Duration: 85 ms | Response size: 28 bytes
Response: {"userId":42,"name":"Alice"}

*** ✖  ERROR - /v1 ***
[GET] https://api.example.com/v1/products/999
Payload: null
Status: 404 | Duration: 55 ms
Message: Request failed with status code 404
Details: {"error":"Product not found"}

Production mode — structured JSON per line:

{"appName":"demo-app","appVersion":"1.0.0","level":"ERROR","message":"Auth failure","detail":{"name":"Error","message":"invalid token"},"metadata":{"category":"auth","scope":"login","level":"CRITICAL"},"timestamp":"2026-03-06T12:40:41.223Z"}
{"appName":"demo-app","appVersion":"1.0.0","level":"SUCCESS","message":"Order placed","detail":{"orderId":"ORD-001","total":99.99},"metadata":null,"timestamp":"2026-03-06T12:40:41.224Z"}
{"appName":"demo-app","appVersion":"1.0.0","level":"WARNING","message":"High memory usage","detail":{"usedMb":780,"limitMb":1024},"metadata":{"category":"system","scope":"memory","level":"HIGH"},"timestamp":"2026-03-06T12:40:41.224Z"}

🌐 Frontend output preview

Frontend logs use the browser DevTools console.debug with %c CSS styling. Each level has a distinct color, and object details are rendered as interactive expandable trees.

*** Something went wrong ***        ← red on #ffe6e6
*** Record saved successfully ***   ← green on #e6ffe6
*** Watch out ***                   ← orange on #fffbe6
*** App initialized ***             ← purple on #f3e6ff
    3/6/2026, 13:40:40

Frontend API interceptor — success and error details appear as expandable objects in DevTools:

*** ✔  SUCCESS - /v1 ***
▶ { method: "GET", url: "…", statusCode: 200, duration: 85, responseSize: 28, response: {…}, params: {…} }

*** ✖  ERROR - /v1 ***
▶ { method: "GET", url: "…", statusCode: 404, errorMessage: "…", errorDetails: {…}, duration: 55, params: null }

📖 Usage

BackendLogger

Structured logger for Node.js services. Supports two output modes controlled by envMode.

import { createBackendLogger } from "@laigma/logger";

const logger = createBackendLogger({
  envMode: "development", // "production" switches to structured JSON output
  appName: "my-app",
  appVersion: "1.0.0",
});

BackendLoggerConfig

| Property | Type | Default | Description | |---|---|---|---| | envMode | string | — | "production" enables JSON output; any other value uses colorized ANSI | | appName | string | "unknown" | Included in every production log entry | | appVersion | string | "unknown" | Included in every production log entry |

Methods

| Method | Signature | Notes | |---|---|---| | logError | (message, errorObj, metadata, stopProcess?) | errorObj and metadata required — all LogMetadata fields must be present. Pass stopProcess: true to call process.exit(1). | | logWarning | (message, detailObj, metadata) | detailObj and metadata required — all LogMetadata fields must be present. | | logSuccess | (message, detailObj?, metadata?) | All extra params optional. LogMetadata fields are optional. | | logInfo | (message, metadata?) | metadata optional. LogMetadata fields are optional. Appends a timestamp automatically. | | logProgressBar | (processed, total, message) | Renders an inline progress bar to stdout. |

LogMetadata

All fields are required when passed to logError or logWarning (Required<LogMetadata>). All fields are optional when passed to logInfo or logSuccess.

{
  category: string;  // e.g. "auth", "api", "storage"
  scope: string;     // e.g. "login", "http", "upload"
  level: "LOW" | "MEDIUM" | "HIGH" | "CRITICAL";
}

When metadata is omitted (allowed on logInfo/logSuccess), the production JSON output will contain "metadata": null. Only the fields you provide are included.

Examples

logger.logError("Auth failed", new Error("invalid token"), { category: "auth", scope: "login", level: "CRITICAL" });
logger.logWarning("High memory", { usedMb: 780 }, { category: "system", scope: "memory", level: "HIGH" });
logger.logSuccess("Order placed", { orderId: "ORD-001" });
logger.logInfo("Server started");

// progress bar — call on every iteration
for (let i = 1; i <= total; i++) {
  logger.logProgressBar(i, total, "Importing records");
}

BackendApiLogger

Attaches Axios request/response interceptors to automatically log all HTTP calls. Requires a BackendLogger instance.

import { createBackendLogger, createBackendApiLogger } from "@laigma/logger";

const logger = createBackendLogger({
  envMode: process.env.NODE_ENV,
  appName: "my-app",
  appVersion: "1.0.0",
});

const apiLogger = createBackendApiLogger(
  logger,
  process.env.NODE_ENV,
  { category: "api", scope: "http", level: "LOW" }, // optional, these are the defaults
);

apiLogger.attachLoggerInterceptors(axiosInstance);

Parameters

| Parameter | Type | Description | |---|---|---| | logger | BackendLogger | An instance created with createBackendLogger | | envMode | string | Controls dev vs production detail format (should match the logger's envMode) | | metadata | LogMetadata | Optional. Attached to every logError call. Defaults to { category: "api", scope: "http", level: "LOW" } |

Behavior

  • A request interceptor stamps config.metadata.startTime on every outgoing request to measure duration.
  • Successful responses call logSuccess with method, URL, status, duration, response size, and body.
    • Dev mode: formatted ANSI string.
    • Production mode: plain object.
  • Error responses call logError with method, URL, status, error message, error details, and duration, plus the metadata passed at construction time.
    • Dev mode: formatted ANSI string.
    • Production mode: plain object.

FrontendLogger

Browser logger using styled console.debug calls. Each level renders with a distinct CSS badge in DevTools.

import { createFrontendLogger } from "@laigma/logger";

const logger = createFrontendLogger({
  onError: (message) => alertError(message), // optional
});

FrontendLoggerConfig

| Property | Type | Description | |---|---|---| | onError | (message: string) => void | Optional callback invoked when logError is called with stopProcess = true |

Methods

| Method | Signature | Notes | |---|---|---| | logError | (message, errorObj?, stopProcess?) | All params after message optional. Pass stopProcess: true to trigger the onError callback. | | logWarning | (message, detailObj?) | — | | logSuccess | (message, detailObj?) | — | | logInfo | (message, detailObj?) | If no detailObj is provided, appends a timestamp automatically. |

Object details are passed as a third argument to console.debug so DevTools renders them as an expandable tree. String/primitive details are emitted in a second console.debug call.

Examples

logger.logError("Auth failed", error, true); // triggers onError
logger.logWarning("Slow response", { ms: 4200 });
logger.logSuccess("Profile saved", { userId: 7 });
logger.logInfo("App initialized");               // auto-appends timestamp
logger.logInfo("Route changed", { path: "/home" }); // uses provided detail

FrontendApiLogger

Attaches Axios request/response interceptors for browser apps. Requires a FrontendLogger instance. Detail objects are logged as interactive trees in DevTools — no string formatting, no envMode needed.

import { createFrontendLogger, createFrontendApiLogger } from "@laigma/logger";

const logger = createFrontendLogger({
  onError: (msg) => alertError(msg),
});

const apiLogger = createFrontendApiLogger(logger);

apiLogger.attachLoggerInterceptors(axiosInstance);

Parameters

| Parameter | Type | Description | |---|---|---| | logger | FrontendLogger | An instance created with createFrontendLogger |

Behavior

  • A request interceptor stamps config.metadata.startTime on every outgoing request to measure duration.
  • Successful responses call logSuccess with an object containing: method, url, params, statusCode, duration (ms), responseSize (bytes), response.
  • Error responses call logError with an object containing: method, url, params, statusCode, errorMessage, errorDetails, duration (ms).

Success detail shape

{
  method: string;           // "GET", "POST", …
  url: string;              // full URL (baseURL + url)
  params: unknown;          // request params or body
  statusCode: number;       // e.g. 200
  duration: number | null;  // ms from request start, null if unavailable
  responseSize: number;     // serialized response byte length
  response: unknown;        // response body
}

Error detail shape

{
  method: string;
  url: string;
  params: unknown;
  statusCode: number;       // defaults to 500 if no response object
  errorMessage: string;
  errorDetails: unknown;    // response body, null if unavailable
  duration: number | null;
}