node.js - 如何在 Loopback 4 中跟踪请求 ID?
问题描述
我正在尝试使用 Loopback 4 在我的 REST API 中跟踪每个 HTTP 请求,以便使用 log4js 将它们记录到控制器中,就像这样:
[2020-05-05T19:21:52.191] [INFO] [request-id:47e9a486-1243-1c07-3ac0-0acc9cce2c0e] user.controller.ts - starting request validation
[2020-05-05T19:21:52.191] [INFO] [request-id:1dc81e45-093a-8009-42d2-e545c3a10c9d] user.controller.ts - starting request validation
[2020-05-05T19:21:53.126] [INFO] [request-id:47e9a486-1243-1c07-3ac0-0acc9cce2c0e] user.controller.ts - request validation success
[2020-05-05T19:21:53.145] [ERROR] [request-id:1dc81e45-093a-8009-42d2-e545c3a10c9d] user.controller.ts - request validation failed
这里的主要问题是[request-id:UUID]
部分,因为 Node.js 有时会混淆日志,我无法识别它们中的哪些属于同一个请求。我已经为 Express 应用程序找到了一些解决方案,但是我找不到一种方法来使用 Loopback 4 和 log4js:
- https://itnext.io/request-id-tracing-in-node-js-applications-c517c7dab62d
- https://solidgeargroup.com/en/express-logging-global-unique-request-identificator-nodejs/
- 在 node.js 中按 ID 跟踪请求流
该解决方案可能涉及使用序列处理程序,但我还不知道如何去做。注入 Request 对象的一些提示:https ://github.com/strongloop/loopback-next/issues/1881#issuecomment-431384142
解决方案
我们使用 winston logger 来完成它,它作为 Logger Service 注入到我们的 sequence.ts 中。这是 sequence.ts 的代码。
export class MySequence implements SequenceHandler {
constructor(
@inject(SequenceActions.FIND_ROUTE) protected findRoute: FindRoute,
@inject(SequenceActions.PARSE_PARAMS) protected parseParams: ParseParams,
@inject(SequenceActions.INVOKE_METHOD) protected invoke: InvokeMethod,
@inject(SequenceActions.SEND) public send: Send,
@inject(SequenceActions.REJECT) public reject: Reject,
@inject(LOGGER.LOGGER_INJECT) public logger: ILogger,
@inject(HelmetSecurityBindings.HELMET_SECURITY_ACTION)
protected helmetAction: HelmetAction,
@inject(RateLimitSecurityBindings.RATELIMIT_SECURITY_ACTION)
protected rateLimitAction: RateLimitAction,
@inject(AlivioBindings.i18n)
protected i18n: i18nAPI,
) {}
async handle(context: RequestContext) {
const requestTime = Date.now();
try {
const {request, response} = context;
this.logger.info(
`Request ${request.method} ${
request.url
} started at ${requestTime.toString()}.
Request Details
Referer = ${request.headers.referer}
User-Agent = ${request.headers['user-agent']}
Remote Address = ${request.connection.remoteAddress}
Remote Address (Proxy) = ${request.headers['x-forwarded-for']}`,
);
const route = this.findRoute(request);
const args = await this.parseParams(request, route);
await this.rateLimitAction(request, response);
await this.helmetAction(request, response);
request.body = args[args.length - 1];
const result = await this.invoke(route, args);
this.send(response, result);
} catch (err) {
this.logger.error(
`Request ${context.request.method} ${
context.request.url
} errored out. Error :: ${JSON.stringify(err)} ${err}`,
);
this.reject(context, error);
} finally {
this.logger.info(
`Request ${context.request.method} ${
context.request.url
} Completed in ${Date.now() - requestTime}ms`,
);
}
}
}
您可以在此处使用任何记录器作为提供程序。您可以在 log4js 上创建一个包装器提供程序,然后像上面那样做。希望这可以帮助。如果您也想查看提供程序代码,请告诉我。我也会分享的。
推荐阅读
- encryption - 对于基于 ISO 的媒体的加密,每个样本是否有最大允许的子样本?
- ionic-framework - 如何在 ionic 3 中的 Onesignal 中将默认推送通知图标更改为小图标?
- c# - 动作结果
没有按预期工作 - javascript - ReactJS,react-router:登录页面中的排除导航菜单
- jquery - 如何从 jQuery 库中获取项目的属性
- java - Spring Boot JSP 页面有效,但 XmlViewResolver 无效
- python - 如何在多个线程之间共享 asyncio.Queue?
- reporting-services - 收到重复的电子邮件 SSRS 订阅
- capybara - 无头 Capybara 测试中的 webkit 目录上传
- python - 为某些案例指定搜索字段 DRF