feat: logger middleware

This commit is contained in:
DIYgod 2024-03-01 21:42:51 +08:00
parent 7af2a2ae27
commit 68a99bf4d9
No known key found for this signature in database
4 changed files with 69 additions and 13 deletions

View File

@ -3,6 +3,7 @@ import '@/utils/request-wrapper';
import { Hono } from 'hono';
import { compress } from 'hono/compress';
import mLogger from '@/middleware/logger';
import cache from '@/middleware/cache';
import template from '@/middleware/template';
import sentry from '@/middleware/sentry';
@ -11,6 +12,7 @@ import debug from '@/middleware/debug';
import header from '@/middleware/header';
import antiHotlink from '@/middleware/anti-hotlink';
import parameter from '@/middleware/parameter';
import logger from '@/utils/logger';
import routes from '@/routes';
@ -23,14 +25,16 @@ process.on('uncaughtException', (e) => {
const app = new Hono();
app.use(compress());
app.use('*', sentry);
app.use('*', accessControl);
app.use('*', debug);
app.use('*', template);
app.use('*', header);
app.use('*', antiHotlink);
app.use('*', parameter);
app.use('*', cache);
app.use(mLogger);
app.use(sentry);
app.use(accessControl);
app.use(debug);
app.use(template);
app.use(header);
app.use(antiHotlink);
app.use(parameter);
app.use(cache);
routes(app);

View File

@ -1,7 +1,5 @@
import { getIp } from '@/utils/helpers';
import { MiddlewareHandler } from 'hono';
import etagCalculate from 'etag';
import logger from '@/utils/logger';
import { config } from '@/config';
import { Data } from '@/types';
@ -20,9 +18,6 @@ function etagMatches(etag: string, ifNoneMatch: string | null) {
}
const middleware: MiddlewareHandler = async (ctx, next) => {
const ip = getIp(ctx);
logger.info(`${ctx.req.url}, user IP: ${ip}`);
for (const key in headers) {
ctx.header(key, headers[key]);
}

40
lib/middleware/logger.ts Normal file
View File

@ -0,0 +1,40 @@
import { MiddlewareHandler } from 'hono';
import logger from '@/utils/logger';
import { getIp, getPath, time } from '@/utils/helpers';
enum LogPrefix {
Outgoing = '-->',
Incoming = '<--',
Error = 'xxx',
}
const colorStatus = (status: number) => {
const out: { [key: string]: string } = {
7: `\u001B[35m${status}\u001B[0m`,
5: `\u001B[31m${status}\u001B[0m`,
4: `\u001B[33m${status}\u001B[0m`,
3: `\u001B[36m${status}\u001B[0m`,
2: `\u001B[32m${status}\u001B[0m`,
1: `\u001B[32m${status}\u001B[0m`,
0: `\u001B[33m${status}\u001B[0m`,
};
const calculateStatus = Math.trunc(status / 100);
return out[calculateStatus];
};
const middleware: MiddlewareHandler = async (ctx, next) => {
const { method, raw } = ctx.req;
const path = getPath(raw);
logger.info(`${LogPrefix.Incoming} ${method} ${path} from ${getIp(ctx)}`);
const start = Date.now();
await next();
logger.info(`${LogPrefix.Outgoing} ${method} ${path} ${colorStatus(ctx.res.status)} ${time(start)}`);
};
export default middleware;

View File

@ -13,3 +13,20 @@ export const getRouteNameFromPath = (path: string) => {
};
export const getIp = (ctx: Context) => (config.nodeName === 'mock' && ctx.req.header('X-Mock-IP') ? ctx.req.header('X-Mock-IP') : ipware.getClientIP(ctx.req.raw)?.ip);
export const getPath = (request: Request): string => {
// Optimized: RegExp is faster than indexOf() + slice()
const match = request.url.match(/^https?:\/\/[^/]+(\/[^?]*)/);
return match ? match[1] : '';
};
const humanize = (times: string[]) => {
const [delimiter, separator] = [',', '.'];
const orderTimes = times.map((v) => v.replaceAll(/(\d)(?=(\d{3})+(?!\d))/g, '$1' + delimiter));
return orderTimes.join(separator);
};
export const time = (start: number) => {
const delta = Date.now() - start;
return humanize([delta < 1000 ? delta + 'ms' : Math.round(delta / 1000) + 's']);
};