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

@egi/smart-log

v1.0.0

Published

Smart logging library with severity levels, flexible formatting, and optional DB persistence

Readme

smart-log

A TypeScript logging library with severity levels, flexible formatting, stack trace integration, and optional persistence via a pluggable db writer.

Installation

npm install @egi/smart-log

Quick Start

import { smartLog, SmartSeverityLevel } from "@egi/smart-log";

smartLog.info("Application started");
smartLog.warning("Low disk space");
smartLog.error(new Error("Something went wrong"));

A singleton instance smartLog is exported for convenience. Create additional instances as needed:

import { SmartLog } from "@egi/smart-log";

const log = new SmartLog({ logLevel: SmartSeverityLevel.Debug });
log.debug("detailed trace");

Severity Levels

enum SmartSeverityLevel {
    None = 0, Fatal = 1, Error = 2, Warning = 3,
    Info = 4, Verbose = 5, Debug = 6, All = 9
}

Methods: fatal(), error(), warning(), info(), verbose(), debug(), write() (no severity).

Each method accepts a string, an Error, or a string + SmartMessageOptions:

log.error("fetch failed", { data: err, location: "api.ts:42" });
log.info("user logged in", { type: "BACKEND", timestamp: new Date() });
log.debug("internal detail", { skipConsole: true });   // db writer only
log.info("console only",    { skipDatabase: true });   // console only

Options

const log = new SmartLog({
    logLevel: SmartSeverityLevel.Info,  // minimum level to process
    logChannels: true,                  // route to console.error/warn/info/debug by level
    location: true,                     // include caller location in output
    leading: "[APP]",                   // prefix every line
    separator: " | ",                   // separator between format elements
    lowerCase: false,                   // lowercase severity codes
    user: "admin",                      // user id stamped on each log entry
    dbWriter: myWriter,                 // persist entries (see below)
    outputHook: (text, msg) => {},      // side-effect hook; return { suppress: true } to skip console
    formatHook: (text, msg) => text,     // transform output text before console
    stackProvider: () => new Error(),   // custom stack source for caller detection
});

Log Format

The output format is fully configurable via sequence. Elements can be enum values, fixed strings, or functions:

import { SmartLog, SmartLogFormatElement } from "@egi/smart-log";

const log = new SmartLog({
    leading: "%",
    lowerCase: true,
    location: true,
    sequence: [
        SmartLogFormatElement.Severity,
        "myapp",
        SmartLogFormatElement.Timestamp,
        SmartLogFormatElement.Message,
        SmartLogFormatElement.Location,
        () => process.pid.toString()
    ]
});

| Element | Output | |---|---| | Severity | Single letter code: F E W I I D | | Type | First letter of the location type (App → A) | | Timestamp | 2024-03-15 14:30:00.000 | | Message | The log message text | | Location | [file.ts:42 (functionName)] |

Default sequence: Severity - Type - Timestamp: Message [Location]

Output Hook

outputHook is called after formatting and before console output. Use it for side effects — writing to a file, sending to a remote service, emitting events — without needing to implement a full ISmartLogDbWriter.

Return false to prevent the entry from appearing on the console. Both sync and async hooks are supported.

import { SmartLog, LogMessage } from "@egi/smart-log";

const log = new SmartLog({
    outputHook: (text: string, message: LogMessage) => {
        fs.appendFileSync("app.log", text + "\n");
        // return false to hide from console as well
    }
});

// or set it later:
log.setOutputHook(async (text, message) => {
    await sendToSlack(text);
    return false;  // already sent, no need to also print
});

// transform text only:
log.setFormatHook((text) => `[MyApp] ${text}`);

formatHook and outputHook serve different purposes:

| Hook | Purpose | Must return | |---|---|---| | formatHook | Transform the formatted text | Modified string | | outputHook | Side effects / suppress console | void or false |

Database Persistence

Implement ISmartLogDbWriter to persist log entries:

import { ISmartLogDbWriter, LogMessage } from "@egi/smart-log";

class MyDbWriter implements ISmartLogDbWriter {
    write(entry: LogMessage): Promise<void> | void {
        // entry contains: severityLevel, type, location, message, data, timestamp, user
        return db.insert("logs", entry);
    }
}

const log = new SmartLog({ dbWriter: new MyDbWriter() });

// change or disable the writer at runtime:
log.setDbWriter(null);

The writer receives the raw LogMessage object — sync or async writers are both supported.

Location Types

enum SmartLocation {
    App = "APP",
    Frontend = "FRONTEND",
    Backend = "BACKEND",
    Database = "DATABASE",
    UpgradeManager = "UPGRADE-MANAGER"
}

Date Utilities

import { toSmartDbDate, toSmartDbTimestamp, smartDbToDate, smartDbToDateTime } from "@egi/smart-log";

toSmartDbDate(new Date())                // "2024-03-15 14:30:00"
toSmartDbTimestamp(new Date())           // "2024-03-15 14:30:00.000"
smartDbToDate("2024-03-15 14:30:00")     // Date object
smartDbToDateTime(1710508200000)         // Luxon DateTime object

SmartError

A structured error class for use throughout the stack:

import { SmartError, SmartSeverityLevel, SmartLocation } from "@egi/smart-log";

throw new SmartError({
    message: "Record not found",
    code: 404,
    type: SmartSeverityLevel.Error,
    location: SmartLocation.Backend
});

SmartTools

Utility singleton for string conversions and stack inspection:

import { tools } from "@egi/smart-log";

tools.camelCase("my_field_name")   // "myFieldName"
tools.snakeCase("myFieldName")     // "my_field_name"
tools.kebabCase("MyComponent")     // "my-component"
tools.pascalCase("my_model")       // "MyModel"

tools.getCallerFromStack()         // "src/app.ts:42 (doSomething)"