tangled
alpha
login
or
join now
graham.systems
/
statusphere-react
forked from
samuel.fm/statusphere-react
0
fork
atom
the statusphere demo reworked into a vite/react app in a monorepo
0
fork
atom
overview
issues
pulls
pipelines
Remove request-logger middleware
Paul Frazee
2 years ago
b44ed439
c9ca60d0
+1
-110
3 changed files
expand all
collapse all
unified
split
package.json
src
middleware
requestLogger.ts
server.ts
-1
package.json
···
28
28
"kysely": "^0.27.4",
29
29
"multiformats": "^9.9.0",
30
30
"pino": "^9.3.2",
31
31
-
"pino-http": "^10.0.0",
32
31
"uhtml": "^4.5.9"
33
32
},
34
33
"devDependencies": {
-100
src/middleware/requestLogger.ts
···
1
1
-
import { randomUUID } from 'node:crypto'
2
2
-
import type { IncomingMessage, ServerResponse } from 'node:http'
3
3
-
import type { Request, RequestHandler, Response } from 'express'
4
4
-
import type { LevelWithSilent } from 'pino'
5
5
-
import { type CustomAttributeKeys, type Options, pinoHttp } from 'pino-http'
6
6
-
7
7
-
import { env } from '#/env'
8
8
-
9
9
-
enum LogLevel {
10
10
-
Fatal = 'fatal',
11
11
-
Error = 'error',
12
12
-
Warn = 'warn',
13
13
-
Info = 'info',
14
14
-
Debug = 'debug',
15
15
-
Trace = 'trace',
16
16
-
Silent = 'silent',
17
17
-
}
18
18
-
19
19
-
type PinoCustomProps = {
20
20
-
request: Request
21
21
-
response: Response
22
22
-
error: Error
23
23
-
responseBody: unknown
24
24
-
}
25
25
-
26
26
-
const requestLogger = (options?: Options): RequestHandler[] => {
27
27
-
const pinoOptions: Options = {
28
28
-
enabled: env.isProduction,
29
29
-
customProps: customProps as unknown as Options['customProps'],
30
30
-
redact: [],
31
31
-
genReqId,
32
32
-
customLogLevel,
33
33
-
customSuccessMessage,
34
34
-
customReceivedMessage: (req) => `request received: ${req.method}`,
35
35
-
customErrorMessage: (_req, res) =>
36
36
-
`request errored with status code: ${res.statusCode}`,
37
37
-
customAttributeKeys,
38
38
-
...options,
39
39
-
}
40
40
-
return [responseBodyMiddleware, pinoHttp(pinoOptions)]
41
41
-
}
42
42
-
43
43
-
const customAttributeKeys: CustomAttributeKeys = {
44
44
-
req: 'request',
45
45
-
res: 'response',
46
46
-
err: 'error',
47
47
-
responseTime: 'timeTaken',
48
48
-
}
49
49
-
50
50
-
const customProps = (req: Request, res: Response): PinoCustomProps => ({
51
51
-
request: req,
52
52
-
response: res,
53
53
-
error: res.locals.err,
54
54
-
responseBody: res.locals.responseBody,
55
55
-
})
56
56
-
57
57
-
const responseBodyMiddleware: RequestHandler = (_req, res, next) => {
58
58
-
const isNotProduction = !env.isProduction
59
59
-
if (isNotProduction) {
60
60
-
const originalSend = res.send
61
61
-
res.send = (content) => {
62
62
-
res.locals.responseBody = content
63
63
-
res.send = originalSend
64
64
-
return originalSend.call(res, content)
65
65
-
}
66
66
-
}
67
67
-
next()
68
68
-
}
69
69
-
70
70
-
const customLogLevel = (
71
71
-
_req: IncomingMessage,
72
72
-
res: ServerResponse<IncomingMessage>,
73
73
-
err?: Error
74
74
-
): LevelWithSilent => {
75
75
-
if (err || res.statusCode >= 500) return LogLevel.Error
76
76
-
if (res.statusCode >= 400) return LogLevel.Warn
77
77
-
if (res.statusCode >= 300) return LogLevel.Silent
78
78
-
return LogLevel.Info
79
79
-
}
80
80
-
81
81
-
const customSuccessMessage = (
82
82
-
req: IncomingMessage,
83
83
-
res: ServerResponse<IncomingMessage>
84
84
-
) => {
85
85
-
if (res.statusCode === 404) return 'Not found'
86
86
-
return `${req.method} completed`
87
87
-
}
88
88
-
89
89
-
const genReqId = (
90
90
-
req: IncomingMessage,
91
91
-
res: ServerResponse<IncomingMessage>
92
92
-
) => {
93
93
-
const existingID = req.id ?? req.headers['x-request-id']
94
94
-
if (existingID) return existingID
95
95
-
const id = randomUUID()
96
96
-
res.setHeader('X-Request-Id', id)
97
97
-
return id
98
98
-
}
99
99
-
100
100
-
export default requestLogger()
+1
-9
src/server.ts
···
1
1
import events from 'node:events'
2
2
import type http from 'node:http'
3
3
-
import express, { type Express, type ErrorRequestHandler } from 'express'
3
3
+
import express, { type Express } from 'express'
4
4
import { pino } from 'pino'
5
5
6
6
import { createDb, migrateToLatest } from '#/db'
7
7
import { env } from '#/env'
8
8
import { Ingester } from '#/firehose/ingester'
9
9
-
import requestLogger from '#/middleware/requestLogger'
10
9
import { createRouter } from '#/routes'
11
10
import { createClient } from '#/auth/client'
12
11
import { createResolver } from '#/ident/resolver'
···
46
45
app.use(express.json())
47
46
app.use(express.urlencoded({ extended: true }))
48
47
49
49
-
// Request logging
50
50
-
app.use(requestLogger)
51
51
-
52
48
// Routes
53
49
const router = createRouter(ctx)
54
50
app.use(router)
55
51
56
52
// Error handlers
57
53
app.use((_req, res) => res.sendStatus(404))
58
58
-
app.use(((err, _req, res, next) => {
59
59
-
res.locals.err = err
60
60
-
next(err)
61
61
-
}) as ErrorRequestHandler)
62
54
63
55
const server = app.listen(env.PORT)
64
56
await events.once(server, 'listening')