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?


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
...

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

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

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

4
Dzięki, ta odpowiedź „bez zależności” była dokładnie tym, czego potrzebowałem.
RdR


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

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

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


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.


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.


-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 :)

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.