是否可以使用Winston,Pino或Bunyan登录Loopback4?如果是这样,在Loopback4中实现它们的基本步骤是什么?
在查看本教程时,我能够使用Express使Winston正常工作: https://www.digitalocean.com/community/tutorials/how-to-use-winston-to-log-node-js-applications
有适用于Winston和Brunyan的Loopback模块。但是,我的印象是(因为最近的更新已经超过10个月了)它们一定适用于旧版本的Loopback(因为v4于10月18日发布)?
温斯顿-https://www.npmjs.com/package/loopback-component-winston
Brunyan-https://www.npmjs.com/package/loopback-component-bunyan
答案 0 :(得分:1)
可以在Loopback 4
中实现自定义日志记录,这样做应该与Express
没什么不同。
我已经对winston
进行了实验,因此,将对其进行详细说明,但这也可以使用bunyan
来实现。
首先,您可以在项目的根目录中创建一个utils
文件夹,以保留您的自定义记录器。使用LB4 CLI搭建支架的应用采用典型结构,并带有utils
文件夹,如下所示:
.
|
|-- public
|-- src
|-- utils
| |-- logger
| |-- index.js <-- custom logger can be defined here.
|-- node_modules
|-- index.js
|--
.
我正在使用示例 如winston's github repo中所述,用于定义记录器:
// utils/logger/index.js
const winston = require('winston');
const logger = winston.createLogger({
level: 'info',
format: winston.format.json(),
defaultMeta: { service: 'user-service' },
transports: [
//
// - Write to all logs with level `info` and below to `combined.log`
// - Write all logs error (and below) to `error.log`.
//
new winston.transports.File({ filename: 'error.log', level: 'error' }),
new winston.transports.File({ filename: 'combined.log' })
]
});
module.exports = logger;
您现在可以通过在整个应用程序中“导入”记录器来开始使用它。对于根文件夹中的index.js
,import
如下所示:
// index.js
const logger = require('./utils/logger');
对于先前定义的记录器,以下语句会将I am logged.
记录到名为combined.log
的文件中:
logger.info('I am logged.');
这应该让您入门。
P.S。我确信答案(和方法)可以改善,因此非常欢迎任何有用的建议。
答案 1 :(得分:0)
令我有些困扰的是,如果我的一条路线引发异常,则输出只能记录到stderr。因此,我执行以下操作来解决此问题,并改用Winston进行日志记录,同时仍然完全不了解实际使用的底层日志记录系统。
假设在我的一个控制器中,我具有以下REST端点:
@post('/myendpoint')
async handleEndpoint(): Promise<void> {
throw new Error('I am an error!');
}
现在要添加自定义记录器,我为其创建了一个新服务,并将其Winston变体绑定到我的应用程序。
src / services / logger.service.ts (抽象记录器服务及其使用Winston的具体实现)
import winston from 'winston';
export interface LoggerService {
logger: object;
}
export class WinstonLoggerService implements LoggerService {
logger: winston.Logger = winston.createLogger({
level: 'info',
format: winston.format.combine(
winston.format.timestamp(),
winston.format.json(),
),
transports: [
new winston.transports.Console({
format: winston.format.combine(
winston.format.colorize(),
winston.format.printf(info => {
return `[${info.timestamp}] ${info.level}: ${info.message}`;
}),
),
}),
],
});
}
src / keys.ts
export namespace LoggerBindings {
export const LOGGER = BindingKey.create<LoggerService>('services.logger');
}
src / providers / log-error.provider.ts (环回4提供程序类,其中将应用程序绑定的记录器类注入该类,然后可以使用它)
import {Provider} from '@loopback/context';
import {LogError, Request} from '@loopback/rest';
import {inject} from '@loopback/core';
import {LoggerBindings} from '../keys';
import {LoggerService} from '../services/logger.service';
export class LogErrorProvider implements Provider<LogError> {
constructor(@inject(LoggerBindings.LOGGER) protected logger: LoggerService) {}
value(): LogError {
return (err, statusCode, req) => this.action(err, statusCode, req);
}
action(err: Error, statusCode: number, req: Request) {
if (statusCode < 500) {
return;
}
this.logger.logger.error(
`HTTP ${statusCode} on ${req.method} ${req.url}: ${err.stack ?? err}`,
);
}
}
src / application.ts (绑定语句进入构造函数)
import {WinstonLoggerService} from './services/logger.service';
import {LogErrorProvider} from './providers/log-error.provider';
this.bind(LoggerBindings.LOGGER).toClass(WinstonLoggerService);
this.bind(RestBindings.SequenceActions.LOG_ERROR).toProvider(LogErrorProvider);
上一个代码块的最后一行是此处的关键,因为它确保为LOG_ERROR
绑定我们的自定义提供程序。在内部,回送4使用RejectProvider
中定义的@loopback/rest/src/providers/reject.provider.ts
处理在REST端点中引发的错误。向此提供程序中注入RestBindings.SequenceActions.LOG_ERROR
,它是默认情况下从@loopback/rest/src/providers/log-error.provider.ts
提取的,我们在这里重新定义。这样,我们不需要重写整个拒绝提供程序,而只需重写其中的一小部分即可处理REST错误记录。
现在调用示例路由时,控制台上将显示以下内容:
[2020-01-05T23:41:28.604Z] error: HTTP 500 on POST /myendpoint: Error: I am an error!
at [...long stacktrace...]