@alwatr/logger
Version:
Fancy colorful console debugger with custom scope written in tiny TypeScript, ES module.
181 lines (153 loc) • 5.56 kB
text/typescript
import {getGlobalThis} from '@alwatr/global-this';
import {platformInfo} from '@alwatr/platform-info';
import type {AlwatrLogger} from './type.js';
const console_ = getGlobalThis().console;
/**
* Default debug mode state, determined by environment variables or localStorage.
*/
const defaultDebugMode = (() => {
if (platformInfo.development) {
if (platformInfo.isCli) {
return process.env.ALWATR_DEBUG !== '0';
} else {
return typeof localStorage !== 'undefined' && localStorage.getItem('ALWATR_DEBUG') !== '0';
}
}
// else
return platformInfo.isCli ?
Boolean(process.env.DEBUG)
: typeof localStorage !== 'undefined' && localStorage.getItem('ALWATR_DEBUG') === '1';
})();
/**
* A list of aesthetically pleasing colors for console logging, adapted for CLI and browser environments.
*/
const colorList = (() =>
platformInfo.isCli ?
['0;36', '0;35', '0;34', '0;33', '0;32'] // CLI-safe colors
: [
'#35b997',
'#f05561',
'#ee224a',
'#91c13e',
'#22af4b',
'#f0e995',
'#0fe995',
'#0f89ca',
'#08b9a5',
'#fee851',
'#ee573d',
'#f9df30',
'#1da2dc',
'#f05123',
'#ee2524',
])();
/**
* Platform-specific styling templates for logger output.
*/
const style_ = (() => ({
scope: platformInfo.isCli ? '\x1b[{{color}}m' : 'color: {{color}};',
reset: platformInfo.isCli ? '\x1b[0m' : 'color: inherit;',
}))();
/**
* Platform-specific format for displaying the logger's scope.
*/
const keySection_ = (() => (platformInfo.isCli ? '%s%s%s' : '%c%s%c'))();
// --- Utility Functions ---
let colorIndex_ = 0;
/**
* Cycles through the `colorList` to provide a new color for each logger instance.
*/
function getNextColor_(): string {
const color = colorList[colorIndex_];
colorIndex_ = (colorIndex_ + 1) % colorList.length;
return color;
}
/**
* Sanitizes and formats the logger name string by wrapping it in brackets if not already.
*/
function sanitizeName_(name: string): string {
if (!/^[[{<]/.test(name)) {
name = `{${name}}`;
}
return name;
}
// --- Core Factory ---
/**
* Create a logger function for fancy console debug with custom scope.
*
* - `color` is optional and automatically selected from an internal list.
* - `debug` is optional and automatically detected from `ALWATR_DEBUG` in localStorage or `process.env.DEBUG`.
*
* @example
* ```ts
* import {createLogger} from '@alwatr/logger';
* const logger = createLogger('my-module');
*
* logger.logMethodArgs?.('myMethod', {a: 1}); // This line is ignored if debugMode is false.
* ```
*/
export function createLogger(name: string, forceDebugMode = defaultDebugMode): AlwatrLogger {
const color = getNextColor_();
const styleScope = style_.scope.replace('{{color}}', color);
const sanitizedDomain = sanitizeName_(name);
/**
* Logger methods that are always available, regardless of debugMode.
*/
const requiredItems: AlwatrLogger = {
name,
banner:
platformInfo.isCli ?
console_.log.bind(console_, `\x1b[1;37;45m {{{ %s }}} ${style_.reset}`)
: console_.log.bind(
console_,
'%c%s',
'font-size: 2rem; background-color: #5858e8; color: #fff; padding: 1rem 4rem; border-radius: 0.5rem;',
),
accident:
platformInfo.isCli ?
console_.warn.bind(
console_,
`${styleScope}⚠️\n%s\x1b[33m.%s() Accident \`%s\`!${style_.reset}`,
sanitizedDomain,
)
: console_.warn.bind(console_, '%c%s%c.%s() Accident `%s`!', styleScope, sanitizedDomain, style_.reset),
error:
platformInfo.isCli ?
console_.error.bind(console_, `${styleScope}❌\n%s\x1b[31m.%s() Error \`%s\`${style_.reset}\n`, sanitizedDomain)
: console_.error.bind(console_, '%c%s%c.%s() Error `%s`\n', styleScope, sanitizedDomain, style_.reset),
};
if (!forceDebugMode) {
return requiredItems;
}
/**
* Logger methods available only when debugMode is true.
* Using `console.debug` which is often filtered by default in browsers unless "Verbose" logs are enabled.
*/
return {
...requiredItems,
logProperty: console_.debug.bind(console_, keySection_ + '.%s = %o;', styleScope, sanitizedDomain, style_.reset),
logMethod: console_.debug.bind(console_, keySection_ + '.%s();', styleScope, sanitizedDomain, style_.reset),
logFileModule: console_.debug.bind(console_, keySection_ + '/%s.js;', styleScope, sanitizedDomain, style_.reset),
logMethodArgs: console_.debug.bind(console_, keySection_ + '.%s(%o);', styleScope, sanitizedDomain, style_.reset),
logMethodFull: console_.debug.bind(
console_,
keySection_ + '.%s(%o) => %o',
styleScope,
sanitizedDomain,
style_.reset,
),
logStep: console_.debug.bind(console_, keySection_ + '.%s() -> %s', styleScope, sanitizedDomain, style_.reset),
logOther: console_.debug.bind(console_, keySection_, styleScope, sanitizedDomain, style_.reset),
logTable: console_.table.bind(console_),
incident:
platformInfo.isCli ?
console_.log.bind(
console_,
`${styleScope}🚸\n%s${style_.reset}.%s() Incident \`%s\`!${style_.reset}`,
sanitizedDomain,
)
: console_.log.bind(console_, '%c%s%c.%s() Incident `%s`!', styleScope, sanitizedDomain, 'color: orange;'),
time: (label: string) => console_.time(sanitizedDomain + '.' + label),
timeEnd: (label: string) => console_.timeEnd(sanitizedDomain + '.' + label),
};
}