@a.nemreen/loggo
v0.1.3
Published
Beautiful console.log in development. Silent in production.
Maintainers
Readme
Why loggo?
Frontend apps fill up with temporary console.log calls. Before release you either:
- hunt them down by hand
- fight lint rules
- wrap every call in
if (import.meta.env.DEV) - or ship noisy (sometimes sensitive) output to users' consoles
loggo is a drop-in replacement: styled DevTools output while you build, and a silent noop build in production — so debug clutter never reaches the browser console.
Arguments are forwarded to native console.*. Objects stay expandable, DOM nodes stay inspectable, errors keep their stacks. Nothing is JSON.stringify'd.
Install
npm install @a.nemreen/loggopnpm add @a.nemreen/loggoyarn add @a.nemreen/loggobun add @a.nemreen/loggoRequirements: a modern bundler that honors package exports conditions (Vite, Webpack 5, Next.js, Rollup, esbuild, Parcel, and similar). Browser-first — not a Node/server logger.
Quick start
import { log } from '@a.nemreen/loggo';
log('Application initialized');
log('Current user:', user);
log('Selected element:', document.querySelector('#app'));
log.debug('Cache state:', cache);
log.info('User loaded:', user);
log.warn('Token expires soon');
log.error('Request failed:', error);Open DevTools. In development you get timestamps and level badges. In a production build you get nothing.
How to use
1. Replace console.log
// before
console.log('user', user);
// after
import { log } from '@a.nemreen/loggo';
log('user', user);log(...) and log.log(...) are the same.
2. Use levels when it helps
| Method | Console method | Badge |
|---------------|----------------|-------|
| log.debug() | console.debug | DEBUG |
| log() / log.log() | console.log | LOG |
| log.info() | console.info | INFO |
| log.warn() | console.warn | WARN |
| log.error() | console.error | ERROR |
log.debug('verbose detail', payload);
log.info('something happened', data);
log.warn('be careful', context);
log.error('it broke', error);2b. Full console surface
Every common DevTools helper is mirrored and silent in production:
| Method | Native |
|--------|--------|
| log.dir() / log.dirxml() | inspect object / DOM tree |
| log.table() | tabular data |
| log.group() / log.groupCollapsed() / log.groupEnd() | collapsible groups |
| log.time() / log.timeLog() / log.timeEnd() | timers |
| log.count() / log.countReset() | counters |
| log.assert() | log only when condition is false |
| log.trace() | stack trace |
| log.clear() | clear console |
| log.timeStamp() / log.profile() / log.profileEnd() | performance markers |
log.table(users, ['id', 'name']);
log.group('checkout');
log.time('pay');
log.count('retry');
log.timeEnd('pay');
log.groupEnd();
log.assert(total > 0, 'total must be positive', { total });
log.trace('how did we get here?', ctx);3. Name loggers per module
import { createLoggo } from '@a.nemreen/loggo';
const apiLog = createLoggo({ name: 'API' });
const authLog = createLoggo({ name: 'Auth' });
apiLog('Request started', { method: 'GET', path: '/users' });
apiLog.info('Response received', response);
authLog.warn('Session almost expired');
apiLog.error('Request failed', error);Example DevTools output:
12:14:02 › API LOG
Request started {…}
12:14:03 › API INFO
Response received {…}
12:14:05 › Auth WARN
Session almost expired
12:14:06 › API ERROR
Request failed Error: …4. Pass any value — keep DevTools native
log('primitives', 'hello', 123, true, null);
log('object', { id: 1, nested: { ok: true } });
log('array', [1, 2, 3]);
log('function', (x) => x * 2);
log('dom', document.querySelector('#app'));
log('error', new Error('boom'));
const circular = { label: 'node' };
circular.self = circular;
log('circular', circular); // safe — not JSON.stringified5. Framework notes
Vite / Vitest — mode maps to development / production export conditions automatically.
Next.js (App or Pages) — client components and browser bundles resolve the matching build. Prefer loggo for client-side debug logs; use your server logger or monitoring for the backend.
Create React App / Webpack 5 — production builds resolve the silent entry.
SSR caveat: if a resolver does not understand export conditions, the default is silent (fail closed). That is intentional.
Landing & demo
Interactive landing: boot line, typewriter code, CRT sample stream, and live DevTools cases.
Live: https://nemreen.info/loggo
Local:
npm install
npm run demoOpen http://localhost:4173/demo/.
cPanel deploy
npm run build:siteUpload the contents of site/ (or unzip loggo-cpanel.zip) into public_html/loggo/ so index.html is at public_html/loggo/index.html.
| Section | What you get |
|---------|----------------|
| Hero | Logo stamp-in + typed // dev logs. prod silent. // |
| Install / usage | Typewriter shell + app.ts snippets |
| Live console | Looping CRT-style sample output |
| Try samples | Real @a.nemreen/loggo calls in your DevTools |
| Named / before-after | API logger example + migration contrast |
How production silence works
loggo ships two builds:
| Condition | Entry | Behavior |
|-----------|--------|----------|
| development | styled logger | timestamps + badges + native args |
| production | noop logger | every method is () => {} |
| default (fallback) | noop logger | silent if conditions are unknown |
Bundlers pick the entry by build mode. Production apps import the noop file directly — no per-call if (isProd) checks, and no reliance on dead-code elimination to strip the pretty path.
All levels are silent in production, including warn and error. Real production errors belong in Sentry (or similar) — not in the user's console via loggo.
API
export type LogFn = (...args: unknown[]) => void;
export interface Loggo {
(...args: unknown[]): void;
debug: LogFn;
log: LogFn;
info: LogFn;
warn: LogFn;
error: LogFn;
dir: (item?: unknown, options?: Record<string, unknown>) => void;
dirxml: LogFn;
table: (data?: unknown, columns?: string[]) => void;
group: LogFn;
groupCollapsed: LogFn;
groupEnd: () => void;
time: (label?: string) => void;
timeLog: (label?: string, ...data: unknown[]) => void;
timeEnd: (label?: string) => void;
count: (label?: string) => void;
countReset: (label?: string) => void;
assert: (condition?: boolean, ...data: unknown[]) => void;
trace: LogFn;
clear: () => void;
timeStamp: (label?: string) => void;
profile: (label?: string) => void;
profileEnd: (label?: string) => void;
}
export interface LoggoOptions {
/** Shown beside the level badge; also scopes time/count labels */
name?: string;
}
/** Shared default logger */
export declare const log: Loggo;
/** Create a named (or extra) logger instance */
export declare function createLoggo(options?: LoggoOptions): Loggo;Styled level lines use a blank line above the badge and put arguments on the next line so DevTools output stays readable instead of cramped.
What it replaces / what it doesn't
Replaces
console.log(...)
console.info(...)
console.warn(...)
console.error(...)
console.debug(...)
console.table(...)
console.dir(...)
console.group(...)
console.time(...)
// …and the rest of the console helpers mirrored on `log`if (import.meta.env.DEV) {
console.log(...);
}Does not replace
- Sentry / Datadog / browser monitoring
- Pino / Winston / backend logging
- Analytics or audit trails
- Shipping logs to a server
Security
Helps prevent accidental exposure of debugging data through the production browser console.
It does not guarantee that secrets or personal data never reach the client. loggo only silences its own console output. It cannot protect values already present in frontend code, API responses, storage, or network traffic.
Browser support
Designed for modern Chromium, Firefox, and Safari DevTools. Uses console.* with %c styling and Intl.DateTimeFormat. No polyfills. No runtime dependencies.
Project scripts
npm run build # emit dist (dev + prod + types)
npm run demo # build + serve interactive demoLinks
- npm: npmjs.com/package/@a.nemreen/loggo
- Demo: nemreen.info/loggo
- License: MIT
