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

smart-logger-js

v1.0.0

Published

A lightweight, configurable logging utility with colors, timestamps, and context support

Readme

smart-logger-js

A lightweight, zero-dependency, opinionated state-change logger for JavaScript/TypeScript applications. Unlike traditional loggers that output messages, Smart Logger tracks data changes over time with intelligent diffing, debounced output, and visual console summaries.

Why Smart Logger?

The Problem

When debugging complex state changes in applications (React state, Redux stores, API responses), traditional console.log falls short:

// Traditional approach - hard to track what changed
console.log('user data:', userData);
// ... later
console.log('user data:', userData); // What changed? 🤷

You end up with walls of JSON in your console, manually comparing objects to find what changed.

The Opinionated Solution

Smart Logger takes a fundamentally different approach:

  1. Track, Don't Log — Instead of logging snapshots, it tracks a data stream and computes precise diffs
  2. Identity-Based Array Diffing — Arrays of objects are compared by identity (id, _id, key, etc.), not position
  3. Debounced Summaries — Multiple rapid changes are batched into readable summaries
  4. Visual Console Output — Changes are displayed in formatted tables with emojis for quick scanning
import { smartLog } from 'smart-logger-js';

// Just call smartLog with the same ID whenever data changes
smartLog('userData', { name: 'Alice', age: 30 });
// ... later
smartLog('userData', { name: 'Alice', age: 31 });

// Console shows:
// 🚨 [SmartLog] Summary: userData (1 update(s) in last 1s)
// ┌─────────┬──────────┬──────┬────┐
// │  Type   │   Path   │ From │ To │
// ├─────────┼──────────┼──────┼────┤
// │ ✏️ CHANGE │ age      │ 30   │ 31 │
// └─────────┴──────────┴──────┴────┘

Installation

pnpm add smart-logger-js
npm install smart-logger-js
yarn add smart-logger-js
bun add smart-logger-js

Quick Start

Simple API

The easiest way to use Smart Logger:

import { smartLog } from 'smart-logger-js';

// Track any data by giving it an ID
smartLog('myData', { count: 0 });

// Call again with updated data - changes are automatically detected
smartLog('myData', { count: 1 });
smartLog('myData', { count: 2, newField: 'hello' });

// After the debounce period (default 1s), you'll see a summary in the console

Instance API

For more control, create dedicated logger instances:

import { createSmartLogger } from 'smart-logger-js';

const logger = createSmartLogger({
  debounceMs: 500,        // Faster summaries
  ignoreArrMove: true,    // Don't log array reorderings
  maxPreviewLength: 100,  // Longer value previews
});

logger.log('users', usersArray);

API Reference

smartLog(id, data, options?)

The simple, stateless API. Manages logger instances automatically.

| Parameter | Type | Description | |-----------|------|-------------| | id | string | Unique identifier for this data stream | | data | unknown | The data snapshot to track | | options | SmartLogOptions | Configuration (only used on first call per ID) |

smartLog('users', usersData);
smartLog('settings', settingsData, { debounceMs: 2000 });

createSmartLogger(options?)

Creates a new SmartLogger instance with custom configuration.

const logger = createSmartLogger({
  debounceMs: 1000,
  ignoreArrMove: false,
  maxPreviewLength: 50,
  arrayIdentifierKeys: ['id', 'uuid'],
});

SmartLogger Class

The core logger class with full control.

Methods

| Method | Description | |--------|-------------| | log(id, data) | Track a data snapshot | | getHistory(id) | Get all recorded change batches for a stream | | clear(id) | Stop tracking and clear history for a stream | | clearAll() | Stop tracking all streams |

const logger = new SmartLogger();

logger.log('stream1', data);
const history = logger.getHistory('stream1');
logger.clear('stream1');

Helper Functions

import { clearSmartLog, clearAllSmartLogs } from 'smart-logger-js';

// Clear a specific stream from the simple API
clearSmartLog('userData');

// Clear all streams
clearAllSmartLogs();

Configuration Options

SmartLogOptions

| Option | Type | Default | Description | |--------|------|---------|-------------| | debounceMs | number | 1000 | Milliseconds to wait before flushing batched changes to console | | ignoreArrMove | boolean | false | If true, array MOVE operations won't be logged (useful when order doesn't matter) | | maxPreviewLength | number | 50 | Maximum characters for string value previews in the table | | arrayIdentifierKeys | string[] | [] | Custom keys to identify array elements (prioritized over defaults) |

Default Identifier Keys

When comparing arrays of objects, Smart Logger looks for these keys to match elements:

