1 | "use strict"
|
2 | const { v4: makeUuid } = require("uuid")
|
3 | const reqIdHeader = "X-Request-Id"
|
4 |
|
5 | module.exports = function createCtxLogger(logger) {
|
6 | const errorHandler = initErrorHandler()
|
7 | const logMiddleware = initLogMiddleware(logger, errorHandler)
|
8 |
|
9 | return logMiddleware
|
10 | }
|
11 |
|
12 | function initLogMiddleware(logger, errorHandler) {
|
13 | return async (ctx, next) => {
|
14 | const reqId = ctx.reqId = ctx.request.get(reqIdHeader) || makeUuid()
|
15 | const log = logger.child(reqId)
|
16 | const requestTimer = log.timer()
|
17 |
|
18 | ctx.log = log
|
19 | ctx.requestTimer = requestTimer
|
20 |
|
21 | try {
|
22 | await next()
|
23 | } catch (e) {
|
24 | await errorHandler(ctx, e)
|
25 | } finally {
|
26 | ctx.response.set("X-Server-Request-Id", ctx.reqId)
|
27 | ctx.requestTimer.end("%s %s > %d", ctx.request.method, ctx.request.url, ctx.response.status)
|
28 | }
|
29 | }
|
30 | }
|
31 |
|
32 | function initErrorHandler() {
|
33 | const handler = async (ctx, e) => {
|
34 | if (e instanceof Error === false) {
|
35 | e = new Error(e)
|
36 | }
|
37 |
|
38 | if (!e.status) e.status = 500
|
39 | if (!e.jsonBody) e.jsonBody = {}
|
40 |
|
41 | ctx.type = "json"
|
42 | ctx.status = e.status
|
43 |
|
44 | ctx.log.error("%s %s < params: %O, body: %O", ctx.request.method, ctx.request.url, ctx.params, ctx.request.body)
|
45 |
|
46 | if (!e.expose) {
|
47 | const requestInformation = {
|
48 | method: ctx.method,
|
49 | url: ctx.url,
|
50 | userAgent: ctx.request.get("user-agent"),
|
51 | referrer: ctx.request.get("referrer"),
|
52 | statusCode: ctx.status,
|
53 | remoteAddress: ctx.ip,
|
54 | requestId: ctx.request.get("x-request-id") }
|
55 | ctx.log.error(e, requestInformation)
|
56 | }
|
57 |
|
58 | e.jsonBody.status = e.status
|
59 | e.jsonBody.message = e.expose ? e.message : "Error"
|
60 |
|
61 | ctx.body = {
|
62 | error: e.jsonBody,
|
63 | reqId: ctx.reqId
|
64 | }
|
65 | }
|
66 | return handler
|
67 | } |
\ | No newline at end of file |