chore: strengthen backend eslint profile
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { Global, Module } from '@nestjs/common';
|
||||
|
||||
import { RequestContextService } from './request-context.service';
|
||||
import { RequestLoggingMiddleware } from './request-logging.middleware';
|
||||
import { StructuredLogger } from './structured-logger.service';
|
||||
|
||||
@@ -2,10 +2,10 @@ import { Injectable } from '@nestjs/common';
|
||||
import { AsyncLocalStorage } from 'node:async_hooks';
|
||||
|
||||
export type RequestLogContext = {
|
||||
requestId: string;
|
||||
clientRequestId?: string;
|
||||
userId?: string;
|
||||
brokerageAccountId?: string;
|
||||
clientRequestId?: string;
|
||||
requestId: string;
|
||||
userId?: string;
|
||||
};
|
||||
|
||||
@Injectable()
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { EventEmitter } from 'node:events';
|
||||
|
||||
import { RequestLoggingMiddleware } from './request-logging.middleware';
|
||||
|
||||
describe('RequestLoggingMiddleware', () => {
|
||||
@@ -19,11 +20,11 @@ describe('RequestLoggingMiddleware', () => {
|
||||
const next = jest.fn();
|
||||
|
||||
const request: {
|
||||
method: string;
|
||||
baseUrl: string;
|
||||
route: { path: string };
|
||||
header: jest.Mock<string>;
|
||||
id?: string;
|
||||
method: string;
|
||||
route: { path: string };
|
||||
} = {
|
||||
method: 'GET',
|
||||
baseUrl: '/api/v1',
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { constants as httpStatus } from 'node:http2';
|
||||
import { Injectable, NestMiddleware } from '@nestjs/common';
|
||||
import type { NextFunction, Request, Response } from 'express';
|
||||
|
||||
import { Injectable, NestMiddleware } from '@nestjs/common';
|
||||
import { randomUUID } from 'node:crypto';
|
||||
import { constants as httpStatus } from 'node:http2';
|
||||
|
||||
import { RequestContextService } from './request-context.service';
|
||||
import { StructuredLogger } from './structured-logger.service';
|
||||
|
||||
@@ -31,26 +33,26 @@ export class RequestLoggingMiddleware implements NestMiddleware {
|
||||
const routePath = (routeRequest as { route?: { path?: unknown } }).route
|
||||
?.path;
|
||||
const route =
|
||||
typeof routePath === 'string'
|
||||
? `${request.baseUrl}${routePath}`
|
||||
: '<unmatched>';
|
||||
typeof routePath === 'string' ?
|
||||
`${request.baseUrl}${routePath}` :
|
||||
'<unmatched>';
|
||||
const context = {
|
||||
method: request.method,
|
||||
route,
|
||||
status: response.statusCode,
|
||||
durationMs: Math.round(performance.now() - startedAt),
|
||||
...(response.locals.publicErrorCode
|
||||
? { code: response.locals.publicErrorCode as string }
|
||||
: {}),
|
||||
...(response.locals.publicErrorCode ?
|
||||
{ code: response.locals.publicErrorCode as string } :
|
||||
{}),
|
||||
};
|
||||
const level =
|
||||
response.statusCode >= httpStatus.HTTP_STATUS_INTERNAL_SERVER_ERROR
|
||||
? 'error'
|
||||
: response.statusCode === httpStatus.HTTP_STATUS_TOO_MANY_REQUESTS ||
|
||||
response.statusCode === httpStatus.HTTP_STATUS_UNAUTHORIZED ||
|
||||
response.statusCode === httpStatus.HTTP_STATUS_FORBIDDEN
|
||||
? 'warn'
|
||||
: 'info';
|
||||
response.statusCode >= httpStatus.HTTP_STATUS_INTERNAL_SERVER_ERROR ?
|
||||
'error' :
|
||||
response.statusCode === httpStatus.HTTP_STATUS_TOO_MANY_REQUESTS ||
|
||||
response.statusCode === httpStatus.HTTP_STATUS_UNAUTHORIZED ||
|
||||
response.statusCode === httpStatus.HTTP_STATUS_FORBIDDEN ?
|
||||
'warn' :
|
||||
'info';
|
||||
this.logger.event(level, 'http.request.completed', context);
|
||||
});
|
||||
|
||||
|
||||
@@ -1,27 +1,28 @@
|
||||
import { Injectable, OnApplicationShutdown } from '@nestjs/common';
|
||||
import { PinoLogger } from 'nestjs-pino';
|
||||
|
||||
import { RequestContextService } from './request-context.service';
|
||||
|
||||
type LogLevel = 'debug' | 'info' | 'warn' | 'error';
|
||||
type LogContext = Record<string, string | number | boolean | undefined>;
|
||||
type LogLevel = 'debug' | 'error' | 'info' | 'warn';
|
||||
type LogContext = Record<string, boolean | number | string | undefined>;
|
||||
|
||||
const allowedFields = new Set([
|
||||
'service',
|
||||
'environment',
|
||||
'requestId',
|
||||
'clientRequestId',
|
||||
'userId',
|
||||
'brokerageAccountId',
|
||||
'method',
|
||||
'route',
|
||||
'status',
|
||||
'durationMs',
|
||||
'code',
|
||||
'operation',
|
||||
'grpcCode',
|
||||
'attempts',
|
||||
'brokerageAccountId',
|
||||
'clientRequestId',
|
||||
'code',
|
||||
'count',
|
||||
'durationMs',
|
||||
'environment',
|
||||
'found',
|
||||
'grpcCode',
|
||||
'method',
|
||||
'operation',
|
||||
'requestId',
|
||||
'route',
|
||||
'service',
|
||||
'status',
|
||||
'userId',
|
||||
]);
|
||||
|
||||
@Injectable()
|
||||
@@ -48,6 +49,7 @@ export class StructuredLogger implements OnApplicationShutdown {
|
||||
message: string,
|
||||
context: LogContext = {},
|
||||
): void {
|
||||
// eslint-disable-next-line security/detect-object-injection -- The log level is restricted to the internal LogLevel union.
|
||||
this.pino[level](
|
||||
this.safeContext({ ...this.requestContext.get(), ...context }),
|
||||
message,
|
||||
|
||||
Reference in New Issue
Block a user