@quan-hyaku/log-my-app
v0.1.5
Published
Browser logging library that intercepts console methods and persists logs to IndexedDB with localStorage fallback
Maintainers
Readme
@quan-hyaku/log-my-app
Browser logging library that intercepts console.log, console.warn, console.error, console.info, and console.debug, persisting all output to IndexedDB (with automatic localStorage fallback). Retrieve, filter, or download your logs at any time.
Includes a custom Logger API with tag-based grouping for structured logging alongside automatic console interception.
Zero external dependencies.
Installation
npm install @quan-hyaku/log-my-appUsage
Console interception
import { initLogger, getLogs, getLogsByLevel, clearLogs, downloadLogs, destroyLogger } from '@quan-hyaku/log-my-app';
// Start intercepting console methods
await initLogger();
// Use console as normal — all output is automatically persisted
console.log('App started');
console.warn('Disk space low');
console.error('Failed to fetch', { status: 500 });
// Retrieve all persisted logs
const logs = await getLogs();
// Filter by level
const errors = await getLogsByLevel('error');
// Download logs as a file
await downloadLogs('json'); // or 'txt'
// Clear all stored logs
await clearLogs();
// Stop intercepting and clean up
destroyLogger();Custom Logger with tags
import { initLogger, Logger, getLogsByTag, destroyLogger } from '@quan-hyaku/log-my-app';
await initLogger();
// Log without a tag (writes directly to storage, no console output)
Logger.info('App started');
Logger.error('Unexpected failure', { code: 500 });
// Log with a tag for grouping/filtering
Logger.tag('auth').info('User logged in', { userId: 42 });
Logger.tag('auth').warn('Session expiring soon');
Logger.tag('network').error('Request timeout', { url: '/api/data' });
// Retrieve logs by tag
const authLogs = await getLogsByTag('auth');
const networkLogs = await getLogsByTag('network');
destroyLogger();The Logger writes directly to storage without producing console output. Console interception and the Logger API work independently -- use both together or either one alone.
Uncaught error capture
import { initLogger, getLogsByTag, destroyLogger } from '@quan-hyaku/log-my-app';
await initLogger({ captureUncaughtErrors: true });
// Uncaught errors and unhandled promise rejections are now
// automatically captured and stored as log entries.
//
// - Uncaught errors are tagged 'uncaught'
// - Unhandled rejections are tagged 'unhandled-rejection'
// - Both are stored at the 'error' level
// Retrieve captured errors by tag
const uncaught = await getLogsByTag('uncaught');
const rejections = await getLogsByTag('unhandled-rejection');
destroyLogger();Each captured entry includes the serialized Error (name, message, stack) along with source location metadata (filename, line number, column number) when available.
Configuration
Pass options to initLogger():
await initLogger({
maxLogCount: 10000, // Maximum log entries to keep (default: 5000)
storageKey: 'my-app-logs', // Storage key name (default: 'log-my-app')
captureUncaughtErrors: true, // Capture uncaught errors and unhandled rejections (default: false)
maxDepth: 3, // Max object nesting depth for serialization (default: 2)
captureStackTraces: false // Include stack traces in error serialization (default: true)
});Storage behavior
- IndexedDB is used by default when available
- localStorage is used automatically as a fallback (e.g., Firefox Private Browsing, restricted environments)
- localStorage mode caps entries at 1000 regardless of
maxLogCountto stay within browser storage limits - Log rotation happens periodically -- oldest entries are trimmed when the cap is exceeded
Same-origin storage access: Both IndexedDB and localStorage are scoped to the page origin. Any script running on the same origin can read the stored logs. Avoid logging sensitive data (tokens, passwords, PII) if your page loads third-party scripts.
API Reference
initLogger(config?: LoggerConfig): Promise<void>
Initializes the logger, sets up storage, and patches console methods. Throws if called while already initialized.
destroyLogger(): void
Restores original console methods and closes the storage connection.
getLogs(): Promise<LogEntry[]>
Returns all stored log entries, oldest first.
getLogsByLevel(level: LogLevel): Promise<LogEntry[]>
Returns log entries filtered by level. Valid levels: 'log', 'warn', 'error', 'info', 'debug'.
getLogsByTag(tag: string): Promise<LogEntry[]>
Returns log entries that match the given tag.
clearLogs(): Promise<void>
Deletes all stored log entries.
downloadLogs(format?: 'json' | 'txt'): Promise<void>
Triggers a file download of all stored logs.
'json'(default) — prettified JSON array ofLogEntryobjects'txt'— human-readable format:[timestamp] [LEVEL] message args
Logger
A singleton object for structured logging that writes directly to storage (no console output). Must be used after initLogger() has been called.
Logger.log(message, ...args)— log at'log'levelLogger.info(message, ...args)— log at'info'levelLogger.warn(message, ...args)— log at'warn'levelLogger.error(message, ...args)— log at'error'levelLogger.debug(message, ...args)— log at'debug'levelLogger.tag(name)— returns aTaggedLoggerthat attaches the given tag to every entry
TaggedLogger
Returned by Logger.tag(name). Has the same five methods (log, info, warn, error, debug) but every entry is tagged with the name passed to .tag().
const auth = Logger.tag('auth');
auth.info('login succeeded'); // entry.tag === 'auth'
auth.error('token expired'); // entry.tag === 'auth'Types
type LogLevel = 'log' | 'warn' | 'error' | 'info' | 'debug';
interface LogEntry {
timestamp: string; // ISO 8601 UTC
level: LogLevel;
message: string; // First console argument, stringified
args: string[]; // Remaining arguments, each stringified
tag?: string; // Optional tag for grouping (set via Logger.tag())
}
interface LoggerConfig {
maxLogCount?: number; // default: 5000
storageKey?: string; // default: 'log-my-app'
captureUncaughtErrors?: boolean; // default: false
maxDepth?: number; // default: 2
captureStackTraces?: boolean; // default: true
}License
MIT
