Agregar marcas de tiempo a todos los mensajes de la consola

93

Tengo un proyecto completo, implementado y basado en Express, con muchas declaraciones console.log () y console.error () en todas partes. El proyecto se ejecuta usando forever, dirigiendo stdout y stderr a 2 archivos separados.

Todo funciona bastante bien, pero ahora me faltan las marcas de tiempo, para saber exactamente cuándo ocurrieron los errores.

Puedo hacer algún tipo de búsqueda / reemplazo en todo mi código, o usar algún módulo npm que anule la consola en cada archivo, pero no quiero tocar cada archivo de modelo / ruta, a menos que sea absolutamente necesario.

¿Hay alguna forma, tal vez un middleware Express, que me permita agregar una marca de tiempo a cada llamada realizada, o tengo que agregarla manualmente?

Chico tecnológico viajero
fuente

Respuestas:

116

Resulta que puede anular las funciones de la consola en la parte superior del archivo app.js y hacer que surta efecto en todos los demás módulos. Obtuve resultados mixtos porque uno de mis módulos está bifurcado como child_process. Una vez que copié la línea en la parte superior de ese archivo, todo funciona.

Para el registro, instalé el módulo console-stamp ( npm install console-stamp --save) y agregué esta línea en la parte superior de app.js y childProcess.js:

// add timestamps in front of log messages
require('console-stamp')(console, '[HH:MM:ss.l]');

Mi problema ahora era que el :dateformato del registrador de conexión usa el formato UTC, en lugar del que estoy usando en las otras llamadas de la consola. Eso se solucionó fácilmente registrando mi propio formato de hora (y como efecto secundario, requiriendo el dateformatmódulo que console stampviene con, en lugar de instalar otro):

// since logger only returns a UTC version of date, I'm defining my own date format - using an internal module from console-stamp
express.logger.format('mydate', function() {
    var df = require('console-stamp/node_modules/dateformat');
    return df(new Date(), 'HH:MM:ss.l');
});
app.use(express.logger('[:mydate] :method :url :status :res[content-length] - :remote-addr - :response-time ms'));

Ahora mis archivos de registro se ven organizados (y mejor aún, analizables):

[15:09:47.746] staging server listening on port 3000
[15:09:49.322] connected to database server xxxxx successfully
[15:09:52.743] GET /product 200 - - 127.0.0.1 - 214 ms
[15:09:52.929] GET /stylesheets/bootstrap-cerulean.min.css 304 - - 127.0.0.1 - 8 ms
[15:09:52.935] GET /javascripts/vendor/require.js 304 - - 127.0.0.1 - 3 ms
[15:09:53.085] GET /javascripts/product.js 304 - - 127.0.0.1 - 2 ms
...
Chico tecnológico viajero
fuente
2
No pude encontrar los documentos correspondientes, pero parece que ": mm" se referirá al mes y ": MM" es el formato que realmente desea utilizar
Laurent Sigal
2
debe cambiar la parte de los minutos de acuerdo con lo que dice @ user603124. Por minutos, la cadena es : MM ( github.com/starak/node-console-stamp )
sucotronic
Gracias por el comentario. ¡Corregido!
Travel Tech Guy
2
Parece que ya no necesita ajustar HH: MM: ss.l entre paréntesis; lo está haciendo automáticamente
Jeff
3
FYI loggerha sido reemplazado por morgan github.com/senchalabs/connect#middleware
vtellier
34

módulo: "log-timestamp" funciona para mí.

ver https://www.npmjs.com/package/log-timestamp

npm install log-timestamp

Fácil de usar

console.log('Before log-timestamp');
require('log-timestamp');
console.log('After log-timestamp');

Resultado

Before log-timestamp
[2012-08-23T20:08:32.000Z] After log-timestamp
Sunding Wei
fuente
26

Cree un archivo con lo siguiente:

var log = console.log;

console.log = function(){
  log.apply(console, [Date.now()].concat(arguments));
};

Solicítelo en su aplicación antes de iniciar sesión. Haga lo mismo console.errorsi es necesario.

