Cómo usar Winston para registrar aplicaciones Node.js en Ubuntu 16.04

Introducción

Una solución de registro eficaz es crucial para el éxito de cualquier aplicación. En esta guía, nos centraremos en un paquete de registro llamado Winston, una biblioteca de registro extremadamente versátil y la solución de registro más popular disponible para aplicaciones Node.js, basada en estadísticas de descarga de NPM. Las características de Winston incluyen compatibilidad con múltiples opciones de almacenamiento y niveles de registro, consultas de registro e incluso un generador de perfiles integrado. Este tutorial le mostrará cómo usar Winston para registrar una aplicación Node/Express que crearemos como parte de este proceso. También veremos cómo podemos combinar Winston con otro registrador de middleware de solicitudes HTTP popular para Node.js llamado Morgan para consolidar los registros de datos de solicitudes HTTP con otra información.

Después de completar este tutorial, tendrá un servidor Ubuntu ejecutando una pequeña aplicación Node/Express. También habrá implementado Winston para registrar errores y mensajes en un archivo y en la consola.

Prerrequisitos

Antes de comenzar esta guía necesitarás lo siguiente:

  • Un servidor Ubuntu 16.04 configurado siguiendo la guía de configuración inicial del servidor Ubuntu 16.04, incluido un usuario sudo no root y un firewall.

  • Node.js se instaló usando el PPA oficial, como se explica en Cómo instalar Node.js en Ubuntu 16.04.

Con estos requisitos previos establecidos, podemos crear nuestra aplicación e instalar Winston.

Paso 1: Creación de una aplicación básica de Node/Express

Un uso común de Winston es el registro de eventos de aplicaciones web creadas con Node.js. Para demostrar completamente cómo incorporar Winston, crearemos una aplicación web Node.js simple utilizando el marco Express. Para ayudarnos a poner en funcionamiento una aplicación web básica, utilizaremos express-generator, una herramienta de línea de comandos para poner en funcionamiento rápidamente una aplicación web Node/Express. Debido a que instalamos el Node Package Manager como parte de nuestros requisitos previos, podremos utilizar el npmcomando para instalar express-generator. También utilizaremos el -gindicador , que instala el paquete globalmente para que pueda utilizarse como una herramienta de línea de comandos fuera de un proyecto/módulo Node existente. Instale el paquete con el siguiente comando:

  1. sudo npm install express-generator -g

Una vez express-generatorinstalado, podemos crear nuestra aplicación mediante el expresscomando, seguido del nombre del directorio que queremos utilizar para nuestro proyecto. Esto creará nuestra aplicación con todo lo que necesitamos para comenzar:

  1. express myApp

A continuación, instala Nodemon, que recargará automáticamente la aplicación cada vez que hagamos algún cambio. Una aplicación Node.js debe reiniciarse cada vez que se realizan cambios en el código fuente para que dichos cambios surtan efecto. Nodemon observará automáticamente los cambios y reiniciará la aplicación por nosotros. Y como queremos poder usarlo nodemoncomo una herramienta de línea de comandos, lo instalaremos con el -gindicador:

  1. sudo npm install nodemon -g

Para finalizar la configuración de la aplicación, cambie al directorio de la aplicación e instale las dependencias de la siguiente manera:

  1. cd myApp
  2. npm install

De forma predeterminada, las aplicaciones creadas con express-generatorse ejecutan en el puerto 3000, por lo que debemos asegurarnos de que el firewall no bloquee ese puerto. Para abrir el puerto 3000, ejecute el siguiente comando:

  1. sudo ufw allow 3000

Ahora tenemos todo lo que necesitamos para iniciar nuestra aplicación web. Para ello, ejecute el siguiente comando:

  1. nodemon bin/www

Esto inicia la ejecución de la aplicación en el puerto 3000. Podemos comprobar que funciona accediendo a ella desde un navegador web. Debería ver algo como esto:http://your_server_ip:3000

En este punto, es una buena idea iniciar una segunda sesión SSH en el servidor para utilizarla durante el resto de este tutorial, dejando la aplicación web que acabamos de iniciar en ejecución en la sesión original. En el resto de este artículo, nos referiremos a la sesión SSH que hemos estado utilizando hasta ahora y que actualmente ejecuta la aplicación como Sesión A. Utilizaremos la nueva sesión SSH para ejecutar comandos y editar archivos, y nos referiremos a esta sesión como Sesión B. A menos que se indique lo contrario, todos los comandos restantes deben ejecutarse en la Sesión B.

