Węzeł: zaloguj się do pliku zamiast do konsoli


174

Czy mogę skonfigurować console.logtak, aby dzienniki były zapisywane w pliku zamiast drukować w konsoli?


1
może, ale w przypadku aplikacji produkcyjnych o długim czasie wykonywania trudno byłoby znaleźć dzienniki tylko z określonego dnia, prawda? @racar

Odpowiedzi:


72

Aktualizacja 2013 - została napisana wokół Node v0.2 i v0.4; Wokół logowania jest teraz dużo lepszych narzędzi. Bardzo polecam Winston

Aktualizacja pod koniec 2013 r. - Nadal używamy winston, ale teraz z biblioteką rejestratora, aby zawinąć funkcjonalność wokół rejestrowania niestandardowych obiektów i formatowania. Oto próbka naszego logger.js https://gist.github.com/rtgibbons/7354879


Powinno być takie proste.

var access = fs.createWriteStream(dir + '/node.access.log', { flags: 'a' })
      , error = fs.createWriteStream(dir + '/node.error.log', { flags: 'a' });

// redirect stdout / stderr
proc.stdout.pipe(access);
proc.stderr.pipe(error);

1
Nvm, to chyba proces ... Jak to działa? console.log(whatever);nadal idzie do konsoli, a nie do pliku.
trusktr

12
Ze względu na ostatnią zmianę nie możesz już wywoływać stderr.pipe () - trwa to teraz:process.__defineGetter__('stderr', function() { return fs.createWriteStream(__dirname + '/error.log', {flags:'a'}) })
damianb

15
Osobiście unikałbym Winstona. Używamy go już od ponad roku i w końcu zdecydowaliśmy się go całkowicie usunąć, ponieważ powodował wiele problemów w naszym środowisku produkcyjnym. Projekt wydaje się być obecnie wyjątkowo słabo utrzymany. Lista problemów jest tak długa, jak twoja ręka. Wiele problemów miało żądania ściągnięcia przesłane przez innych użytkowników, ale opiekunowie projektu nie poświęcają nawet czasu na ich scalenie. Jeśli chodzi o alternatywy, warto przyjrzeć się węzłowi bunyan i gąsienicy.
UpTheCreek

To jest do bani, że opiekunowie nie reagują. Myślałem, że zostało to utrzymane przez ludzi z Nodejitsu. Używaliśmy go w kilku witrynach, które generują ponad milion odsłon dziennie i nie mieliśmy żadnych problemów z logowaniem. Może ma to związek z tym, co jest rejestrowane i jego ilością.
Ryan Gibbons

1
Wygląda na to, że od kwietnia 2015 roku Winston jest aktualny i jest bardzo aktywny.
Mike Grace

180

Możesz także po prostu przeładować domyślną funkcję console.log:

var fs = require('fs');
var util = require('util');
var log_file = fs.createWriteStream(__dirname + '/debug.log', {flags : 'w'});
var log_stdout = process.stdout;

console.log = function(d) { //
  log_file.write(util.format(d) + '\n');
  log_stdout.write(util.format(d) + '\n');
};

Powyższy przykład będzie logował się do debug.log i stdout.

Edycja: Zobacz wersję wieloparametrową Clémenta również na tej stronie.


9
nie zawracałbym sobie głowy nadpisywaniem console.log. Po prostu stwórz własną funkcję, która loguje się do określonego pliku.
Alexander Mills,

Ponadto nie działa to dla wielu parametrów. Np. Console.log (p1, p2, p3)
user603749

10
Świetna odpowiedź! Ponadto, jeśli chcesz przechwycić wiele argumentów console.log, po prostu weź obiekt „Arguments” zamiast „d” - developer.mozilla.org/en/docs/Web/JavaScript/Reference/ ...
Charlie

@AlexMills Cześć, może mógłbyś podać przykład, jak dokładnie można by to zrobić?
Jonathan

6
ale muszę to mieć w każdym pliku js, czy można uczynić go globalnym?
stackdave

60

Jeśli szukasz czegoś w produkcji, winston jest prawdopodobnie najlepszym wyborem.

Jeśli chcesz po prostu szybko robić rzeczy deweloperskie, wyślij bezpośrednio do pliku (myślę, że działa to tylko w systemach * nix):

nohup node simple-server.js > output.log &

7
Korzystanie >z przekierowania STDOUT działa również w systemie Windows. nohupnie.
Brad

1
to działa szczęśliwie bez nohupon * nix, tj node simple-server.js > output.log. W takim razie, jeśli chcesz śledzić dziennik tak, jak jest napisanytail -f output.log
paskudny pasty

To nie zadziałało, gdy przekazałem argumenty do procesu
eran otzap

Jakie są wady robienia tego w produkcji?
marcelino

