es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Nodejs / Express / Winston logger: ¿cómo poner de manera elegante req.headers.username en el formato de registro?

Mi backend de nodejs / Express js utiliza el registrador Winston.

src/utils/logger.ts:

import winston from 'winston'
import moment from 'moment';
import os from 'os';
import process from 'process';
import request from 'express';

<p>const levels = {
  error: 0,
  warn: 1,
  info: 2,
  http: 3,
  debug: 4,
}</p>

<p>const level = () => {
  return 'debug'
}</p>

<p>const colors = {
  error: 'red',
  warn: 'yellow',
  info: 'green',
  http: 'magenta',
  debug: 'white',
}
winston.addColors(colors)</p>

<p>const timezonedTime = () => {
  return moment().local().format('YYYY-MMM-DD hh:mm:ss:ms');<br>
}; </p>

<p>const format_string = winston.format.combine(
  winston.format.timestamp({format: timezonedTime}),
  winston.format.colorize({ all: true }),
  winston.format.printf(
    (info) => <code>${info.timestamp}  ${os.hostname()} ${process.pid} ${info.level}: ${info.message}</code>,
  ),
)</p>

<p>const format_json = winston.format.combine(
  winston.format.timestamp({format: timezonedTime}),
  winston.format.colorize({ all: true }),
  winston.format.printf(
    (info) => <code>${info.timestamp}  ${os.hostname()} ${process.pid} ${info.level}: ${info.message}</code>,
  ),
  winston.format.json(),
)</p>

<p>const options = {
  conosle: {
    format: format_string,
    level: 'info',
    handleExceptions: true,
    json: false,
    colorize: true,
  },</p>

<p>error<em>logfile: {
    filename: 'logs/error.log',
    level: 'error',
    format: format</em>string,
    handleExceptions: true,
  }, </p>

<p>all<em>logfile: {
    filename: 'logs/all.log',
    format: format</em>string
  },</p>

<p>all<em>logfile</em>json: {
    filename: 'logs/all<em>json.log',
    format: format</em>json
  }</p>

<p>};</p>

<p>const transports = [
  new winston.transports.Console(options.conosle),
  new winston.transports.File(options.error<em>logfile),
  new winston.transports.File(options.all</em>logfile),
  new winston.transports.File(options.all<em>logfile</em>json),
]</p>

<p>const Logger = winston.createLogger({
  level: level(),
  levels,
  transports,
})</p>

<p>export default Logger</p>

<p>```
Mi aplicación está diseñada de tal manera que mientras un usuario haya iniciado sesión en su cuenta, la cabecera de la solicitud contendrá un campo de <code>username</code>.

Quiero poner este <code>username</code> en cada mensaje de registro causado por las funciones en los puntos finales de la API. Ahora mismo estoy haciendo:

/src/routes.ts:
<code>
app.get(&#39;/api/organizations/project&#39;, organizations.getProject);
</code>
Y:

export const getProject = catchErrors( async (req, res) => {

const username = req.header(‘username’);
if (!username) {
Logger.warn(no req.headers.username found!);
throw new NoUsernameError();
}

const user = await findUserWithOrganizationsByUsername(username);
const userId = user.id;
const userType = user.userType;
Logger.info(User ${req.headers.username} has id and type ${userId}, ${userType};);

const organizationId = req.query.organizationId;

const organization = await findEntityOrThrow(Organization, organizationId, {
relations: [‘users’]
});
Logger.info(User ${req.headers.username}: got organization);


“`
Básicamente, en muchos pasos en el código de lógica empresarial, necesito registrar un mensaje con req.headers.username, así como lo hacen level y timestamp en todas las entradas de registro.

¿Hay alguna manera elegante de ponerlo? No quiero hacer

Logger.info(User ${req.headers.username} ....bla bla bla ...);

en cada línea de registro.

Tags:  , , ,

Answer

  1. Avatar for davy.ai

    Sí, hay una manera de evitar repetir req.headers.username en cada mensaje de registro. Como Logger es simplemente una instancia de la clase winston.Logger, puedes crear un registro personalizado que extienda la clase Logger y agregue el campo username a cada mensaje de registro. Aquí hay un ejemplo de cómo puedes hacerlo:

    import winston, { Logger } from 'winston'
    
    class CustomLogger extends Logger {
      private username: string
    
      constructor(username: string, options: winston.LoggerOptions) {
        super(options)
        this.username = username
      }
    
      public info(message: string) {
        super.info(`Usuario ${this.username}: ${message}`)
      }
    
      public warn(message: string) {
        super.warn(`Usuario ${this.username}: ${message}`)
      }
    
      public error(message: string) {
        super.error(`Usuario ${this.username}: ${message}`)
      }
    
      // Agrega otros niveles de registro según sea necesario
    }
    
    export default CustomLogger
    

    Luego, en tu función getProject, puedes crear un registro personalizado de esta manera:

    const username = req.header('username');
    if (!username) {
      Logger.warn(`¡no se encontró req.headers.username!`);
      throw new NoUsernameError();
    }
    
    const userLogger = new CustomLogger(username, Logger.options)
    

    Y usarlo en lugar de Logger:

    userLogger.info('Se ha obtenido la organización')
    userLogger.debug('Mensaje de depuración')
    

    De esta manera, el campo username se agregará a cada mensaje de registro sin tener que repetirlo en cada declaración de registro. Ten en cuenta que CustomLogger solo anula los métodos de registro que necesitas usar. Si necesitas usar otros niveles de registro (debug, http, etc.), también puedes agregarlos a la definición de la clase.

Comments are closed.