2023-12-27 05:56:13 +00:00
|
|
|
import { getLoggerFilePath } from './config';
|
2023-12-30 15:34:40 +00:00
|
|
|
import { LoggerOptions, createLogger } from './logger';
|
2023-12-27 05:56:13 +00:00
|
|
|
import { pick } from 'lodash';
|
|
|
|
const defaultRequestWhitelist = [
|
|
|
|
'action',
|
|
|
|
'header.x-role',
|
|
|
|
'header.x-hostname',
|
|
|
|
'header.x-timezone',
|
|
|
|
'header.x-locale',
|
2024-04-08 11:43:00 +00:00
|
|
|
'header.x-authenticator',
|
|
|
|
'header.x-data-source',
|
2023-12-27 05:56:13 +00:00
|
|
|
'referer',
|
|
|
|
];
|
|
|
|
const defaultResponseWhitelist = ['status'];
|
|
|
|
|
2023-12-30 15:34:40 +00:00
|
|
|
export interface RequestLoggerOptions extends LoggerOptions {
|
|
|
|
skip?: (ctx?: any) => Promise<boolean>;
|
|
|
|
requestWhitelist?: string[];
|
|
|
|
responseWhitelist?: string[];
|
|
|
|
}
|
|
|
|
|
|
|
|
export const requestLogger = (appName: string, options?: RequestLoggerOptions) => {
|
2023-12-27 05:56:13 +00:00
|
|
|
const requestLogger = createLogger({
|
|
|
|
dirname: getLoggerFilePath(appName),
|
|
|
|
filename: 'request',
|
2023-12-30 15:34:40 +00:00
|
|
|
...(options || {}),
|
2023-12-27 05:56:13 +00:00
|
|
|
});
|
|
|
|
return async (ctx, next) => {
|
|
|
|
const reqId = ctx.reqId;
|
|
|
|
const path = /^\/api\/(.+):(.+)/.exec(ctx.path);
|
|
|
|
const contextLogger = ctx.app.log.child({ reqId, module: path?.[1], submodule: path?.[2] });
|
|
|
|
// ctx.reqId = reqId;
|
|
|
|
ctx.logger = ctx.log = contextLogger;
|
|
|
|
const startTime = Date.now();
|
|
|
|
const requestInfo = {
|
|
|
|
method: ctx.method,
|
|
|
|
path: ctx.url,
|
|
|
|
};
|
|
|
|
requestLogger.info({
|
2024-01-02 01:35:46 +00:00
|
|
|
message: `request ${ctx.method} ${ctx.url}`,
|
2023-12-27 05:56:13 +00:00
|
|
|
...requestInfo,
|
2023-12-30 15:34:40 +00:00
|
|
|
req: pick(ctx.request.toJSON(), options?.requestWhitelist || defaultRequestWhitelist),
|
2023-12-27 05:56:13 +00:00
|
|
|
action: ctx.action?.toJSON?.(),
|
2023-12-30 15:34:40 +00:00
|
|
|
app: appName,
|
|
|
|
reqId,
|
2023-12-27 05:56:13 +00:00
|
|
|
});
|
|
|
|
let error: Error;
|
|
|
|
try {
|
|
|
|
await next();
|
|
|
|
} catch (e) {
|
|
|
|
error = e;
|
|
|
|
} finally {
|
|
|
|
const cost = Date.now() - startTime;
|
|
|
|
const status = ctx.status;
|
|
|
|
const info = {
|
2024-01-02 01:35:46 +00:00
|
|
|
message: `response ${ctx.url}`,
|
2023-12-27 05:56:13 +00:00
|
|
|
...requestInfo,
|
2023-12-30 15:34:40 +00:00
|
|
|
res: pick(ctx.response.toJSON(), options?.responseWhitelist || defaultResponseWhitelist),
|
2023-12-27 05:56:13 +00:00
|
|
|
action: ctx.action?.toJSON?.(),
|
|
|
|
userId: ctx.auth?.user?.id,
|
|
|
|
status: ctx.status,
|
|
|
|
cost,
|
2023-12-30 15:34:40 +00:00
|
|
|
app: appName,
|
|
|
|
reqId,
|
2023-12-27 05:56:13 +00:00
|
|
|
};
|
|
|
|
if (Math.floor(status / 100) == 5) {
|
|
|
|
requestLogger.error({ ...info, res: ctx.body?.['errors'] || ctx.body });
|
|
|
|
} else if (Math.floor(status / 100) == 4) {
|
|
|
|
requestLogger.warn({ ...info, res: ctx.body?.['errors'] || ctx.body });
|
|
|
|
} else {
|
|
|
|
requestLogger.info(info);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx.res.setHeader('X-Request-Id', reqId);
|
|
|
|
|
|
|
|
if (error) {
|
|
|
|
throw error;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
};
|