@innei/pretty-logger-core 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/consola/consola.ts +409 -0
- package/consola/constants.ts +109 -0
- package/consola/core.ts +2 -0
- package/consola/index.ts +50 -0
- package/consola/reporters/basic.ts +74 -0
- package/consola/reporters/browser.ts +70 -0
- package/consola/reporters/fancy.ts +152 -0
- package/consola/reporters/file.ts +126 -0
- package/consola/reporters/index.ts +6 -0
- package/consola/reporters/logger.ts +31 -0
- package/consola/reporters/subscriber.ts +30 -0
- package/consola/shared.ts +6 -0
- package/consola/types.ts +60 -0
- package/consola/utils/box.ts +320 -0
- package/consola/utils/color.ts +132 -0
- package/consola/utils/error.ts +12 -0
- package/consola/utils/log.ts +22 -0
- package/consola/utils/stream.ts +9 -0
- package/consola/utils/string.ts +64 -0
- package/consola/utils/tester.ts +16 -0
- package/consola/utils.ts +9 -0
- package/consola.instance.ts +36 -0
- package/dist/index.d.mts +190 -0
- package/dist/index.d.ts +190 -0
- package/dist/index.js +1105 -0
- package/dist/index.mjs +1054 -0
- package/index.ts +3 -0
- package/package.json +23 -0
- package/tool.util.ts +29 -0
- package/tsup.config.ts +9 -0
|
@@ -0,0 +1,409 @@
|
|
|
1
|
+
import { defu } from 'defu'
|
|
2
|
+
import type { LogLevel, LogType } from './constants'
|
|
3
|
+
import type {
|
|
4
|
+
ConsolaOptions,
|
|
5
|
+
ConsolaReporter,
|
|
6
|
+
InputLogObject,
|
|
7
|
+
LogObject,
|
|
8
|
+
} from './types'
|
|
9
|
+
|
|
10
|
+
import { LogTypes } from './constants'
|
|
11
|
+
import { isLogObj } from './utils/log'
|
|
12
|
+
|
|
13
|
+
let paused = false
|
|
14
|
+
const queue: any[] = []
|
|
15
|
+
|
|
16
|
+
export class Consola {
|
|
17
|
+
options: ConsolaOptions
|
|
18
|
+
|
|
19
|
+
_lastLog: {
|
|
20
|
+
serialized?: string
|
|
21
|
+
object?: LogObject
|
|
22
|
+
count?: number
|
|
23
|
+
time?: Date
|
|
24
|
+
timeout?: ReturnType<typeof setTimeout>
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
_mockFn?: ConsolaOptions['mockFn']
|
|
28
|
+
|
|
29
|
+
constructor(options: Partial<ConsolaOptions> = {}) {
|
|
30
|
+
// Options
|
|
31
|
+
const types = options.types || LogTypes
|
|
32
|
+
this.options = defu(
|
|
33
|
+
<ConsolaOptions>{
|
|
34
|
+
...options,
|
|
35
|
+
defaults: { ...options.defaults },
|
|
36
|
+
level: _normalizeLogLevel(options.level, types),
|
|
37
|
+
reporters: [...(options.reporters || [])],
|
|
38
|
+
},
|
|
39
|
+
<Partial<ConsolaOptions>>{
|
|
40
|
+
types: LogTypes,
|
|
41
|
+
throttle: 1000,
|
|
42
|
+
throttleMin: 5,
|
|
43
|
+
formatOptions: {
|
|
44
|
+
date: true,
|
|
45
|
+
colors: false,
|
|
46
|
+
compact: true,
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
// Create logger functions for current instance
|
|
52
|
+
for (const type in types) {
|
|
53
|
+
const defaults: InputLogObject = {
|
|
54
|
+
type: type as LogType,
|
|
55
|
+
...this.options.defaults,
|
|
56
|
+
...types[type as LogType],
|
|
57
|
+
}
|
|
58
|
+
// @ts-expect-error
|
|
59
|
+
;(this as unknown as ConsolaInstance)[type as LogType] =
|
|
60
|
+
this._wrapLogFn(defaults)
|
|
61
|
+
// @ts-ignore
|
|
62
|
+
;(this as unknown as ConsolaInstance)[type].raw = this._wrapLogFn(
|
|
63
|
+
defaults,
|
|
64
|
+
true,
|
|
65
|
+
)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Use _mockFn if is set
|
|
69
|
+
if (this.options.mockFn) {
|
|
70
|
+
this.mockTypes()
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Track of last log
|
|
74
|
+
this._lastLog = {}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
get level() {
|
|
78
|
+
return this.options.level
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
set level(level) {
|
|
82
|
+
this.options.level = _normalizeLogLevel(
|
|
83
|
+
level,
|
|
84
|
+
this.options.types,
|
|
85
|
+
this.options.level,
|
|
86
|
+
)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
create(options: Partial<ConsolaOptions>): ConsolaInstance {
|
|
90
|
+
const instance = new Consola({
|
|
91
|
+
...this.options,
|
|
92
|
+
...options,
|
|
93
|
+
}) as ConsolaInstance
|
|
94
|
+
|
|
95
|
+
if (this._mockFn) {
|
|
96
|
+
instance.mockTypes(this._mockFn)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return instance
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
withDefaults(defaults: InputLogObject): ConsolaInstance {
|
|
103
|
+
return this.create({
|
|
104
|
+
...this.options,
|
|
105
|
+
defaults: {
|
|
106
|
+
...this.options.defaults,
|
|
107
|
+
...defaults,
|
|
108
|
+
},
|
|
109
|
+
})
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
withTag(tag: string): ConsolaInstance {
|
|
113
|
+
return this.withDefaults({
|
|
114
|
+
tag: this.options.defaults.tag
|
|
115
|
+
? `${this.options.defaults.tag}:${tag}`
|
|
116
|
+
: tag,
|
|
117
|
+
})
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
addReporter(reporter: ConsolaReporter) {
|
|
121
|
+
this.options.reporters.push(reporter)
|
|
122
|
+
return this
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
removeReporter(reporter: ConsolaReporter) {
|
|
126
|
+
if (reporter) {
|
|
127
|
+
const i = this.options.reporters.indexOf(reporter)
|
|
128
|
+
if (i >= 0) {
|
|
129
|
+
return this.options.reporters.splice(i, 1)
|
|
130
|
+
}
|
|
131
|
+
} else {
|
|
132
|
+
this.options.reporters.splice(0)
|
|
133
|
+
}
|
|
134
|
+
return this
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
setReporters(reporters: ConsolaReporter[]) {
|
|
138
|
+
this.options.reporters = Array.isArray(reporters) ? reporters : [reporters]
|
|
139
|
+
return this
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
wrapAll() {
|
|
143
|
+
this.wrapConsole()
|
|
144
|
+
this.wrapStd()
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
restoreAll() {
|
|
148
|
+
this.restoreConsole()
|
|
149
|
+
this.restoreStd()
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
wrapConsole() {
|
|
153
|
+
for (const type in this.options.types) {
|
|
154
|
+
// Backup original value
|
|
155
|
+
if (!(console as any)[`__${type}`]) {
|
|
156
|
+
// eslint-disable-line no-console
|
|
157
|
+
;(console as any)[`__${type}`] = (console as any)[type] // eslint-disable-line no-console
|
|
158
|
+
}
|
|
159
|
+
// Override
|
|
160
|
+
;(console as any)[type] = (this as unknown as ConsolaInstance)[
|
|
161
|
+
type as LogType
|
|
162
|
+
].raw // eslint-disable-line no-console
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
restoreConsole() {
|
|
167
|
+
for (const type in this.options.types) {
|
|
168
|
+
// Restore if backup is available
|
|
169
|
+
if ((console as any)[`__${type}`]) {
|
|
170
|
+
// eslint-disable-line no-console
|
|
171
|
+
;(console as any)[type] = (console as any)[`__${type}`] // eslint-disable-line no-console
|
|
172
|
+
delete (console as any)[`__${type}`] // eslint-disable-line no-console
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
wrapStd() {
|
|
178
|
+
this._wrapStream(this.options.stdout, 'log')
|
|
179
|
+
this._wrapStream(this.options.stderr, 'log')
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
_wrapStream(stream: NodeJS.WriteStream | undefined, type: LogType) {
|
|
183
|
+
if (!stream) {
|
|
184
|
+
return
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Backup original value
|
|
188
|
+
if (!(stream as any).__write) {
|
|
189
|
+
;(stream as any).__write = stream.write
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Override
|
|
193
|
+
;(stream as any).write = (data: any) => {
|
|
194
|
+
;(this as unknown as ConsolaInstance)[type].raw(String(data).trim())
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
restoreStd() {
|
|
199
|
+
this._restoreStream(this.options.stdout)
|
|
200
|
+
this._restoreStream(this.options.stderr)
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
_restoreStream(stream?: NodeJS.WriteStream) {
|
|
204
|
+
if (!stream) {
|
|
205
|
+
return
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if ((stream as any).__write) {
|
|
209
|
+
stream.write = (stream as any).__write
|
|
210
|
+
delete (stream as any).__write
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
pauseLogs() {
|
|
215
|
+
paused = true
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
resumeLogs() {
|
|
219
|
+
paused = false
|
|
220
|
+
|
|
221
|
+
// Process queue
|
|
222
|
+
const _queue = queue.splice(0)
|
|
223
|
+
for (const item of _queue) {
|
|
224
|
+
item[0]._logFn(item[1], item[2])
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
mockTypes(mockFn?: ConsolaOptions['mockFn']) {
|
|
229
|
+
const _mockFn = mockFn || this.options.mockFn
|
|
230
|
+
|
|
231
|
+
this._mockFn = _mockFn
|
|
232
|
+
|
|
233
|
+
if (typeof _mockFn !== 'function') {
|
|
234
|
+
return
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
for (const type in this.options.types) {
|
|
238
|
+
// @ts-expect-error
|
|
239
|
+
;(this as unknown as ConsolaInstance)[type as LogType] =
|
|
240
|
+
_mockFn(type as LogType, this.options.types[type as LogType]) ||
|
|
241
|
+
(this as unknown as ConsolaInstance)[type as LogType]
|
|
242
|
+
;(this as unknown as ConsolaInstance)[type as LogType].raw = (
|
|
243
|
+
this as unknown as ConsolaInstance
|
|
244
|
+
)[type as LogType]
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
_wrapLogFn(defaults: InputLogObject, isRaw?: boolean) {
|
|
249
|
+
return (...args: any[]) => {
|
|
250
|
+
if (paused) {
|
|
251
|
+
queue.push([this, defaults, args, isRaw])
|
|
252
|
+
return
|
|
253
|
+
}
|
|
254
|
+
return this._logFn(defaults, args, isRaw)
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
_logFn(defaults: InputLogObject, args: any[], isRaw?: boolean) {
|
|
259
|
+
if (((defaults.level as number) || 0) > this.level) {
|
|
260
|
+
return false
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// Construct a new log object
|
|
264
|
+
const logObj: Partial<LogObject> = {
|
|
265
|
+
date: new Date(),
|
|
266
|
+
args: [],
|
|
267
|
+
...defaults,
|
|
268
|
+
level: _normalizeLogLevel(defaults.level, this.options.types),
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// Consume arguments
|
|
272
|
+
if (!isRaw && args.length === 1 && isLogObj(args[0])) {
|
|
273
|
+
Object.assign(logObj, args[0])
|
|
274
|
+
} else {
|
|
275
|
+
logObj.args = [...args]
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// Aliases
|
|
279
|
+
if (logObj.message) {
|
|
280
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
281
|
+
logObj.args!.unshift(logObj.message)
|
|
282
|
+
delete logObj.message
|
|
283
|
+
}
|
|
284
|
+
if (logObj.additional) {
|
|
285
|
+
if (!Array.isArray(logObj.additional)) {
|
|
286
|
+
logObj.additional = logObj.additional.split('\n')
|
|
287
|
+
}
|
|
288
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
289
|
+
logObj.args!.push(`\n${logObj.additional.join('\n')}`)
|
|
290
|
+
delete logObj.additional
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// Normalize type to lowercase
|
|
294
|
+
logObj.type = (
|
|
295
|
+
typeof logObj.type === 'string' ? logObj.type.toLowerCase() : 'log'
|
|
296
|
+
) as LogType
|
|
297
|
+
logObj.tag = typeof logObj.tag === 'string' ? logObj.tag : ''
|
|
298
|
+
|
|
299
|
+
// Resolve log
|
|
300
|
+
/**
|
|
301
|
+
* @param newLog false if the throttle expired and
|
|
302
|
+
* we don't want to log a duplicate
|
|
303
|
+
*/
|
|
304
|
+
const resolveLog = (newLog = false) => {
|
|
305
|
+
const repeated = (this._lastLog.count || 0) - this.options.throttleMin
|
|
306
|
+
if (this._lastLog.object && repeated > 0) {
|
|
307
|
+
const args = [...this._lastLog.object.args]
|
|
308
|
+
if (repeated > 1) {
|
|
309
|
+
args.push(`(repeated ${repeated} times)`)
|
|
310
|
+
}
|
|
311
|
+
this._log({ ...this._lastLog.object, args })
|
|
312
|
+
this._lastLog.count = 1
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// Log
|
|
316
|
+
if (newLog) {
|
|
317
|
+
this._lastLog.object = logObj as LogObject
|
|
318
|
+
this._log(logObj as LogObject)
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// Throttle
|
|
323
|
+
clearTimeout(this._lastLog.timeout)
|
|
324
|
+
const diffTime =
|
|
325
|
+
this._lastLog.time && logObj.date
|
|
326
|
+
? logObj.date.getTime() - this._lastLog.time.getTime()
|
|
327
|
+
: 0
|
|
328
|
+
this._lastLog.time = logObj.date
|
|
329
|
+
if (diffTime < this.options.throttle) {
|
|
330
|
+
try {
|
|
331
|
+
const serializedLog = JSON.stringify([
|
|
332
|
+
logObj.type,
|
|
333
|
+
logObj.tag,
|
|
334
|
+
logObj.args,
|
|
335
|
+
])
|
|
336
|
+
const isSameLog = this._lastLog.serialized === serializedLog
|
|
337
|
+
this._lastLog.serialized = serializedLog
|
|
338
|
+
if (isSameLog) {
|
|
339
|
+
this._lastLog.count = (this._lastLog.count || 0) + 1
|
|
340
|
+
if (this._lastLog.count > this.options.throttleMin) {
|
|
341
|
+
// Auto-resolve when throttle is timed out
|
|
342
|
+
this._lastLog.timeout = setTimeout(
|
|
343
|
+
resolveLog,
|
|
344
|
+
this.options.throttle,
|
|
345
|
+
)
|
|
346
|
+
return // SPAM!
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
} catch {
|
|
350
|
+
// Circular References
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
resolveLog(true)
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
_log(logObj: LogObject) {
|
|
358
|
+
for (const reporter of this.options.reporters) {
|
|
359
|
+
reporter.log(logObj, {
|
|
360
|
+
options: this.options,
|
|
361
|
+
})
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
function _normalizeLogLevel(
|
|
367
|
+
input: LogLevel | LogType | undefined,
|
|
368
|
+
types: any = {},
|
|
369
|
+
defaultLevel = 3,
|
|
370
|
+
) {
|
|
371
|
+
if (input === undefined) {
|
|
372
|
+
return defaultLevel
|
|
373
|
+
}
|
|
374
|
+
if (typeof input === 'number') {
|
|
375
|
+
return input
|
|
376
|
+
}
|
|
377
|
+
if (types[input] && types[input].level !== undefined) {
|
|
378
|
+
return types[input].level
|
|
379
|
+
}
|
|
380
|
+
return defaultLevel
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
export interface LogFn {
|
|
384
|
+
(message: InputLogObject | any, ...args: any[]): void
|
|
385
|
+
raw: (...args: any[]) => void
|
|
386
|
+
}
|
|
387
|
+
export type ConsolaInstance = Consola & Record<LogType, LogFn>
|
|
388
|
+
|
|
389
|
+
// Legacy support
|
|
390
|
+
// @ts-expect-error
|
|
391
|
+
Consola.prototype.add = Consola.prototype.addReporter
|
|
392
|
+
// @ts-expect-error
|
|
393
|
+
Consola.prototype.remove = Consola.prototype.removeReporter
|
|
394
|
+
// @ts-expect-error
|
|
395
|
+
Consola.prototype.clear = Consola.prototype.removeReporter
|
|
396
|
+
// @ts-expect-error
|
|
397
|
+
Consola.prototype.withScope = Consola.prototype.withTag
|
|
398
|
+
// @ts-expect-error
|
|
399
|
+
Consola.prototype.mock = Consola.prototype.mockTypes
|
|
400
|
+
// @ts-expect-error
|
|
401
|
+
Consola.prototype.pause = Consola.prototype.pauseLogs
|
|
402
|
+
// @ts-expect-error
|
|
403
|
+
Consola.prototype.resume = Consola.prototype.resumeLogs
|
|
404
|
+
|
|
405
|
+
export function createConsola(
|
|
406
|
+
options: Partial<ConsolaOptions> = {},
|
|
407
|
+
): ConsolaInstance {
|
|
408
|
+
return new Consola(options) as ConsolaInstance
|
|
409
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import type { LogObject } from './types'
|
|
2
|
+
|
|
3
|
+
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
4
|
+
export type LogLevel = 0 | 1 | 2 | 3 | 4 | 5 | (number & {})
|
|
5
|
+
|
|
6
|
+
export const LogLevels: Record<LogType, number> = {
|
|
7
|
+
silent: Number.NEGATIVE_INFINITY,
|
|
8
|
+
|
|
9
|
+
fatal: 0,
|
|
10
|
+
error: 0,
|
|
11
|
+
|
|
12
|
+
warn: 1,
|
|
13
|
+
|
|
14
|
+
log: 2,
|
|
15
|
+
info: 3,
|
|
16
|
+
|
|
17
|
+
success: 3,
|
|
18
|
+
fail: 3,
|
|
19
|
+
ready: 3,
|
|
20
|
+
start: 3,
|
|
21
|
+
box: 3,
|
|
22
|
+
|
|
23
|
+
debug: 4,
|
|
24
|
+
|
|
25
|
+
trace: 5,
|
|
26
|
+
|
|
27
|
+
verbose: Number.POSITIVE_INFINITY,
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export type LogType =
|
|
31
|
+
// 0
|
|
32
|
+
| 'silent'
|
|
33
|
+
| 'fatal'
|
|
34
|
+
| 'error'
|
|
35
|
+
// 1
|
|
36
|
+
| 'warn'
|
|
37
|
+
// 2
|
|
38
|
+
| 'log'
|
|
39
|
+
// 3
|
|
40
|
+
| 'info'
|
|
41
|
+
| 'success'
|
|
42
|
+
| 'fail'
|
|
43
|
+
| 'ready'
|
|
44
|
+
| 'start'
|
|
45
|
+
| 'box'
|
|
46
|
+
// Verbose
|
|
47
|
+
| 'debug'
|
|
48
|
+
| 'trace'
|
|
49
|
+
| 'verbose'
|
|
50
|
+
|
|
51
|
+
export const LogTypes: Record<LogType, Partial<LogObject>> = {
|
|
52
|
+
// Silent
|
|
53
|
+
silent: {
|
|
54
|
+
level: -1,
|
|
55
|
+
},
|
|
56
|
+
|
|
57
|
+
// Level 0
|
|
58
|
+
fatal: {
|
|
59
|
+
level: LogLevels.fatal,
|
|
60
|
+
},
|
|
61
|
+
error: {
|
|
62
|
+
level: LogLevels.error,
|
|
63
|
+
},
|
|
64
|
+
|
|
65
|
+
// Level 1
|
|
66
|
+
warn: {
|
|
67
|
+
level: LogLevels.warn,
|
|
68
|
+
},
|
|
69
|
+
|
|
70
|
+
// Level 2
|
|
71
|
+
log: {
|
|
72
|
+
level: LogLevels.log,
|
|
73
|
+
},
|
|
74
|
+
|
|
75
|
+
// Level 3
|
|
76
|
+
info: {
|
|
77
|
+
level: LogLevels.info,
|
|
78
|
+
},
|
|
79
|
+
success: {
|
|
80
|
+
level: LogLevels.success,
|
|
81
|
+
},
|
|
82
|
+
fail: {
|
|
83
|
+
level: LogLevels.fail,
|
|
84
|
+
},
|
|
85
|
+
ready: {
|
|
86
|
+
level: LogLevels.info,
|
|
87
|
+
},
|
|
88
|
+
start: {
|
|
89
|
+
level: LogLevels.info,
|
|
90
|
+
},
|
|
91
|
+
box: {
|
|
92
|
+
level: LogLevels.info,
|
|
93
|
+
},
|
|
94
|
+
|
|
95
|
+
// Level 4
|
|
96
|
+
debug: {
|
|
97
|
+
level: LogLevels.debug,
|
|
98
|
+
},
|
|
99
|
+
|
|
100
|
+
// Level 5
|
|
101
|
+
trace: {
|
|
102
|
+
level: LogLevels.trace,
|
|
103
|
+
},
|
|
104
|
+
|
|
105
|
+
// Verbose
|
|
106
|
+
verbose: {
|
|
107
|
+
level: LogLevels.verbose,
|
|
108
|
+
},
|
|
109
|
+
}
|
package/consola/core.ts
ADDED
package/consola/index.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { isCI, isDebug, isTest } from 'std-env'
|
|
2
|
+
import type { ConsolaInstance } from './consola'
|
|
3
|
+
import type { LogLevel } from './constants'
|
|
4
|
+
import type { ConsolaOptions } from './types'
|
|
5
|
+
|
|
6
|
+
import { createConsola as _createConsola } from './consola'
|
|
7
|
+
import { LogLevels } from './constants'
|
|
8
|
+
import { BasicReporter } from './reporters/basic'
|
|
9
|
+
import { FancyReporter } from './reporters/fancy'
|
|
10
|
+
|
|
11
|
+
export * from './shared'
|
|
12
|
+
|
|
13
|
+
export function createConsola(
|
|
14
|
+
options: Partial<ConsolaOptions & { fancy: boolean }> = {},
|
|
15
|
+
): ConsolaInstance {
|
|
16
|
+
// Log level
|
|
17
|
+
let level = _getDefaultLogLevel()
|
|
18
|
+
if (process.env.CONSOLA_LEVEL) {
|
|
19
|
+
level = Number.parseInt(process.env.CONSOLA_LEVEL) ?? level
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Create new consola instance
|
|
23
|
+
const consola = _createConsola({
|
|
24
|
+
level: level as LogLevel,
|
|
25
|
+
defaults: { level },
|
|
26
|
+
stdout: process.stdout,
|
|
27
|
+
stderr: process.stderr,
|
|
28
|
+
|
|
29
|
+
reporters: options.reporters || [
|
|
30
|
+
options.fancy ?? !(isCI || isTest)
|
|
31
|
+
? new FancyReporter()
|
|
32
|
+
: new BasicReporter(),
|
|
33
|
+
],
|
|
34
|
+
...options,
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
return consola
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function _getDefaultLogLevel() {
|
|
41
|
+
if (isDebug) {
|
|
42
|
+
return LogLevels.debug
|
|
43
|
+
}
|
|
44
|
+
if (isTest) {
|
|
45
|
+
return LogLevels.warn
|
|
46
|
+
}
|
|
47
|
+
return LogLevels.info
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export const consola = createConsola()
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { formatWithOptions } from 'node:util'
|
|
2
|
+
import type {
|
|
3
|
+
ConsolaOptions,
|
|
4
|
+
ConsolaReporter,
|
|
5
|
+
FormatOptions,
|
|
6
|
+
LogObject,
|
|
7
|
+
} from '../types'
|
|
8
|
+
|
|
9
|
+
import { parseStack } from '../utils/error'
|
|
10
|
+
import { writeStream } from '../utils/stream'
|
|
11
|
+
|
|
12
|
+
const bracket = (x: string) => (x ? `[${x}]` : '')
|
|
13
|
+
|
|
14
|
+
export class BasicReporter implements ConsolaReporter {
|
|
15
|
+
formatStack(stack: string, opts: FormatOptions) {
|
|
16
|
+
return ` ${parseStack(stack).join('\n ')}`
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
formatArgs(args: any[], opts: FormatOptions) {
|
|
20
|
+
const _args = args.map((arg) => {
|
|
21
|
+
if (arg && typeof arg.stack === 'string') {
|
|
22
|
+
return `${arg.message}\n${this.formatStack(arg.stack, opts)}`
|
|
23
|
+
}
|
|
24
|
+
return arg
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
// Only supported with Node >= 10
|
|
28
|
+
// https://nodejs.org/api/util.html#util_util_inspect_object_options
|
|
29
|
+
return formatWithOptions(opts, ..._args)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
formatDate(date: Date, opts: FormatOptions) {
|
|
33
|
+
return opts.date ? date.toLocaleTimeString() : ''
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
filterAndJoin(arr: any[]) {
|
|
37
|
+
return arr.filter(Boolean).join(' ')
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
formatLogObj(logObj: LogObject, opts: FormatOptions) {
|
|
41
|
+
const message = this.formatArgs(logObj.args, opts)
|
|
42
|
+
|
|
43
|
+
if (logObj.type === 'box') {
|
|
44
|
+
return `\n${[
|
|
45
|
+
bracket(logObj.tag),
|
|
46
|
+
logObj.title && logObj.title,
|
|
47
|
+
...message.split('\n'),
|
|
48
|
+
]
|
|
49
|
+
.filter(Boolean)
|
|
50
|
+
.map((l) => ` > ${l}`)
|
|
51
|
+
.join('\n')}\n`
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return this.filterAndJoin([
|
|
55
|
+
bracket(logObj.type),
|
|
56
|
+
bracket(logObj.tag),
|
|
57
|
+
message,
|
|
58
|
+
])
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
log(logObj: LogObject, ctx: { options: ConsolaOptions }) {
|
|
62
|
+
const line = this.formatLogObj(logObj, {
|
|
63
|
+
columns: (ctx.options.stdout as any).columns || 0,
|
|
64
|
+
...ctx.options.formatOptions,
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
return writeStream(
|
|
68
|
+
`${line}\n`,
|
|
69
|
+
logObj.level < 2
|
|
70
|
+
? ctx.options.stderr || process.stderr
|
|
71
|
+
: ctx.options.stdout || process.stdout,
|
|
72
|
+
)
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type { LogObject } from '../types'
|
|
2
|
+
|
|
3
|
+
export class BrowserReporter {
|
|
4
|
+
options: any
|
|
5
|
+
defaultColor: string
|
|
6
|
+
levelColorMap: Record<number, string>
|
|
7
|
+
typeColorMap: Record<string, string>
|
|
8
|
+
|
|
9
|
+
constructor(options: any) {
|
|
10
|
+
this.options = { ...options }
|
|
11
|
+
|
|
12
|
+
this.defaultColor = '#7f8c8d' // Gray
|
|
13
|
+
this.levelColorMap = {
|
|
14
|
+
0: '#c0392b', // Red
|
|
15
|
+
1: '#f39c12', // Yellow
|
|
16
|
+
3: '#00BCD4', // Cyan
|
|
17
|
+
}
|
|
18
|
+
this.typeColorMap = {
|
|
19
|
+
success: '#2ecc71', // Green
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
_getLogFn(level: number) {
|
|
24
|
+
if (level < 1) {
|
|
25
|
+
return (console as any).__error || console.error
|
|
26
|
+
}
|
|
27
|
+
if (level === 1) {
|
|
28
|
+
return (console as any).__warn || console.warn
|
|
29
|
+
}
|
|
30
|
+
return (console as any).__log || console.log
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
log(logObj: LogObject) {
|
|
34
|
+
const consoleLogFn = this._getLogFn(logObj.level)
|
|
35
|
+
|
|
36
|
+
// Type
|
|
37
|
+
const type = logObj.type === 'log' ? '' : logObj.type
|
|
38
|
+
|
|
39
|
+
// Tag
|
|
40
|
+
const tag = logObj.tag || ''
|
|
41
|
+
|
|
42
|
+
// Styles
|
|
43
|
+
const color =
|
|
44
|
+
this.typeColorMap[logObj.type] ||
|
|
45
|
+
this.levelColorMap[logObj.level] ||
|
|
46
|
+
this.defaultColor
|
|
47
|
+
const style = `
|
|
48
|
+
background: ${color};
|
|
49
|
+
border-radius: 0.5em;
|
|
50
|
+
color: white;
|
|
51
|
+
font-weight: bold;
|
|
52
|
+
padding: 2px 0.5em;
|
|
53
|
+
`
|
|
54
|
+
|
|
55
|
+
const badge = `%c${[tag, type].filter(Boolean).join(':')}`
|
|
56
|
+
|
|
57
|
+
// Log to the console
|
|
58
|
+
if (typeof logObj.args[0] === 'string') {
|
|
59
|
+
consoleLogFn(
|
|
60
|
+
`${badge}%c ${logObj.args[0]}`,
|
|
61
|
+
style,
|
|
62
|
+
// Empty string as style resets to default console style
|
|
63
|
+
'',
|
|
64
|
+
...logObj.args.slice(1),
|
|
65
|
+
)
|
|
66
|
+
} else {
|
|
67
|
+
consoleLogFn(badge, style, ...logObj.args)
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|