
При развертывании API в рабочей среде очень важно иметь возможность регистрировать все входящие запросы и ответы с вашего сервера для таких целей, как отладка, аудит и оптимизация. Для NodeJS существует ряд популярных библиотек ведения журналов, которые отлично справляются с настройкой базовой конфигурации. Однако ни один из них не поставляется с вводом запроса по умолчанию и ведением журнала тела ответа. Вот краткое руководство о том, как мы можем добиться этого с помощью morgan.
Чтобы регистрировать дополнительную информацию помимо стандартных конфигураций morgan, нам потребуется создать собственные токены. Начнем с пользовательского промежуточного ПО, написанного для расширения morgan.
// /middlewares/morgan.ts
import { Request, Response } from "express";
import morgan from "morgan";
// in my app, I extend express's Request interface to store a
// `requester` prop. this holds the decoded jwt token data
morgan.token("requester", function getRequester(req: Request): string {
return JSON.stringify(req.requester);
});
morgan.token("input", function getInput(req: Request): string {
let input: Record<string, any> = {};
if (req.method === "GET") {
input = req.query;
} else {
input = req.body;
}
// mask any input that should be secret
input = { ...input };
if (input.password) {
input.password = "*";
}
return JSON.stringify(input);
});
morgan.token("response-body", (req: Request, res: Response): string => {
const body = { ...JSON.parse(res.responseBody) };
// mask any input that should be secret
if (body?.data?.accessToken) {
body.data.accessToken = "*";
}
if (body?.data?.refreshToken) {
body.data.refreshToken = "*";
}
return JSON.stringify(body);
});
export { morgan };
Теперь мы можем импортировать это в index.ts и определить собственный формат с нашими вновь определенными токенами, которые должен использовать Морган.
// index.ts
import express, { Express, Request, Response } from "express";
import { morgan } from "./middlewares/morgan";
const PORT = process.env.PORT || 3000;
const app: Express = express();
// override send to store response body for morgan token to retrieve
const originalSend = app.response.send;
app.response.send = function sendOverride(body) {
this.responseBody = body;
return originalSend.call(this, body);
};
app.use(express.json());
app.use(cookieParser()); // I use this to retrieve jwt from cookies
app.use(
morgan(
':requester :remote-addr [:date[clf]] ":method :url HTTP/:http-version" Input :input Response :response-body'
)
);
... // other middleware, route handlers, server setup
Наконец, нам также нужно будет расширить типы запросов и ответов от экспресс, чтобы избежать ошибок во время сборки. Обязательно включите этот файл в свой tsconfig.json в опции include или files.
// custom.d.ts
declare namespace Express {
export interface Request {
requester: import("./models/Policy").Requester;
}
export interface Response {
responseBody: any;
}
}
Теперь у нас есть все объекты ввода запроса и тела ответа, хранящиеся в каждом журнале запросов!