Introducción
Una solución de registro eficaz es fundamental para el éxito de cualquier aplicación. Winston es una biblioteca de registro versátil y una solución de registro popular disponible para aplicaciones Node.js. Las características de Winston incluyen compatibilidad con múltiples opciones de almacenamiento, niveles de registro, consultas de registro y un generador de perfiles integrado.
En este tutorial, utilizará Winston para registrar una aplicación Node/ Express que creará como parte de este proceso. También verá cómo combinar Winston con Morgan , otro registrador de middleware de solicitudes HTTP popular para Node.js, para consolidar los registros de datos de solicitudes HTTP con otra información. Después de completar este tutorial, su servidor Ubuntu ejecutará una pequeña aplicación Node/Express y Winston se implementará para registrar errores y mensajes en un archivo y en la consola.
Prerrequisitos
Para seguir este tutorial, necesitarás:
-
Un servidor Ubuntu 20.04 con un usuario sudo no root, que puede configurar siguiendo la configuración inicial del servidor .
-
Node.js se instala utilizando el PPA oficial (archivo de paquete personal), que se explica en Cómo instalar Node.js en Ubuntu 20.04, opción 2 .
Paso 1: Creación de una aplicación básica de Node/Express
Winston se utiliza a menudo para registrar eventos de aplicaciones web creadas con Node.js. En este paso, creará una aplicación web Node.js sencilla utilizando el marco Express. Utilizará express-generator, una herramienta de línea de comandos, para ejecutar rápidamente una aplicación web Node/Express.
Dado que instaló Node Package Manager durante los requisitos previos, puede usar el npmcomando para instalar express-generator:
- sudo npm install express-generator -g
La -gbandera instala el paquete globalmente, lo que significa que puede usarse como una herramienta de línea de comandos fuera de un proyecto/módulo Node existente.
Una vez express-generatorinstalado, puedes crear tu aplicación usando el expresscomando, seguido del nombre del directorio que deseas usar para el proyecto:
- express myApp
Para este tutorial, el proyecto se llamará myApp.
Nota: También es posible ejecutar la express-generatorherramienta directamente sin instalarla globalmente como un comando para todo el sistema primero. Para ello, ejecute este comando:
- npx express-generator myApp
El npxcomando es un ejecutor de comandos incluido con Node Package Manager que facilita la ejecución de herramientas de línea de comandos desde el npmregistro.
Durante la primera ejecución, le preguntará si acepta descargar el paquete:
Producción
Need to install the following packages: express-generatorOk to proceed? (y)
Responde yy pulsa ENTER. Ahora puedes utilizar npx express-generatoren lugar de express.
A continuación, instala Nodemon , que recargará automáticamente la aplicación cada vez que realices cambios. Una aplicación Node.js debe reiniciarse cada vez que se realizan cambios en el código fuente para que dichos cambios surtan efecto, por lo que Nodemon observará automáticamente los cambios y reiniciará la aplicación. Dado que quieres poder utilizarlo nodemoncomo una herramienta de línea de comandos, instálalo con el -gindicador:
- sudo npm install nodemon -g
Para finalizar la configuración de la aplicación, muévase al directorio de la aplicación e instale las dependencias de la siguiente manera:
- cd myApp
- npm install
De forma predeterminada, las aplicaciones creadas con express-generatorse ejecutan en el puerto 3000, por lo que debe asegurarse de que el firewall no bloquee el puerto.
Para abrir el puerto 3000, ejecute el siguiente comando:
- sudo ufw allow 3000
Ahora tienes todo lo que necesitas para iniciar tu aplicación web. Para ello, ejecuta el siguiente comando:
- nodemon bin/www
Este comando inicia la aplicación en el puerto 3000. Puedes comprobar si funciona apuntando tu navegador a . Deberías ver algo como esto:http://your_server_ip:3000
En este punto, puede iniciar una segunda sesión SSH en su servidor durante el resto de este tutorial, dejando la aplicación web que acaba de iniciar ejecutándose en la sesión original. Durante el resto de este artículo, la sesión SSH inicial que actualmente ejecuta la aplicación se llamará Sesión A. Todos los comandos de la Sesión A aparecerán sobre un fondo azul marino oscuro como este:
- nodemon bin/www
Utilizará la nueva sesión SSH para ejecutar comandos y editar archivos. Esta sesión se llamará Sesión B. Todos los comandos de la Sesión B aparecerán sobre un fondo azul claro como este:
- cd ~/myApp
A menos que se indique lo contrario, ejecutará todos los comandos restantes en la sesión B.
En este paso, creaste la aplicación básica. A continuación, la personalizarás.
Paso 2: Personalización de las variables de registro
Si bien la aplicación predeterminada creada por express-generatores un buen comienzo, debe personalizar la aplicación para que llame al registrador correcto cuando sea necesario.
express-generatorincluye el middleware de registro HTTP de Morgan que utilizará para registrar datos sobre todas las solicitudes HTTP. Dado que Morgan admite flujos de salida, se combina perfectamente con el soporte de flujo integrado en Winston, lo que le permite consolidar los registros de datos de solicitudes HTTP con cualquier otra cosa que elija registrar con Winston.
El express-generatorcódigo repetitivo utiliza la variable loggeral hacer referencia al morganpaquete. Dado que utilizará morgany winston, que son ambos paquetes de registro, puede resultar confuso llamar a cualquiera de ellos logger. Para especificar qué variable desea, puede cambiar las declaraciones de variables editando el app.jsarchivo.
Para abrir app.jsy editar, utilice nanosu editor de texto favorito:
- nano ~/myApp/app.js
Encuentre la siguiente línea cerca de la parte superior del archivo:
~/miAplicación/app.js
...var logger = require('morgan');...
Cambie el nombre de la variable de loggera morgan:
~/miAplicación/app.js
...var morgan = require('morgan');...
Esta actualización especifica que la variable declarada morganllamará al require()método vinculado al registrador de solicitudes de Morgan.
Debes buscar en qué otro lugar loggerdel archivo se hizo referencia a la variable y cambiarla a morgan. También deberás cambiar el formato de registro utilizado por el morganpaquete a combined, que es el formato de registro estándar de Apache e incluirá información útil en los registros, como la dirección IP remota y el encabezado de solicitud HTTP del agente de usuario.
Para ello, busque la siguiente línea:
~/miAplicación/app.js
...app.use(logger('dev'));...
Actualízalo a lo siguiente:
~/miAplicación/app.js
...app.use(morgan('combined'));...
Estos cambios le ayudarán a comprender a qué paquete de registro se hace referencia en un momento dado después de integrar la configuración de Winston.
Cuando termine, guarde y cierre el archivo.
Ahora que tu aplicación está configurada, puedes comenzar a trabajar con Winston.
Paso 3: Instalación y configuración de Winston
En este paso, instalará y configurará Winston. También explorará las opciones de configuración disponibles como parte del winstonpaquete y creará un registrador para registrar información en un archivo y en la consola.
Instalar winstoncon el siguiente comando:
- cd ~/myApp
- npm install winston
Resulta útil mantener los archivos de configuración de utilidades o soporte para sus aplicaciones en un directorio especial. Cree una configcarpeta que contenga la winstonconfiguración:
- mkdir ~/myApp/config
A continuación, cree una carpeta que contendrá sus archivos de registro:
- mkdir ~/myApp/logs
Por último, instale app-root-path:
- npm install app-root-path --save
El app-root-pathpaquete es útil para especificar rutas en Node.js. Aunque este paquete no está directamente relacionado con Winston, es útil para determinar rutas a archivos en Node.js. Lo usará para especificar la ubicación de los archivos de registro de Winston desde la raíz del proyecto y para evitar la desagradable sintaxis de ruta relativa.
Ahora que la configuración para gestionar el registro está en su lugar, puede definir sus ajustes. Cree y abra ~/myApp/config/winston.jspara editar:
- nano ~/myApp/config/winston.js
El winston.jsarchivo contendrá su winstonconfiguración.
A continuación, agregue el siguiente código para requerir los paquetes app-root-pathy winston:
~/miAplicación/config/winston.js
const appRoot = require('app-root-path');const winston = require('winston');
Con estas variables en su lugar, puede definir los ajustes de configuración para sus transportes . Los transportes son un concepto introducido por Winston que se refiere a los mecanismos de almacenamiento/salida utilizados para los registros. Winston viene con cuatro transportes básicos integrados: consola , archivo , HTTP y flujo .
En este tutorial, nos centraremos en los transportes de consola y de archivos. El transporte de consola registrará información en la consola y el transporte de archivos registrará información en un archivo específico. Cada definición de transporte puede contener ajustes de configuración, como tamaño de archivo, niveles de registro y formato de registro.
A continuación se muestra un resumen rápido de las configuraciones que utilizará para cada transporte:
level:nivel de mensajes a registrar.filename:el archivo que se utilizará para escribir datos de registro.handleExceptions:captura y registra excepciones no controladas.maxsize: tamaño máximo del archivo de registro, en bytes, antes de que se cree un nuevo archivo.maxFiles:limita la cantidad de archivos creados cuando se excede el tamaño del archivo de registro.format:cómo se formateará la salida del registro.
Los niveles de registro indican la prioridad del mensaje y se denotan con un número entero. Winston utiliza npmniveles de registro que se priorizan de 0 a 6 (de mayor a menor):
- 0 : error
- 1 : advertir
- 2 : información
- 3 : http
- 4 : verboso
- 5 : depuración
- 6 : tonto
Al especificar un nivel de registro para un transporte en particular, se registrará todo lo que se encuentre en ese nivel o en un nivel superior. Por ejemplo, al establecer un nivel de info, se registrará todo lo que se encuentre en el nivel error, warno .info
Los niveles de registro se especifican al llamar al registrador, lo que significa que puede ejecutar el siguiente comando para registrar un error: logger.error('test error message').
Aún en el archivo de configuración, agregue el siguiente código para definir las opciones de configuración para los transportes filey consoleen la winstonconfiguración:
~/miAplicación/config/winston.js
...// define the custom settings for each transport (file, console)const options = { file: { level: "info", filename: `${appRoot}/logs/app.log`, handleExceptions: true, maxsize: 5242880, // 5MB maxFiles: 5, format: winston.format.combine( winston.format.timestamp(), winston.format.json() ), }, console: { level: "debug", handleExceptions: true, format: winston.format.combine( winston.format.colorize(), winston.format.simple() ), },};
A continuación, agregue el siguiente código para crear una instancia de un nuevo winstonregistrador con transportes de archivo y consola utilizando las propiedades definidas en la optionsvariable:
~/miAplicación/config/winston.js
...// instantiate a new Winston Logger with the settings defined aboveconst logger = winston.createLogger({ transports: [ new winston.transports.File(options.file), new winston.transports.Console(options.console), ], exitOnError: false, // do not exit on handled exceptions});
De manera predeterminada, morgansolo se envían los resultados a la consola, por lo que deberá definir una función de flujo que podrá obtener morganlos resultados generados en los winstonarchivos de registro. Utilizará el infonivel para recoger los resultados de ambos transportes (archivo y consola). Agregue el siguiente código al archivo de configuración:
~/miAplicación/config/winston.js
...// create a stream object with a 'write' function that will be used by `morgan`logger.stream = { write: function(message, encoding) { // use the 'info' log level so the output will be picked up by both // transports (file and console) logger.info(message); },};
Por último, agregue el código a continuación para exportar el registrador para que pueda usarse en otras partes de la aplicación:
~/miAplicación/config/winston.js
...module.exports = logger;
El winstonarchivo de configuración completo ahora se verá así:
~/miAplicación/config/winston.js
const appRoot = require("app-root-path");const winston = require("winston");// define the custom settings for each transport (file, console)const options = { file: { level: "info", filename: `${appRoot}/logs/app.log`, handleExceptions: true, maxsize: 5242880, // 5MB maxFiles: 5, format: winston.format.combine( winston.format.timestamp(), winston.format.json() ), }, console: { level: "debug", handleExceptions: true, format: winston.format.combine( winston.format.colorize(), winston.format.simple() ), },};// instantiate a new Winston Logger with the settings defined aboveconst logger = winston.createLogger({ transports: [ new winston.transports.File(options.file), new winston.transports.Console(options.console), ], exitOnError: false, // do not exit on handled exceptions});// create a stream object with a 'write' function that will be used by `morgan`logger.stream = { write: function (message, encoding) { // use the 'info' log level so the output will be picked up by both // transports (file and console) logger.info(message); },};module.exports = logger;
Guarde y cierre el archivo.
Ahora tiene el registrador configurado, pero su aplicación aún no lo reconoce ni sabe cómo usarlo, por lo que necesita integrar el registrador con la aplicación.
Paso 4: Integración de Winston con la aplicación
Para que su registrador funcione con la aplicación, debe tenerlo expressen cuenta. En el paso 2, vio que su expressconfiguración se encuentra en app.js, por lo que puede importar su registrador a este archivo.
Abra el archivo para editarlo:
- nano ~/myApp/app.js
Agregue una winstondeclaración de variable cerca de la parte superior del archivo con las otras requiredeclaraciones:
~/miAplicación/app.js
...var winston = require('./config/winston');...
El primer lugar donde lo usarás winstones con morgan. Aún en app.js, busca la siguiente línea:
~/miAplicación/app.js
...app.use(morgan('combined'));...
Actualízalo para incluir la streamopción:
~/miAplicación/app.js
...app.use(morgan('combined', { stream: winston.stream }));...
Aquí, configura la streamopción de la interfaz de transmisión que creaste como parte de la winstonconfiguración.
Guarde y cierre el archivo.
En este paso, configuró su aplicación Express para que funcione con Winston. A continuación, revisará los datos de registro.
Paso 5: Acceso a los datos de registro y registro de mensajes de registro personalizados
Ahora que la aplicación está configurada, está listo para ver algunos datos de registro. En este paso, revisará las entradas de registro y actualizará su configuración con un mensaje de registro personalizado de muestra.
Si vuelve a cargar la página en el navegador web, debería ver algo similar al siguiente resultado en la consola de la sesión SSH A:
Output[nodemon] restarting due to changes...[nodemon] starting `node bin/www`info: ::1 - - [25/Apr/2022:18:10:55 +0000] "GET / HTTP/1.1" 200 170 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36"info: ::1 - - [25/Apr/2022:18:10:55 +0000] "GET /stylesheets/style.css HTTP/1.1" 304 - "http://localhost:3000/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36"
Aquí hay dos entradas de registro: la primera para la solicitud a la página HTML y la segunda para la hoja de estilo asociada. Dado que cada transporte está configurado para manejar infodatos de registro de nivel, también debería ver información similar en el archivo de transporte ubicado en ~/myApp/logs/app.log.
Para ver el contenido del archivo de registro, ejecute el siguiente comando:
- tail ~/myApp/logs/app.log
tailmostrará las últimas partes del archivo en su terminal.
Deberías ver algo similar a lo siguiente:
{"level":"info","message":"::1 - - [25/Apr/2022:18:10:55 +0000] "GET / HTTP/1.1"" 304 - ""-"" ""Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTMLNo related posts.