implement log lib

This commit is contained in:
2025-09-11 09:57:44 +02:00
parent 539ebf01d9
commit 6b01ec5e19
6 changed files with 141 additions and 5 deletions
+6 -1
View File
@@ -9,7 +9,12 @@ export default defineConfig([
files: ['**/*.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
plugins: {js},
extends: ['js/recommended'],
languageOptions: {globals: {...globals.browser, ...globals.node}}
languageOptions: {globals: {...globals.browser, ...globals.node}},
rules: {
'no-unused-vars': 'warn',
'@typescript-eslint/no-unused-vars': ['warn']
}
},
globalIgnores(['dist'])
])
+3 -1
View File
@@ -7,7 +7,9 @@
"typecheck": "tsc --noEmit"
},
"dependencies": {},
"dependencies": {
"chalk": "^5.6.2"
},
"devDependencies": {
"@eslint/js": "^9.35.0",
"@types/bun": "^1.2.21",
+19
View File
@@ -0,0 +1,19 @@
import {Chalk} from 'chalk'
import {Level} from './types'
const chalk = new Chalk({level: 2}) // 256 colors
export function get_color(level: Level) {
switch (level) {
case Level.DEBUG:
return chalk.blueBright
case Level.TRACE:
return chalk.green
case Level.INFO:
return (str: string) => str
case Level.WARNING:
return chalk.hex('#FFA500')
case Level.ERROR:
return chalk.red
}
}
+5 -3
View File
@@ -1,3 +1,5 @@
export function greet() {
console.log('Hello, world!')
}
import {Level, type WriterOptions, type Writer} from './types'
import {Logger, writers, options} from './logger'
export default (namespace: string): Logger => new Logger(namespace)
export {Logger, Level, type WriterOptions, type Writer, writers, options}
+79
View File
@@ -0,0 +1,79 @@
import {Level, type Options, type Writer} from './types'
export const writers = new Map<string, Writer>()
export const options: Options = {
format: '[$time] $level $namespace :',
pad_level: true,
verbose: true
}
export class Logger {
constructor(private readonly _namespace: string) {}
public get namespace(): string {
return this._namespace
}
public extend(sub_namespace: string): Logger {
return new Logger(`${this.namespace}:${sub_namespace}`)
}
public debug(...data: unknown[]): void {
log(data, Level.DEBUG, this._namespace)
}
public trace(...data: unknown[]): void {
log(data, Level.TRACE, this._namespace)
}
public info(...data: unknown[]): void {
log(data, Level.INFO, this._namespace)
}
public warn(...data: unknown[]): void {
log(data, Level.WARNING, this._namespace)
}
public error(...data: unknown[]): void {
log(data, Level.ERROR, this._namespace)
}
}
function log(message: unknown[], level: Level, namespace: string): void {
if (writers.size === 0) {
if (options.verbose) console.log('No writer subscribed, discard message')
return
}
// Format header of log
const head = options.format.replace('$time', new Date().toISOString()).replace('$namespace', namespace)
let lvl = get_string(level)
if (!options.pad_level) lvl = lvl.trimEnd()
const head_bw = head.replace('$level', lvl)
for (const [name, writer] of writers.entries()) {
const options = writer.options
if (options?.minLevel > level) {
if (options.verbose) console.log(`Writer's level is lower, discard message for ${name}`)
continue
}
writer.log(level, head_bw, ...message)
}
}
function get_string(level: Level): string {
switch (level) {
case Level.DEBUG:
return 'DEBUG '
case Level.TRACE:
return 'TRACE '
case Level.INFO:
return 'INFO '
case Level.WARNING:
return 'WARNING'
case Level.ERROR:
return 'ERROR '
}
}
+29
View File
@@ -0,0 +1,29 @@
/**
* Global options for loggers
*
* Format : can contain $time, $level and $namespace
*/
export type Options = {
format: string
pad_level: boolean
verbose: boolean
}
export enum Level {
TRACE = 0,
DEBUG = 1,
INFO = 2,
WARNING = 3,
ERROR = 4
}
export type WriterOptions = {
minLevel: Level
[key: string | number | symbol]: unknown
}
export interface Writer {
log(level: Level, ...data: unknown[]): void
get options(): WriterOptions
readonly _options: WriterOptions
}