Tenga en cuenta que esta solución destruirá la inserción variable ( console.log("he%s", "y") // "hey") si la está utilizando. Si lo necesita, primero registre la marca de tiempo:

log.call(console, Date.now());
log.apply(console, arguments);
Andreas Hultgren
fuente
2
No si es la misma aplicación / proceso. La consola es un objeto global, por lo que si secuestra una de sus funciones como esta, seguirá siendo secuestrada para todos los archivos que comparten ese objeto global.
Andreas Hultgren
Entonces, ¿esto debería / podría colocarse en el archivo app.js?
Travel Tech Guy
1
Si. <min 15 caracteres ...>
Andreas Hultgren
1
Recomiendo usar el sello de consola en su lugar
Jacek Pietal
1
Esta no es una buena solución: destruye la inserción de variables (por lo tanto, no se puede usar como reemplazo) o imprime la fecha y la salida del registro en diferentes líneas.
George Y.14 de
16

Si desea una solución sin otra dependencia externa pero desea mantener todas las funcionalidades de console.log (múltiples parámetros, inserción de variables), puede usar el siguiente código:

var log = console.log;

console.log = function () {
    var first_parameter = arguments[0];
    var other_parameters = Array.prototype.slice.call(arguments, 1);

    function formatConsoleDate (date) {
        var hour = date.getHours();
        var minutes = date.getMinutes();
        var seconds = date.getSeconds();
        var milliseconds = date.getMilliseconds();

        return '[' +
               ((hour < 10) ? '0' + hour: hour) +
               ':' +
               ((minutes < 10) ? '0' + minutes: minutes) +
               ':' +
               ((seconds < 10) ? '0' + seconds: seconds) +
               '.' +
               ('00' + milliseconds).slice(-3) +
               '] ';
    }

    log.apply(console, [formatConsoleDate(new Date()) + first_parameter].concat(other_parameters));
};

Puede modificar la función formatConsoleDate para formatear la fecha como desee.

Este código debe escribirse solo una vez en la parte superior de su archivo JavaScript principal.

console.log("he%s", "y") imprimirá algo como esto:

[12:22:55.053] hey
leszek.hanusz
fuente
4
Gracias, esta respuesta "sin dependencias" era exactamente lo que necesitaba.
RdR
9

También puede utilizar el paquete log-timestamp . Es bastante sencillo y también personalizable.

Chetan
fuente
3
app.use(morgan('[:date[web]] :method :url :status :res[content-length] - :remote-addr - :response-time ms'))
thxmxx
fuente
2

Esta implementación es simple, admite la funcionalidad original de console.log (pasando un solo objeto y sustitución de variables), no usa módulos externos e imprime todo en una sola llamada a console.log:

var origlog = console.log;

console.log = function( obj, ...placeholders ){
    if ( typeof obj === 'string' )
        placeholders.unshift( Date.now() + " " + obj );
    else
    {
        // This handles console.log( object )
        placeholders.unshift( obj );
        placeholders.unshift( Date.now() + " %j" );
    }

    origlog.apply( this, placeholders );
};
George Y.
fuente
2

Si lo desea, puede crear un registrador personalizado para su aplicación ampliando la compilación del nodo en la clase "Consola". Por favor, consulte la siguiente implementación

"use strict";

const moment = require('moment');
const util = require('util');
const Console = require('console').Console;

class Logger extends Console {
    constructor(stdout, stderr, ...otherArgs) {
        super(stdout, stderr, ...otherArgs);
    }

    log(...args) {
        super.log(moment().format('D MMM HH:mm:ss'), '-', util.format(...args));
    }

    error(...args) {
        super.error(moment().format('D MMM HH:mm:ss'), '-', util.format(...args));
    }
}

module.exports = (function() {
    return new Logger(process.stdout, process.stderr); 
}());

Después de eso, puede usarlo en su código como:

const logger = require('./logger');

logger.log('hello world', 123456);
logger.error('some error occurred', err);

Shivam Shekhar
fuente
1

Esta no es una respuesta directa, pero ¿ha investigado winston.js? Tiene muchas más opciones de registro, incluido el registro en un archivo o base de datos json. Estos siempre tienen marcas de tiempo por defecto. Solo un pensamiento.

Zeke Alexandre Nierenberg
fuente
He mirado en muchas cosas, en este momento, me gustaría añadir algo a un proyecto existente, desplegado - sin tocar demasiado el código
Viajar individuo de la tecnología
1

Estoy intentando sobrescribir el consoleobjeto, parece que funciona bien. Para usarlo, guarde el código a continuación en un archivo, y luego impórtelo para sobrescribir el objeto proxy y luego utilícelo normalmente.

(Tenga en cuenta que esto requiere la transpilación de babel y no funcionará en entornos que no admitan el Proxyconstructor de JavaScript , como IE 11).

import console from './console-shadow.js'

console.log(...)
console.warn(...)
console.error(...)
// console-shadow.js

// Only these functions are shadowed by default
const overwrites = ['log', 'warn', 'info', 'error']

export default new Proxy(
  // Proxy (overwrite console methods here)
  {},

  // Handler
  {
    get: (obj, prop) =>
      prop in obj
        ? obj[prop]
        : overwrites.includes(prop)
        ? (...args) => console[prop].call(console, new Date(), ...args)
        : console[prop],
  }
)

Básicamente, sobrescribo el objeto de la consola con un objeto proxy de JavaScript. Cuando se llama .log, .warnetc. sobrescribe la consola comprobará si lo que está llamando es una función, si por lo que inyectará una fecha en la declaración de registro como primer parámetro, seguido por todos sus parámetros.

Creo que el consoleobjeto en realidad hace mucho y no lo entiendo del todo. Por lo que sólo me intercepción console.log, console.info,console.warn ,console.error llama.

Zach Smith
fuente
-1

Use un detector de eventos como este,

process.on('error', function() { 
   console.log('Error Occurred.');

   var d = Date(Date.now()).toString();
   console.log.call(console, d); // Wed Aug 07 2019 23:40:07 GMT+0100 (GMT+01:00)
});

codificación feliz :)

JsWizard
fuente