['id', '_id', 'key', 'uuid', 'uid', 'name', 'title']

Custom keys are checked first, then defaults.

Change Types

Smart Logger detects and categorizes changes:

| Type | Emoji | Description | |------|-------|-------------| | CREATE | 🆕 | New property or value added | | CHANGE | ✏️ | Existing value modified | | REMOVE | 🗑️ | Property deleted | | ADD | ➕ | New array element | | ARRAY_REMOVE | ➖ | Array element removed | | MOVE | ↔️ | Array element moved to different index |

Advanced Examples

Tracking React State

import { useEffect } from 'react';
import { smartLog } from 'smart-logger-js';

const MyComponent = () => {
  const [users, setUsers] = useState([]);

  useEffect(() => {
    smartLog('users-state', users);
  }, [users]);

  // ... component logic
};

Tracking API Responses

import { smartLog } from 'smart-logger-js';

const fetchUsers = async () => {
  const response = await api.getUsers();
  smartLog('api-users', response.data, { debounceMs: 0 }); // Immediate logging
  return response;
};

Ignoring Array Reordering

When tracking data where order doesn't matter (like a set of selected items):

const logger = createSmartLogger({ ignoreArrMove: true });

logger.log('selectedIds', [1, 2, 3]);
logger.log('selectedIds', [3, 1, 2]); // No changes logged - same items
logger.log('selectedIds', [3, 1, 2, 4]); // Only the ADD is logged

Custom Identifier Keys

For APIs with non-standard ID fields:

const logger = createSmartLogger({
  arrayIdentifierKeys: ['productCode', 'sku'], // Checked before defaults
});

logger.log('products', [
  { productCode: 'ABC', price: 100 },
  { productCode: 'XYZ', price: 200 },
]);

Accessing Change History

const logger = createSmartLogger();

logger.log('data', initialData);
logger.log('data', updatedData);

const history = logger.getHistory('data');
// history contains all ChangeBatch objects with timestamps and changes

Console Output Format

When changes are flushed, you'll see grouped output:

🚨 [SmartLog] Summary: userData (3 update(s) in last 1s)
  ▶ Update #1 @ 14:32:15.123
    State Before: { name: 'Alice', age: 30 }
    Changes: [{ type: 'CHANGE', path: [...], ... }]
    State After: { name: 'Alice', age: 31 }
    ┌──────────┬──────┬──────┬────┐
    │   Type   │ Path │ From │ To │
    ├──────────┼──────┼──────┼────┤
    │ ✏️ CHANGE │ age  │  30  │ 31 │
    └──────────┴──────┴──────┴────┘
  ▶ Update #2 @ 14:32:15.456
    ...

TypeScript Support

Full TypeScript support with exported types:

import type {
  SmartLogOptions,
  SmartChange,
  Difference,
  DifferenceCreate,
  DifferenceChange,
  DifferenceRemove,
  ArrayMovement,
  ArrayAddition,
  ArrayRemoval,
  ChangeBatch,
} from 'smart-logger-js';

Philosophy & Design Decisions

Why Debouncing?

In real applications, state often changes rapidly (e.g., typing in a form, dragging elements). Logging every micro-change creates noise. Smart Logger batches changes within a time window, giving you a meaningful summary instead of a flood of individual logs.

Why Identity-Based Array Diffing?

Consider tracking a todo list where items can be reordered:

// Traditional diff would see this as "everything changed"
before: [{ id: 1, text: 'A' }, { id: 2, text: 'B' }]
after:  [{ id: 2, text: 'B' }, { id: 1, text: 'A' }]

// Smart Logger sees: "item 1 moved from index 0 to 1, item 2 moved from index 1 to 0"

This makes debugging drag-and-drop, sorting, and filtering operations much clearer.

Why Opinionated Defaults?

Smart Logger makes assumptions that work for 90% of use cases:

  • Objects in arrays usually have id or similar identifier fields
  • You usually want to see changes after a brief pause, not during rapid updates
  • Visual console tables are more scannable than raw JSON

If these don't fit your use case, everything is configurable.

Comparison with Other Tools

| Feature | console.log | Redux DevTools | Smart Logger | |---------|-------------|----------------|--------------| | Works anywhere | ✅ | ❌ Redux only | ✅ | | Shows diffs | ❌ | ✅ | ✅ | | Identity-based array diff | ❌ | ❌ | ✅ | | Debounced output | ❌ | ❌ | ✅ | | Zero config | ✅ | ❌ | ✅ | | Visual tables | ❌ | ✅ | ✅ |

License

MIT