Paso 2: Personalización de la aplicación Node.js

La aplicación predeterminada creada por express-generatorhace un gran trabajo para ayudarnos a comenzar, e incluso incluye el middleware de registro HTTP de Morgan que usaremos para registrar datos sobre todas las solicitudes HTTP. Y dado que Morgan admite flujos de salida, es una buena combinación con el soporte de flujo integrado en Winston, lo que nos permite consolidar los registros de datos de solicitudes HTTP con cualquier otra cosa que elijamos registrar con Winston.

De forma predeterminada, el express-generatorcódigo repetitivo utiliza la variable logger al hacer referencia al morganpaquete. Dado que utilizaremos morgany winston, que son paquetes de registro, puede resultar confuso llamar a cualquiera de ellos logger . Por lo tanto, cambiemos eso editando el app.jsarchivo en la raíz del proyecto y realizando algunos cambios.

Para abrir app.jsy editar, utilice el nanocomando:

  1. nano ~/myApp/app.js

Encuentre la siguiente línea cerca de la parte superior del archivo:

~/miAplicación/app.js

...var logger = require('morgan');...

Cámbielo a lo siguiente:

~/miAplicación/app.js

...var morgan = require('morgan');...

También necesitamos encontrar dónde se hizo referencia a la variable logger en el archivo y cambiarla a morgan. Mientras estamos en ello, cambiemos 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'));...

Cámbielo a lo siguiente:

~/miAplicación/app.js

...app.use(morgan('combined'));...

Estos cambios nos ayudarán a comprender mejor a qué paquete de registro estamos haciendo referencia en cualquier momento después de integrar nuestra configuración de Winston.

Salga y guarde el archivo escribiendo CTRL-X, luego Y, y luego ENTER.

Ahora que nuestra aplicación está configurada, estamos listos para comenzar a trabajar con Winston.

Paso 3: Instalación y configuración de Winston

Ahora estamos listos para instalar y configurar Winston. En este paso, exploraremos algunas de las opciones de configuración que están disponibles como parte del winstonpaquete y crearemos un registrador que registrará información en un archivo y en la consola.

Para instalar, winstonejecute el siguiente comando:

  1. cd ~/myApp
  2. npm install winston

A menudo es útil mantener cualquier tipo de archivo de configuración de soporte o utilidad para nuestras aplicaciones en un directorio especial, así que creemos una configcarpeta que contendrá la winstonconfiguración:

  1. mkdir ~/myApp/config

Ahora vamos a crear el archivo que contendrá nuestra winstonconfiguración, al que llamaremos winston.js:

  1. touch ~/myApp/config/winston.js

A continuación, cree una carpeta que contendrá sus archivos de registro:

  1. mkdir ~/myApp/logs

Por último, instalemos app-root-path, un paquete que resulta útil para especificar rutas en Node.js. Este paquete no está relacionado directamente con Winston, pero resulta de gran ayuda para especificar rutas a archivos en el código de Node.js. Lo utilizaremos para especificar la ubicación de los archivos de registro de Winston desde la raíz del proyecto y evitar la desagradable sintaxis de ruta relativa:

  1. npm install app-root-path --save

Ya tenemos todo lo que necesitamos para configurar cómo queremos gestionar nuestro registro, así que podemos pasar a definir nuestra configuración. Comience abriendo ~/myApp/config/winston.jspara editar:

  1. nano ~/myApp/config/winston.js

A continuación, se requieren los paquetes app-root-pathy winston:

~/miAplicación/config/winston.js

var appRoot = require('app-root-path');var winston = require('winston');

Con estas variables en su lugar, podemos definir los ajustes de configuración para nuestros 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 tres transportes principales: consola, archivo y HTTP. En este tutorial, nos centraremos en los transportes de consola y archivo: el transporte de consola registrará información en la consola y el transporte de archivo registrará información en un archivo específico. Cada definición de transporte puede contener sus propios ajustes de configuración, como tamaño de archivo, niveles de registro y formato de registro. A continuación, se incluye un breve resumen de los ajustes que utilizaremos para cada transporte:

  • nivel – Nivel de mensajes a registrar.
  • nombre_de_archivo : el archivo que se utilizará para escribir los datos del registro.
  • handleExceptions – Captura y registra excepciones no controladas.
  • json – Registra datos de registro en formato JSON.
  • 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.
  • colorize – Colorea la salida. Esto puede resultar útil al consultar los registros de la consola.

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 5 (de mayor a menor):

  • 0 : error
  • 1 : advertir
  • 2 : información
  • 3 : verboso
  • 4 : depuración
  • 5 : 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 especificar 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 podemos hacer lo siguiente para registrar un error: logger.error('test error message').

