diff --git a/packages/koishi-utils/src/logger.ts b/packages/koishi-utils/src/logger.ts index 7c6a836dfd..4b244448f7 100644 --- a/packages/koishi-utils/src/logger.ts +++ b/packages/koishi-utils/src/logger.ts @@ -48,7 +48,9 @@ export class Logger { private code: number private displayName: string - constructor(private name: string, private showDiff = false) { + public stream: NodeJS.WritableStream = process.stderr + + constructor(public name: string, private showDiff = false) { if (name in instances) return instances[name] let hash = 0 for (let i = 0; i < name.length; i++) { @@ -72,7 +74,7 @@ export class Logger { private createMethod(name: LogType, prefix: string, minLevel: number) { this[name] = (...args: [any, ...any[]]) => { if (this.level < minLevel) return - process.stderr.write(prefix + this.displayName + this.format(...args) + '\n') + this.stream.write(prefix + this.displayName + this.format(...args) + '\n') } } diff --git a/packages/koishi-utils/tests/logger.spec.ts b/packages/koishi-utils/tests/logger.spec.ts new file mode 100644 index 0000000000..19c737f49f --- /dev/null +++ b/packages/koishi-utils/tests/logger.spec.ts @@ -0,0 +1,54 @@ +import { install, InstalledClock } from '@sinonjs/fake-timers' +import { expect } from 'chai' +import { Logger } from 'koishi-utils' +import { Writable } from 'stream' + +describe('Logger API', () => { + let logger: Logger + let data: string + let clock: InstalledClock + const { colors } = Logger.options + + before(() => { + Logger.options.colors = false + clock = install({ now: Date.now() }) + }) + + after(() => { + Logger.options.colors = colors + clock.uninstall() + }) + + it('basic support', () => { + logger = new Logger('test').extend('logger', true) + expect(logger.name).to.equal('test:logger') + logger.stream = new Writable({ + write(chunk, encoding, callback) { + data = chunk.toString() + callback() + }, + }) + }) + + it('format error', () => { + const error = new Error('message') + error.stack = null + logger.error(error) + expect(data).to.equal('[E] test:logger message\n') + }) + + it('format object', () => { + clock.tick(2) + const object = { foo: 'bar' } + logger.success(object) + expect(data).to.equal("[S] test:logger { foo: 'bar' } +2ms\n") + }) + + it('custom formatter', () => { + clock.tick(1) + Logger.formatters.x = () => 'custom' + Logger.levels[logger.name] = 2 + logger.info('%x%%x') + expect(data).to.equal('[I] test:logger custom%x +1ms\n') + }) +})