-
-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathindex.ts
More file actions
108 lines (98 loc) · 3.08 KB
/
index.ts
File metadata and controls
108 lines (98 loc) · 3.08 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
import { METHODS, type IncomingMessage as Request, type ServerResponse as Response } from 'node:http'
import { bold, cyan, magenta, red } from 'colorette'
import dayjs from 'dayjs'
import statusEmoji from 'http-status-emojis'
import { FileLogger } from './filelogger.js'
export enum LogLevel {
error = 'error',
warn = 'warn',
trace = 'trace',
info = 'info',
log = 'log'
}
export type LoggerOptions = Partial<{
methods: string[]
output: {
color: boolean
filename?: string
callback: (string: string) => void
level?: LogLevel
}
timestamp: boolean | { format?: string }
emoji: boolean
ip: boolean
ignore: string[]
}>
const compileArgs = (
args: (string | number)[],
req: Request & Partial<{ originalUrl: string; ip: string }>,
res: Response,
options: LoggerOptions = {},
status?: string,
msg?: string
) => {
const { method } = req
const { statusCode } = res
const url = req.originalUrl || req.url
const methods = options.methods ?? METHODS
const timestamp = options.timestamp ?? false
const emojiEnabled = options.emoji
const level = options.output?.level ? options.output.level : null
if (level) args.push(`[${level.toUpperCase()}]`)
if (methods.includes(method) && timestamp) {
args.push(
`${dayjs()
.format(typeof timestamp !== 'boolean' && timestamp.format ? timestamp.format : 'HH:mm:ss')
.toString()} - `
)
}
if (options.ip) args.push(req.ip)
if (emojiEnabled) args.push(statusEmoji[statusCode])
args.push(method)
args.push(status || res.statusCode)
args.push(msg || res.statusMessage)
args.push(url)
}
export const logger = (options: LoggerOptions = {}) => {
const methods = options.methods ?? METHODS
const ignore = options.ignore ?? []
const output = options.output ?? { callback: console.log, color: true, level: null }
let filelogger = null
if (options.output?.filename) {
filelogger = new FileLogger(options.output.filename)
}
return (req: Request, res: Response, next?: () => void) => {
res.on('finish', () => {
const args: (string | number)[] = []
if (methods.includes(req.method) && !ignore.some((url) => req.url.startsWith(url))) {
const s = res.statusCode.toString()
let stringToLog = ''
if (!output.color) {
compileArgs(args, req, res, options)
const m = args.join(' ')
stringToLog = m
} else {
switch (s[0]) {
case '2':
compileArgs(args, req, res, options, cyan(bold(s)), cyan(res.statusMessage))
stringToLog = args.join(' ')
break
case '4':
compileArgs(args, req, res, options, red(bold(s)), red(res.statusMessage))
stringToLog = args.join(' ')
break
case '5':
compileArgs(args, req, res, options, magenta(bold(s)), magenta(res.statusMessage))
stringToLog = args.join(' ')
break
}
}
output.callback(stringToLog)
if (filelogger) {
filelogger.toFile(stringToLog)
}
}
})
next?.()
}
}