Cree un registrador estándar de la industria para Node.js con Pino
Una guía para crear un registrador estándar de la industria para Node.js usando Pino.
Este artículo cubrirá el uso de la biblioteca Pino. Pino es una biblioteca de registro estándar de la industria que ayuda a imprimir sus registros en un formato mucho más significativo. Estos registros pueden contener muchas otras opciones asociadas con su único registro. Esta información puede contener y no se limita a:
- La información de la solicitud HTTP, incluido el tipo de método y los parámetros de consulta.
- El usuario conectado actual
- El error de la base de datos y la marca de tiempo del servidor
- El tipo de mensaje de error original e información adicional
- La gravedad del registro
Seguir los pasos e implementar esta biblioteca elimina el menos poderoso console.log()
(pero no impotente). Con esta configuración, es más fácil depurar los registros con más información adicional, también se puede usar junto con Prometheus y Grafana, que son herramientas de monitoreo del servidor.
Veamos la utilidad del Pino por el registro más simple que proporciona. Los registros son del tipo:
- trace (rastro)
- debug (depurar)
- info (información)
- warn (advertir)
- error
Un fragmento para realizar los pasos:
const pino = require('pino'); log.info('This is info type log from pino'); log.warn('This is warn type log from pino'); log.error('This is error type log from pino'); // node pino-pretty.js
El código anterior resultará en:
Profundizando en Pino, supongamos que necesitamos una declaración de registro de la consola con los siguientes detalles:
formato JSON
Http req método, cuerpo, consulta, parámetros
detalles del usuario conectado actual
marca de tiempo del servidor y dirección IP
el nombre de la función donde se originó el error
el numero de linea
el nivel de registro
los detalles del error
Para construir la funcionalidad, necesitamos extender el uso y crear un registrador personalizado usando Pino. Creando un archivo “.js” logger.js con los siguientes contenidos:
const pino = require('pino'); const moment = require('moment'); const log = pino({}); log.customError = (error, details = '', LogLevel = process.env.LOG_LEVEL) => { // We can manage universal data using globals const req = global.reqInfo; // The error is parsed in a new Error(error: the error passed to this function) const e = new Error(error); // The error frame from origin error's stack const frame = e.stack.split('\n')[2]; // the function where the error occured const functionName = frame.split(' ')[5]; // The exact line number const lineNumber = frame.split(':').reverse()[1]; // The final object to be logged in the console const errorInfo = { // If we have a request object then parse it otherwise it is null reqInfo: req ? { req: { req: req.method, path: req.path, body: req.body, query: req.query, }, // If a req has a property with key user then extract relevant information otherwise return null user: req.user ? { id: req.user.id, name: req.user.name, } : null, // The server information at the moment of error handling server: { ip: req.ip, servertime: moment().format('YYYY-MM-DD HH:mm:ss'), }, } : null, functionName, lineNumber, // Assuming that error is occured in application layer and not the database end. errorType: 'application error', stack: error.stack || e.stack, message: error.message || e.message, env: process.env.NODE_ENV, // defaults read from environment variable logLevel: LogLevel, process: details, }; // Print appropriate level of log from [info, debug, warn, error] switch (LogLevel) { case 'info': log.info(errorInfo); break; case 'debug': log.debug(errorInfo); break; case 'warn': log.warn(errorInfo); break; case 'error': log.error(errorInfo); break; default: log.error(errorInfo); } }; module.exports = { log, };
He usado ampliamente los comentarios dentro del archivo, así que lo dejaré para su uso personal, comprensión e implementación. Los comentarios anteriores brindan toda la información que necesitará desde la perspectiva del código. El json que he construido para imprimir no se limita a la implementación anterior. Puede eliminar los valores innecesarios que no necesita para su uso personal.
Para usar el registrador anterior, actualicemos nuestro archivo principal desde donde podemos ver el registro real.
// To use the node environment and log level from env file. require('dotenv').config(); const { log } = require('./logger'); // Function to test function name being printed out along with line number in the logs const printMyError = () => { const error = new Error('A custom error is generated generated'); log.customError(error, 'This was my custom message'); }; printMyError();
Los registros impresos tienen formato JSON y se pueden ver en línea en cualquier visor JSON (por el momento). En la visualización, da la siguiente imagen:
Como no usé los globales, el objeto req está vacío y no imprimió la información de HTTP, servidor y usuario. Esto se puede actualizar según las necesidades del proyecto. Para embellecer el registro, puede usar la biblioteca pino-pretty. Pero el inconveniente del enfoque es que deja de imprimir los registros en formato JSON. Todo lo que necesita para configurar pino-pretty es inicializar el registro con la siguiente configuración:
const log = pino({ transport: { target: 'pino-pretty', options: { colorize: true, }, }, });
Este fue un ejemplo para configurar el mecanismo de registro básico y puede modificarse según los requisitos de su proyecto. Para tener una idea de cómo se ve un registro de aplicación de producción real, vea la siguiente imagen:
Todo lo que importa es la configuración que usa con el objeto de inicialización de Pino. Cuando ejecuta aplicaciones en varios entornos, como desarrollo/escenario/producción, también puede tener un escenario en el que desee utilizar pino-pretty en desarrollo y tener registros JSON en producción. Eso también depende del objeto de configuración donde puede tener una cláusula de prueba para verificar el entorno del nodo y luego aplicar los filtros apropiados. Para mantener este artículo corto y directo, me detendré aquí. Además, puede encontrar el código base del artículo aquí:
Otros enlaces útiles:
Y ahí lo tiene. Gracias por leer.