Dodawanie sygnatur czasowych do wszystkich komunikatów konsoli

93

Mam kompletny, wdrożony projekt oparty na Express, z wieloma instrukcjami console.log () i console.error (). Projekt działa przy użyciu forever, kierując stdout i stderr do 2 oddzielnych plików.

Wszystko działa całkiem dobrze, ale teraz brakuje mi sygnatur czasowych - żeby dokładnie wiedzieć, kiedy wystąpiły błędy.

Mogę wyszukiwać / zamieniać w całym kodzie lub używać modułu npm, który zastępuje konsolę w każdym pliku, ale nie chcę dotykać każdego pliku modelu / trasy, chyba że absolutnie muszę.

Czy istnieje sposób, być może oprogramowanie pośredniczące Express, które pozwoliłoby mi dodać sygnaturę czasową do każdego wykonanego połączenia, czy też muszę dodawać go ręcznie?

Podróżujący Technik
źródło

Odpowiedzi:

116

Okazuje się, że możesz przesłonić funkcje konsoli w górnej części pliku app.js i zastosować je w każdym innym module. Otrzymałem mieszane wyniki, ponieważ jeden z moich modułów jest rozwidlony jako plikchild_process . Po skopiowaniu wiersza również na początek tego pliku wszystko działa.

Dla npm install console-stamp --saveprzypomnienia , zainstalowałem moduł console-stamp ( ) i dodałem ten wiersz na górze app.js i childProcess.js:

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

Mój problem polegał na tym, że :dateformat rejestratora połączeń używa formatu UTC, a nie tego, którego używam w innych wywołaniach konsoli. Można to łatwo naprawić, rejestrując mój własny format czasu (i jako efekt uboczny, wymagając dateformatmodułu, który console stampjest dołączony, zamiast instalowania innego):

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

Teraz moje pliki dziennika wyglądają na uporządkowane (a jeszcze lepiej, możliwe do przeanalizowania):

[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
...
Podróżujący Technik
źródło
2
Nie mogłem znaleźć odpowiednich dokumentów, ale wygląda na to, że „: mm” będzie odnosić się do miesiąca, a „: MM” to format, którego faktycznie chcesz użyć
Laurent Sigal
2
powinieneś zmienić część minutową zgodnie z tym, co mówi @ user603124. Przez minuty ciąg to : MM ( github.com/starak/node-console-stamp )
sucotronic
Dziękuję za komentarz. Poprawione!
Traveling Tech Guy,
2
Wygląda na to, że nie musisz już zawijać HH: MM: ss.l w nawiasach - robi to automatycznie
Jeff
3
FYI loggerzostało zastąpione przez morgan github.com/senchalabs/connect#middleware
vtellier
34

moduł: "log-timestamp" działa dla mnie.

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

npm install log-timestamp

Prosty w użyciu

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

Wynik

Before log-timestamp
[2012-08-23T20:08:32.000Z] After log-timestamp
Sunding Wei
źródło
26

Utwórz plik zawierający:

var log = console.log;

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

Wymagaj tego w swojej aplikacji, zanim cokolwiek zarejestrujesz. Zrób to samo dlaconsole.error razie potrzeby.

Zwróć uwagę, że to rozwiązanie zniszczy zmienną insertion ( console.log("he%s", "y") // "hey"), jeśli tego używasz. Jeśli tego potrzebujesz, po prostu zaloguj najpierw znacznik czasu:

log.call(console, Date.now());
log.apply(console, arguments);
Andreas Hultgren
źródło
2
Nie, jeśli jest to ta sama aplikacja / proces. Konsola jest obiektem globalnym, więc jeśli przejmiesz jedną z jej funkcji, jak ta, będzie ona nadal przechwytywana dla wszystkich plików, które współużytkują ten obiekt globalny.
Andreas Hultgren,
Więc powinno / można to umieścić w pliku app.js?
Traveling Tech Guy,
1
Tak. <min 15 znaków ...>
Andreas Hultgren
1
Polecam zamiast tego używać konsoli-stempla
Jacek Pietal
1
To nie jest dobre rozwiązanie - albo niszczy wstawianie zmiennych (w związku z tym nie może być używane jako zamiennik) lub drukuje datę i wyjście dziennika w różnych wierszach.
George Y.
16

Jeśli potrzebujesz rozwiązania bez innej zależności zewnętrznej, ale chcesz zachować pełną funkcjonalność console.log (wiele parametrów, wstawianie zmiennych), możesz użyć następującego kodu:

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

Możesz zmodyfikować funkcję formatConsoleDate, aby sformatować datę, jak chcesz.

Ten kod musi być napisany tylko raz w głównym pliku JavaScript.

console.log("he%s", "y") wypisze coś takiego:

[12:22:55.053] hey
leszek.hanusz
źródło
4
Dzięki, ta odpowiedź „bez zależności” była dokładnie tym, czego potrzebowałem.
RdR
9

Możesz również użyć pakietu log-timestamp . Jest to dość proste i również konfigurowalne.

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

Ta implementacja jest prosta, obsługuje oryginalną funkcjonalność console.log (przekazywanie pojedynczego obiektu i podstawianie zmiennych), nie używa zewnętrznych modułów i wypisuje wszystko w jednym wywołaniu 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.
źródło
2

Jeśli chcesz, możesz utworzyć niestandardowy program rejestrujący dla swojej aplikacji, rozszerzając kompilację węzła w klasie „Console”. Prosimy zapoznać się z następującą implementacją

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

Następnie możesz użyć go w swoim kodzie jako:

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

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

Shivam Shekhar
źródło
1

To nie jest bezpośrednia odpowiedź, ale czy zajrzałeś do winston.js? Ma o wiele więcej opcji rejestrowania, w tym logowanie do pliku json lub bazy danych. Te zawsze mają domyślnie sygnatury czasowe. Tylko myśl.

Zeke Alexandre Nierenberg
źródło
Przyjrzałem się wielu rzeczom, teraz chciałbym dodać coś do istniejącego, wdrożonego projektu - bez zbytniego dotykania kodu
Traveling Tech Guy
1

Próbuję nadpisać consoleobiekt - wygląda na to, że działa dobrze. Aby użyć, zapisz poniższy kod w pliku, a następnie zaimportuj, aby nadpisać obiekt proxy, a następnie użyj normalnie.

(Zauważ, że wymaga to transpilacji Babel i nie będzie działać w środowiskach, które nie obsługują Proxykonstruktora JavaScript, takich jak 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],
  }
)

Zasadniczo nadpisuję obiekt konsoli obiektem proxy JavaScript. Kiedy dzwonisz .log,.warn itp. Nadpisana konsola sprawdzi, czy to, co wywołujesz, jest funkcją, jeśli tak, wstrzyknie datę do instrukcji log jako pierwszy parametr, a po niej wszystkie parametry.

Myślę, że consoleobiekt naprawdę dużo robi i nie do końca go rozumiem. Więc tylko przechwytująca console.log, console.info, console.warn, console.errorwzywa.

Zach Smith
źródło
-1

Użyj detektora zdarzeń w ten sposób,

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

miłego kodowania :)

JsWizard
źródło