Podemos definir los ajustes de configuración para los transportes filey consoleen la winstonconfiguración de la siguiente manera:

~/miAplicación/config/winston.js

...var options = {  file: {    level: 'info',    filename: `${appRoot}/logs/app.log`,    handleExceptions: true,    json: true,    maxsize: 5242880, // 5MB    maxFiles: 5,    colorize: false,  },  console: {    level: 'debug',    handleExceptions: true,    json: false,    colorize: true,  },};

A continuación, cree una instancia de un nuevo winstonregistrador con transportes de archivos y consola utilizando las propiedades definidas en la optionsvariable:

~/miAplicación/config/winston.js

...var logger = new winston.Logger({  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 definamos una función de flujo que pueda obtener morganlos resultados generados en los winstonarchivos de registro. Usaremos el infonivel para que ambos transportes (archivo y consola) recojan los resultados:

~/miAplicación/config/winston.js

...logger.stream = {  write: function(message, encoding) {    logger.info(message);  },};

Por último, exporte 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 debería verse así:

~/miAplicación/config/winston.js

var appRoot = require('app-root-path');var winston = require('winston');// define the custom settings for each transport (file, console)var options = {  file: {    level: 'info',    filename: `${appRoot}/logs/app.log`,    handleExceptions: true,    json: true,    maxsize: 5242880, // 5MB    maxFiles: 5,    colorize: false,  },  console: {    level: 'debug',    handleExceptions: true,    json: false,    colorize: true,  },};// instantiate a new Winston Logger with the settings defined abovevar logger = new winston.Logger({  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;

Salir y guardar el archivo.

Ya tenemos configurado nuestro registrador, pero nuestra aplicación aún no lo reconoce ni sabe cómo utilizarlo. Ahora vamos a integrar el registrador con la aplicación.

Paso 4: Integración de Winston con nuestra aplicación

Para que nuestro registrador funcione con la aplicación, debemos informarle express. Ya vimos en el paso 2 que nuestra expressconfiguración se encuentra en app.js, así que importemos nuestro registrador a este archivo. Abra el archivo para editarlo ejecutando:

  1. nano ~/myApp/app.js

Importe winstoncerca de la parte superior del archivo con las otras declaraciones requeridas:

~/miAplicación/app.js

...var winston = require('./config/winston');...

El primer lugar en el que realmente lo usaremos winstones con morgan. Usaremos la streamopción y la configuraremos en la interfaz de transmisión que creamos como parte de la winstonconfiguración. Para ello, busque la siguiente línea:

~/miAplicación/app.js

...app.use(morgan('combined'));...

Cámbialo a esto:

~/miAplicación/app.js

...app.use(morgan('combined', { stream: winston.stream }));...

Salir y guardar el archivo.

¡Estamos listos para ver algunos datos de registro! Si vuelves a cargar la página en el navegador web, deberías ver algo similar a lo siguiente en la consola de la sesión SSH A:

Output[nodemon] restarting due to changes...[nodemon] starting `node bin/www`info: ::ffff:72.80.124.207 - - [07/Mar/2018:17:29:36 +0000] "GET / HTTP/1.1" 304 - "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36"info: ::ffff:72.80.124.207 - - [07/Mar/2018:17:29:37 +0000] "GET /stylesheets/style.css HTTP/1.1" 304 - "http://167.99.4.120:3000/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 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 que la acompaña. Dado que cada transporte está configurado para manejar infodatos de registro de nivel, también deberíamos ver información similar en el archivo de transporte ubicado en ~/myApp/logs/app.log. Sin embargo, la salida en el archivo de transporte debería escribirse como un objeto JSON, ya que lo especificamos json: trueen la configuración del archivo de transporte. Puede obtener más información sobre JSON en nuestro tutorial de introducción a JSON. Para ver el contenido del archivo de registro, ejecute el siguiente comando:

  1. tail ~/myApp/logs/app.log

Deberías ver algo similar a lo siguiente:

{"level":"info","message":"::ffff:72.80.124.207 - - [07/Mar/2018:17:29:36 +0000] "GET / HTTP/1.1"" 304 - ""-"" ""Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML

No related posts.

Otros post

Escríbeme