3263a241ab
* feat: logging package * chore: dependency * chore: pino * feat: request log * feat: log rotate * fix: gitignore * fix: gitignore * fix: middleware await * fix: test * docs: logging * feat: log error handler errors * feat: improve code * fix: response error log level * feat: log http body * feat: improve code * feat: improve code * feat: update docs * fix: error * feat: improve code * fix: deps * feat: update docs * fix: error * fix: colorize Co-authored-by: chenos <chenlinxh@gmail.com>
82 lines
2.1 KiB
TypeScript
82 lines
2.1 KiB
TypeScript
import { randomUUID } from 'crypto';
|
|
import Koa from 'koa';
|
|
import { pick } from 'lodash';
|
|
import { createLogger, LoggerOptions } from './create-logger';
|
|
|
|
const defaultRequestWhitelist = [
|
|
'action',
|
|
'header.x-role',
|
|
'header.x-hostname',
|
|
'header.x-timezone',
|
|
'header.x-locale',
|
|
'referer',
|
|
];
|
|
|
|
const defaultResponseWhitelist = ['status'];
|
|
|
|
export interface AppLoggerOptions extends LoggerOptions {
|
|
skip?: (ctx?: any) => Promise<boolean>;
|
|
requestWhitelist?: string[];
|
|
responseWhitelist?: string[];
|
|
}
|
|
|
|
export function createAppLogger(options: AppLoggerOptions = {}) {
|
|
const {
|
|
skip,
|
|
requestWhitelist = defaultRequestWhitelist,
|
|
responseWhitelist = defaultResponseWhitelist,
|
|
...others
|
|
} = options;
|
|
const instance = createLogger(others);
|
|
const middleware = async (ctx: Koa.Context, next: Koa.Next) => {
|
|
if (skip && (await skip(ctx))) {
|
|
return next();
|
|
}
|
|
const logger = ctx.app['logger'];
|
|
const startTime = Date.now();
|
|
const info = {
|
|
level: 'info',
|
|
message: `END: ${ctx.method} ${ctx.url}`,
|
|
req: ctx.request.toJSON(),
|
|
};
|
|
|
|
ctx.reqId = ctx.req['id'] = randomUUID();
|
|
ctx.logger = ctx.log = logger.child({ reqId: ctx.reqId });
|
|
|
|
ctx.logger.info(`BEGIN: ${ctx.method} ${ctx.url}`);
|
|
|
|
let error;
|
|
|
|
try {
|
|
await next();
|
|
} catch (e) {
|
|
error = e;
|
|
} finally {
|
|
info['res'] = ctx.response.toJSON();
|
|
// info['status'] = ctx.status;
|
|
if (Math.floor(ctx.status / 100) == 5) {
|
|
info.level = 'error';
|
|
info['errors'] = ctx.body?.['errors'] || ctx.body;
|
|
} else if (Math.floor(ctx.status / 100) == 4) {
|
|
info.level = 'warn';
|
|
info['errors'] = ctx.body?.['errors'] || ctx.body;
|
|
}
|
|
info['responseTime'] = Date.now() - startTime;
|
|
if (ctx.action) {
|
|
info['req']['action'] = ctx.action?.toJSON?.();
|
|
}
|
|
info['req'] = pick(info['req'], requestWhitelist);
|
|
info['res'] = pick(info['res'], responseWhitelist);
|
|
ctx.logger.log(info);
|
|
}
|
|
|
|
if (error) {
|
|
throw error;
|
|
}
|
|
};
|
|
|
|
return { instance, middleware };
|
|
}
|
|
|
|
export default createAppLogger;
|