Hinzufügen von Zeitstempeln zu allen Konsolenmeldungen

89

Ich habe ein vollständiges, bereitgestelltes Express-basiertes Projekt mit vielen Anweisungen für console.log () und console.error (). Das Projekt wird für immer ausgeführt und leitet stdout und stderr in zwei separate Dateien.

Es funktioniert alles ganz gut, aber jetzt fehlen mir Zeitstempel - um genau zu wissen, wann Fehler aufgetreten sind.

Ich kann im gesamten Code suchen / ersetzen oder ein npm-Modul verwenden, das die Konsole in jeder Datei überschreibt, aber ich möchte nicht jede Modell- / Routendatei berühren, es sei denn, ich muss dies unbedingt tun.

Gibt es eine Möglichkeit, vielleicht eine Express-Middleware, mit der ich jedem getätigten Anruf einen Zeitstempel hinzufügen kann, oder muss ich ihn manuell hinzufügen?

Travelling Tech Guy
quelle

Antworten:

114

Es stellt sich heraus, Sie können die Funktionen der Konsole an der Spitze der app.js Datei außer Kraft setzen, und haben sie Wirkung in jedem anderen Modul nehmen. Ich habe gemischte Ergebnisse erhalten, weil eines meiner Module als child_process. Sobald ich die Zeile auch an den Anfang dieser Datei kopiert habe, funktioniert alles.

Für den Datensatz habe ich das Modul console-stamp ( npm install console-stamp --save) installiert und diese Zeile oben in app.js und childProcess.js eingefügt:

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

Mein Problem war jetzt, dass das :dateFormat des Verbindungsloggers das UTC-Format verwendet und nicht das, das ich in den anderen Konsolenaufrufen verwende. Dies konnte leicht behoben werden, indem ich mein eigenes Zeitformat registrierte (und als Nebeneffekt das mitgelieferte dateformatModul benötigte console stamp, anstatt ein anderes zu installieren):

// 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'));

Jetzt sehen meine Protokolldateien organisiert aus (und noch besser, analysierbar):

[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
...
Travelling Tech Guy
quelle
2
Ich konnte die Dokumente dafür nicht finden, aber es scheint, dass ": mm" sich auf den Monat bezieht und ": MM" das Format ist, das Sie tatsächlich verwenden möchten
Laurent Sigal
2
Sie sollten den Protokollteil entsprechend den Angaben in @ user603124 ändern. Für Minuten ist die Zeichenfolge : MM ( github.com/starak/node-console-stamp )
sucotronic
Danke für den Kommentar. Korrigiert!
Travelling Tech Guy
2
Scheint, als müssten Sie HH: MM: ss.l nicht mehr in Klammern setzen - es wird automatisch ausgeführt
Jeff,
2
FYI loggerwurde durch morgan github.com/senchalabs/connect#middleware
vtellier
32

Modul: "Log-Timestamp" funktioniert bei mir.

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

npm install log-timestamp

Einfach zu benutzen

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

Ergebnis

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

Erstellen Sie eine Datei mit den folgenden Angaben:

var log = console.log;

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

Fordern Sie es in Ihrer App an, bevor Sie etwas protokollieren. Machen Sie dasselbe console.errorbei Bedarf.

Beachten Sie, dass diese Lösung das Einfügen von Variablen ( console.log("he%s", "y") // "hey") zerstört, wenn Sie diese verwenden. Wenn Sie das brauchen, protokollieren Sie einfach zuerst den Zeitstempel:

log.call(console, Date.now());
log.apply(console, arguments);
Andreas Hultgren
quelle
2
Nicht, wenn es die gleiche App / der gleiche Prozess ist. Die Konsole ist ein globales Objekt. Wenn Sie also eine ihrer Funktionen wie diese entführen, wird sie weiterhin für alle Dateien entführt, die dieses globale Objekt gemeinsam nutzen.
Andreas Hultgren
Also sollte / könnte dies in der Datei app.js platziert werden?
Travelling Tech Guy
1
Ja. <min 15 Zeichen ...>
Andreas Hultgren
1
Ich empfehle stattdessen Konsolenstempel zu verwenden
Jacek Pietal
1
Dies ist keine gute Lösung - sie zerstört entweder das Einfügen von Variablen (kann daher nicht als Ersatz verwendet werden) oder druckt Datums- und Protokollausgaben in verschiedenen Zeilen.
George Y.
13

Wenn Sie eine Lösung ohne eine andere externe Abhängigkeit wünschen, aber die vollen Funktionen von console.log (mehrere Parameter, Einfügen von Variablen) beibehalten möchten, können Sie den folgenden Code verwenden:

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));
};

Sie können die Funktion formatConsoleDate ändern, um das gewünschte Datum zu formatieren.

Dieser Code muss nur einmal über Ihre JavaScript-Hauptdatei geschrieben werden.

console.log("he%s", "y") druckt so etwas:

[12:22:55.053] hey
leszek.hanusz
quelle
2
Vielen Dank, diese Antwort "keine Abhängigkeiten" war genau das, was ich brauchte.
RdR
3
app.use(morgan('[:date[web]] :method :url :status :res[content-length] - :remote-addr - :response-time ms'))
thxmxx
quelle
2

Diese Implementierung ist einfach, unterstützt die ursprüngliche Funktionalität von console.log (Übergeben eines einzelnen Objekts und Ersetzen von Variablen), verwendet keine externen Module und druckt alles in einem einzigen Aufruf von 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.
quelle
1

Dies ist keine direkte Antwort, aber haben Sie sich mit winston.js befasst? Es verfügt über eine Menge weiterer Protokollierungsoptionen, einschließlich der Protokollierung in einer JSON-Datei oder -Datenbank. Diese haben standardmäßig immer Zeitstempel. Nur ein Gedanke.

Zeke Alexandre Nierenberg
quelle
Ich habe mich mit vielen Dingen befasst. Im Moment möchte ich einem vorhandenen, bereitgestellten Projekt etwas hinzufügen - ohne zu viel vom Code zu berühren
Travelling Tech Guy
1

Wenn Sie möchten, können Sie einen benutzerdefinierten Logger für Ihre Anwendung erstellen, indem Sie die Build-in-Klasse "Console" des Knotens erweitern. Bitte beziehen Sie sich auf die folgende Implementierung

"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); 
}());

Danach können Sie es in Ihrem Code verwenden als:

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

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

Shivam Shekhar
quelle
0

Ich versuche das zu überschreiben console Objekt zu - scheint gut zu funktionieren. Speichern Sie zur Verwendung den folgenden Code in einer Datei, importieren Sie ihn, um das Proxy-Objekt zu überschreiben, und verwenden Sie ihn dann wie gewohnt.

(Beachten Sie, dass dies eine Babel-Transpilation erfordert und in Umgebungen, die den JavaScript- ProxyKonstruktor nicht unterstützen, wie z. B. IE 11, nicht funktioniert .)

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],
  }
)

Grundsätzlich überschreibe ich das Konsolenobjekt mit einem JavaScript-Proxy-Objekt. Wenn Sie usw. aufrufen .log, .warnprüft die überschriebene Konsole, ob das, was Sie aufrufen, eine Funktion ist. In diesem Fall wird als erster Parameter ein Datum in die Protokollanweisung eingefügt, gefolgt von allen Ihren Parametern.

Ich denke, das consoleObjekt macht tatsächlich viel und ich verstehe es nicht ganz. Also habe ich nur abfangen console.log, console.info, console.warn, console.errornennt.

Zach Smith
quelle
-1

Verwenden Sie den Ereignis-Listener wie folgt:

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)
});

Happy Coding :)

JsWizard
quelle