1
btw, w zależności od systemu operacyjnego, to "zrób-coś-z-tym-" może być po prostu rotacją logów, co jest dobrym rozwiązaniem imo - abdussamad.com/archives/541-Log-rotation-in-CentOS-Linux.html
ferr

58

Często używam wielu argumentów do console.log () i console.error () , więc moim rozwiązaniem byłoby:

var fs = require('fs');
var util = require('util');
var logFile = fs.createWriteStream('log.txt', { flags: 'a' });
  // Or 'w' to truncate the file every time the process starts.
var logStdout = process.stdout;

console.log = function () {
  logFile.write(util.format.apply(null, arguments) + '\n');
  logStdout.write(util.format.apply(null, arguments) + '\n');
}
console.error = console.log;

32

Winston to bardzo popularny moduł npm używany do logowania.

Oto instrukcja.
Zainstaluj Winston w swoim projekcie jako:

npm install winston --save

Oto konfiguracja gotowa do użycia po wyjęciu z pudełka, której często używam w moich projektach jako logger.js w ramach narzędzi.

 /**
 * Configurations of logger.
 */
const winston = require('winston');
const winstonRotator = require('winston-daily-rotate-file');

const consoleConfig = [
  new winston.transports.Console({
    'colorize': true
  })
];

const createLogger = new winston.Logger({
  'transports': consoleConfig
});

const successLogger = createLogger;
successLogger.add(winstonRotator, {
  'name': 'access-file',
  'level': 'info',
  'filename': './logs/access.log',
  'json': false,
  'datePattern': 'yyyy-MM-dd-',
  'prepend': true
});

const errorLogger = createLogger;
errorLogger.add(winstonRotator, {
  'name': 'error-file',
  'level': 'error',
  'filename': './logs/error.log',
  'json': false,
  'datePattern': 'yyyy-MM-dd-',
  'prepend': true
});

module.exports = {
  'successlog': successLogger,
  'errorlog': errorLogger
};

A następnie po prostu zaimportuj w dowolnym miejscu:

const errorLog = require('../util/logger').errorlog;
const successlog = require('../util/logger').successlog;

Następnie możesz zarejestrować sukces jako:

successlog.info(`Success Message and variables: ${variable}`);

i błędy jak:

errorlog.error(`Error Message : ${error}`);

Rejestruje również wszystkie dzienniki sukcesów i dzienniki błędów w pliku w katalogu dzienników według daty, jak widać tutaj.
druty z bali


Dzienniki są widoczne w konsoli. i żaden plik nie jest tworzony od razu !! Czy coś mi brakuje?
Nigilan,

1
Czy mógłbyś udostępnić swoje konfiguracje? A może użyłeś go tak, jak sugerowałem? Sprawdź import ( winston& winston-daily-rotate-file) raz, jeśli konfiguracja jest w porządku. Powinny zostać utworzone w folderze o nazwie logsw katalogu głównym projektu. Przepraszam za opóźnioną odpowiedź.
keshavDulal

@Nigilan, jak to naprawiłeś? Mam ten sam problem.
user2180794

@ user2180794 Spójrz na mój komentarz nad komentarzem Nigilana. Daj nam znać, jeśli nadal nie możesz tego zrobić.
keshavDulal

1
Nie zapomnij dodać ich do logger-util const winston = require('winston'); const winstonRotator = require('winston-daily-rotate-file'); i const errorLog = require('../util/logger').errorlog; const successlog = require('../util/logger').successlog; wszędzie tam, gdzie chcesz coś zarejestrować.
keshavDulal

14
const fs = require("fs");
const {keys} = Object;
const {Console} = console;

/**
 * Redirect console to a file.  Call without path or with false-y
 * value to restore original behavior.
 * @param {string} [path]
 */
function file(path) {
    const con = path ? new Console(fs.createWriteStream(path)) : null;

    keys(Console.prototype).forEach(key => {
        if (path) {
            this[key] = (...args) => con[key](...args);
        } else {
            delete this[key];
        }
    });
};

// patch global console object and export
module.exports = console.file = file;

Aby go użyć, zrób coś takiego:

require("./console-file");
console.file("/path/to.log");
console.log("write to file!");
console.error("also write to file!");
console.file();    // go back to writing to stdout

czy można tylko uratować błędy?
stackdave,

Zamiast zapętlania Console.prototypekluczy, po prostu jawnie ustaw this.errortylko.
bogate wspomnienie

To zepsuje console.log?
G_V

Nie pęka console.log. Zmienia swoje zachowanie, chociaż możesz przywrócić stare zachowanie, dzwoniąc console.file().
bogate przypomnienie


6

Innym rozwiązaniem, o którym jeszcze nie wspomniano, jest podpięcie Writablestrumieni do process.stdouti process.stderr. W ten sposób nie musisz nadpisywać wszystkich funkcji konsoli, które wyświetlają dane wyjściowe na stdout i stderr. Ta implementacja przekierowuje zarówno stdout, jak i stderr do pliku dziennika:

var log_file = require('fs').createWriteStream(__dirname + '/log.txt', {flags : 'w'})

function hook_stream(stream, callback) {
    var old_write = stream.write

    stream.write = (function(write) {
        return function(string, encoding, fd) {
            write.apply(stream, arguments)  // comments this line if you don't want output in the console
            callback(string, encoding, fd)
        }
    })(stream.write)

    return function() {
        stream.write = old_write
    }
}

console.log('a')
console.error('b')

var unhook_stdout = hook_stream(process.stdout, function(string, encoding, fd) {
    log_file.write(string, encoding)
})

var unhook_stderr = hook_stream(process.stderr, function(string, encoding, fd) {
    log_file.write(string, encoding)
})

console.log('c')
console.error('d')

unhook_stdout()
unhook_stderr()

console.log('e')
console.error('f')

Powinien wydrukować się w konsoli

a
b
c
d
e
f

aw pliku dziennika:

c
d

Aby uzyskać więcej informacji, zapoznaj się z tym streszczeniem .


Poprawna odpowiedź.
nikk wong

6

W prostych przypadkach możemy przekierować strumienie Standard Out (STDOUT) i Standard Error (STDERR) bezpośrednio do pliku za pomocą „>” i „2> & 1”

Przykład:

// test.js
(function() {
    // Below outputs are sent to Standard Out (STDOUT) stream
    console.log("Hello Log");
    console.info("Hello Info");
    // Below outputs are sent to Standard Error (STDERR) stream
    console.error("Hello Error");
    console.warn("Hello Warning");
})();

node test.js> test.log 2> & 1

Zgodnie ze standardem POSIX, strumienie „wejścia”, „wyjścia” i „błędu” są identyfikowane przez deskryptory plików z dodatnimi liczbami całkowitymi (0, 1, 2). tj. stdin to 0, stdout to 1, a stderr to 2.

„2> & 1” przekieruje z 2 (stderr) do 1 (stdout)

'>' przekieruje z 1 (stdout) do pliku (test.log)


5

Nadpisanie console.log jest drogą do zrobienia. Ale aby działał w wymaganych modułach, musisz go również wyeksportować.

module.exports = console;

Aby zaoszczędzić sobie kłopotów z zapisywaniem plików dziennika, obracaniem i innymi rzeczami, możesz rozważyć użycie prostego modułu rejestratora, takiego jak winston:

// Include the logger module
var winston = require('winston');
// Set up log file. (you can also define size, rotation etc.)
winston.add(winston.transports.File, { filename: 'somefile.log' });
// Overwrite some of the build-in console functions
console.error = winston.error;
console.log = winston.info;
console.info = winston.info;
console.debug = winston.debug;
console.warn = winston.warn;
module.exports = console;

Tak. Przepraszam. Mój błąd
Simon Rigét

możesz nadpisać właściwości konsoli na globalobiekcie. dlaczego module.exports?
r3wt

3

METODA STDOUT I STDERR

To podejście może ci pomóc (używam czegoś podobnego w moich projektach) i działa dla wszystkich metod, w tym console.log, console.warn, console.error, console.info

Ta metoda zapisuje bajty zapisane w stdout i stderr do pliku. Jest lepsze niż zmiana metod console.log, console.warn, console.error, console.info, ponieważ dane wyjściowe będą dokładnie takie same, jak te metody.


var fs= require("fs")
var os= require("os")
var HOME= os.homedir()
var stdout_r = fs.createWriteStream(HOME + '/node.stdout.log', { flags: 'a' })
var stderr_r = fs.createWriteStream(HOME + '/node.stderr.log', { flags: 'a' })

var attachToLog= function(std, std_new){

    var originalwrite= std.write
    std.write= function(data,enc){
        try{
            var d= data
            if(!Buffer.isBuffer(d))
                d= Buffer.from(data, (typeof enc === 'string') ? enc : "utf8")
            std_new.write.apply(std_new, d)
        }catch(e){}
        return originalwrite.apply(std, arguments)
    }


}
attachToLog(process.stdout, stdout_r)
attachToLog(process.stderr, stderr_r)

// recommended catch error on stdout_r and stderr_r
// stdout_r.on("error", yourfunction)
// stderr_r.on("error", yourfunction)

Zamierzam użyć tego w moim module npm i przypisać ten kod do Ciebie. czy to fajne?
r3wt

2

Prosto z dokumentacji API nodejs na konsoli

const output = fs.createWriteStream('./stdout.log');
const errorOutput = fs.createWriteStream('./stderr.log');
// custom simple logger
const logger = new Console(output, errorOutput);
// use it like console
const count = 5;
logger.log('count: %d', count);
// in stdout.log: count 5

1

Możesz teraz używać Caterpillar, który jest systemem rejestrowania opartym na strumieniach, umożliwiającym logowanie się do niego, a następnie przesyłanie danych wyjściowych do różnych transformacji i lokalizacji.

Wyprowadzanie do pliku jest tak proste, jak:

var logger = new (require('./').Logger)();
logger.pipe(require('fs').createWriteStream('./debug.log'));
logger.log('your log message');

Pełny przykład w witrynie internetowej firmy Caterpillar



0

Podjąłem pomysł zamiany strumienia wyjściowego na mój strumień.

const LogLater                = require ('./loglater.js');
var logfile=new LogLater( 'log'+( new Date().toISOString().replace(/[^a-zA-Z0-9]/g,'-') )+'.txt' );


var PassThrough = require('stream').PassThrough;

var myout= new PassThrough();
var wasout=console._stdout;
myout.on('data',(data)=>{logfile.dateline("\r\n"+data);wasout.write(data);});
console._stdout=myout;

var myerr= new PassThrough();
var waserr=console._stderr;
myerr.on('data',(data)=>{logfile.dateline("\r\n"+data);waserr.write(data);});
console._stderr=myerr;

loglater.js:

const fs = require('fs');

function LogLater(filename, noduplicates, interval) {
    this.filename = filename || "loglater.txt";
    this.arr = [];
    this.timeout = false;
    this.interval = interval || 1000;
    this.noduplicates = noduplicates || true;
    this.onsavetimeout_bind = this.onsavetimeout.bind(this);
    this.lasttext = "";
    process.on('exit',()=>{ if(this.timeout)clearTimeout(this.timeout);this.timeout=false; this.save(); })
}

LogLater.prototype = {
    _log: function _log(text) {
        this.arr.push(text);
        if (!this.timeout) this.timeout = setTimeout(this.onsavetimeout_bind, this.interval);
    },
    text: function log(text, loglastline) {
        if (this.noduplicates) {
            if (this.lasttext === text) return;
            this.lastline = text;
        }
        this._log(text);
    },
    line: function log(text, loglastline) {
        if (this.noduplicates) {
            if (this.lasttext === text) return;
            this.lastline = text;
        }
        this._log(text + '\r\n');
    },
    dateline: function dateline(text) {
        if (this.noduplicates) {
            if (this.lasttext === text) return;
            this.lastline = text;
        }
        this._log(((new Date()).toISOString()) + '\t' + text + '\r\n');
    },
    onsavetimeout: function onsavetimeout() {
        this.timeout = false;
        this.save();
    },
    save: function save() { fs.appendFile(this.filename, this.arr.splice(0, this.arr.length).join(''), function(err) { if (err) console.log(err.stack) }); }
}

module.exports = LogLater;

0

Ulepsz Andres Riofrio, aby obsłużyć dowolną liczbę argumentów

var fs = require('fs');
var util = require('util');

var log_file = fs.createWriteStream(__dirname + '/debug.log', {flags : 'w'});
var log_stdout = process.stdout;

console.log = function(...args) {
    var output = args.join(' ');
    log_file.write(util.format(output) + '\r\n');
    log_stdout.write(util.format(output) + '\r\n');
};


0

Ja dla siebie po prostu wziąłem przykład z winstona i dodałem log(...)metodę (ponieważ winston nazywa ją info(..):

Console.js:

"use strict"

// Include the logger module
const winston = require('winston');

const logger = winston.createLogger({
    level: 'info',
    format: winston.format.json(),
    transports: [
        //
        // - Write to all logs with level `info` and below to `combined.log`
        // - Write all logs error (and below) to `error.log`.
        //
        new winston.transports.File({ filename: 'error.log', level: 'error' }),
        new winston.transports.File({ filename: 'combined.log' })
    ]
});

//
// If we're not in production then log to the `console` with the format:
// `${info.level}: ${info.message} JSON.stringify({ ...rest }) `
//
if (process.env.NODE_ENV !== 'production') {
    logger.add(new winston.transports.Console({
        format: winston.format.simple()
    }));
}

// Add log command
logger.log=logger.info;

module.exports = logger;

Następnie po prostu użyj w swoim kodzie:

const console = require('Console')

Teraz możesz po prostu użyć normalnych funkcji dziennika w swoim pliku, a utworzy on plik ORAZ zaloguje go do konsoli (podczas debugowania / programowania). Ponieważ if (process.env.NODE_ENV !== 'production') {(jeśli chcesz go również w produkcji) ...


Czy Winston nie dodaje garści śmieci, takich jak „wiadomość” i poziom dziennika?
G_V

@G_V Co masz na myśli? winston jest bardzo elastyczny, możesz go skonfigurować ... czy szukasz ... github.com/winstonjs/winston#formats ?
TechupBusiness
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.