Nodo: accedi a un file anziché alla console


174

Posso configurare in console.logmodo che i registri vengano scritti su un file anziché essere stampati nella console?


1
potrebbe, ma per le app di produzione a lungo runtime, sarebbe difficile trovare i log solo per un giorno specifico, giusto? @racar

Risposte:


72

Aggiornamento 2013 - Questo è stato scritto attorno a Nodo v0.2 e v0.4; Ora ci sono utilities molto migliori per la registrazione. Consiglio vivamente Winston

Aggiornamento alla fine del 2013: utilizziamo ancora Winston, ma ora con una libreria di logger per avvolgere la funzionalità attorno alla registrazione di oggetti personalizzati e formattazione. Ecco un esempio del nostro logger.js https://gist.github.com/rtgibbons/7354879


Dovrebbe essere semplice come questo.

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, significa processo penso ... Come funziona? console.log(whatever);va ancora alla console, non al file.
trusktr,

12
A causa di una recente modifica, non puoi più chiamare stderr.pipe () - ora ci vuole:process.__defineGetter__('stderr', function() { return fs.createWriteStream(__dirname + '/error.log', {flags:'a'}) })
damianb

15
Personalmente starei alla larga da Winston. Lo usiamo da oltre un anno e alla fine abbiamo deciso di rimuoverlo completamente perché causava molti problemi nel nostro ambiente di produzione. Il progetto sembra ora estremamente mal gestito. C'è un elenco di problemi fino a quando il tuo braccio. Molti dei problemi hanno ricevuto richieste pull da altri utenti, ma i responsabili del progetto non si stanno nemmeno prendendo il tempo per unirli. Per le alternative, vale la pena dare un'occhiata al nodo-bunyan e al bruco.
UpTheCreek

Fa schifo che i manutentori non rispondano. Ho pensato che fosse gestito dalla gente di Nodejitsu. L'abbiamo usato su diversi siti per ottenere oltre un milione di visualizzazioni di pagina al giorno e non abbiamo avuto problemi con la registrazione. Forse ha a che fare con ciò che viene registrato e la quantità di esso.
Ryan Gibbons,

1
Sembra che ad aprile 2015 Winston sia aggiornato e riceva molte attività.
Mike Grace,

181

Potresti anche sovraccaricare la funzione console.log predefinita:

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

L'esempio sopra accederà a debug.log e stdout.

Modifica: vedi la versione multiparametro di Clément anche su questa pagina.


9
non mi preoccuperei di sovrascrivere console.log. Basta creare la propria funzione che accede a un file specifico.
Alexander Mills,

Inoltre, questo non funziona per più parametri. Ad esempio console.log (p1, p2, p3)
user603749

10
Bella risposta! Inoltre, se vuoi catturare più argomenti console.log, prendi semplicemente l'oggetto 'Arguments' al posto di 'd' - developer.mozilla.org/en/docs/Web/JavaScript/Reference/…
Charlie

@AlexMills Ciao, forse potresti fornire un esempio su come esattamente ciò sarebbe fatto?
Jonathan,

6
ma devo avere questo in ogni file js, è possibile renderlo globale?
StackDave

60

Se stai cercando qualcosa in produzione, Winston è probabilmente la scelta migliore.

Se vuoi semplicemente fare cose di sviluppo rapidamente, esegui l'output direttamente su un file (penso che funzioni solo per i sistemi * nix):

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

7
L'uso >per reindirizzare STDOUT funziona anche su Windows. nohupnon lo fa.
Brad

1
funziona felicemente senza nohupsu * nix, ad es node simple-server.js > output.log. Quindi, se vuoi seguire il diario come scritto solotail -f output.log
brutto pasticcio il

Questo non ha funzionato 2hen ho avuto argomenti passati al processo
Eran Otzap

Qual è il rovescio della medaglia nel fare questo in produzione?
marcelino,

1
a seconda del tuo sistema operativo, "fare qualcosa al riguardo" potrebbe essere semplicemente la rotazione dei registri, che è una buona soluzione imo - abdussamad.com/archives/541-Log-rotation-in-CentOS-Linux.html
ferr

59

Uso spesso molti argomenti per console.log () e console.error () , quindi la mia soluzione sarebbe:

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 è un modulo npm molto popolare utilizzato per la registrazione.

Ecco un how-to.
Installa winston nel tuo progetto come:

npm install winston --save

Ecco una configurazione pronta per l'uso che utilizzo frequentemente nei miei progetti come logger.js sotto utils.

 /**
 * 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
};

E poi importa semplicemente dove richiesto come questo:

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

Quindi puoi registrare il successo come:

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

ed errori come:

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

Inoltre registra tutti i registri di successo e i registri degli errori in un file nella directory dei registri per data, come puoi vedere qui.
registro log


I registri sono visibili nella console. e nessun file viene creato immediatamente !! Mi sto perdendo qualcosa ?
Nigilan,

1
Potresti forse condividere le tue configurazioni? O l'hai usato come ti ho suggerito? Controlla le importazioni ( winston& winston-daily-rotate-file) una volta se le configurazioni sono a posto. Dovrebbero essere creati all'interno di una cartella denominata logsnella directory principale del progetto. Scusatemi per la risposta ritardata.
keshavDulal,

@Nigilan come hai risolto questo problema? Sto affrontando lo stesso problema.
user2180794

@ user2180794 Dai un'occhiata al mio commento sopra il commento di Nigilan. Facci sapere se non riesci ancora a farlo.
keshavDulal

1
Non dimenticare di aggiungerli sopra logger-util const winston = require('winston'); const winstonRotator = require('winston-daily-rotate-file'); e const errorLog = require('../util/logger').errorlog; const successlog = require('../util/logger').successlog; ovunque tu voglia registrare qualcosa.
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;

Per usarlo, fai qualcosa del tipo:

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

è possibile solo per salvare gli errori?
stackdave,

Invece di passare in rassegna le Console.prototypechiavi, impostate this.errorsolo esplicitamente .
rich remer

Questo interrompe console.log?
G_V

Non si rompe console.log. Cambia il suo comportamento, sebbene sia possibile ripristinare il vecchio comportamento chiamando console.file().
ricco ricordo


6

Un'altra soluzione non ancora menzionata è l'aggancio dei Writableflussi in process.stdoute process.stderr. In questo modo non è necessario eseguire l'override tutte le funzioni della console che producono output su stdout e stderr. Questa implementazione reindirizza sia stdout che stderr a un file di registro:

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

Dovrebbe stampare nella console

a
b
c
d
e
f

e nel file di registro:

c
d

Per maggiori informazioni, controlla questo riassunto .


Risposta corretta.
nikk wong,

6

Per casi semplici, potremmo reindirizzare i flussi Standard Out (STDOUT) e Standard Error (STDERR) direttamente al file di '>' e '2> & 1'

Esempio:

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

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

Secondo lo standard POSIX, i flussi 'input', 'output' e 'error' sono identificati dai descrittori di file interi positivi (0, 1, 2). cioè, stdin è 0, stdout è 1 e stderr è 2.

'2> & 1' reindirizzerà da 2 (stderr) a 1 (stdout)

'>' reindirizzerà da 1 (stdout) a file (test.log)


5

Sovrascrivere console.log è la strada da percorrere. Ma affinché funzioni nei moduli richiesti, devi anche esportarlo.

module.exports = console;

Per evitare il problema di scrivere file di registro, ruotare e altro, potresti prendere in considerazione l'uso di un semplice modulo logger come 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;

Sì. Scusate. Mio cattivo
Simon Rigét,

è possibile sovrascrivere le proprietà della console globalsull'oggetto. perchè module.exports?
rww

3

METODO STDOUT E STDERR

Questo approccio può aiutarti (utilizzo qualcosa di simile nei miei progetti) e funziona con tutti i metodi inclusi console.log, console.warn, console.error, console.info

Questo metodo scrive i byte scritti in stdout e stderr su file. È meglio che cambiare i metodi console.log, console.warn, console.error, console.info, perché l'output sarà esattamente lo stesso di questo metodo output


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)

lo userò nel mio modulo npm e ti attribuirò questo codice. è bello?
r3wt

2

Direttamente dai documenti API di nodejs sulla console

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

Ora puoi usare Caterpillar che è un sistema di registrazione basato su flussi, che consente di accedere ad esso, quindi reindirizzare l'output a trasformazioni e posizioni diverse.

L'output in un file è semplice come:

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

Esempio completo sul sito Web Caterpillar



0

Ho preso l'idea di scambiare il flusso di output con un mio flusso.

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

Migliora Andres Riofrio, per gestire qualsiasi numero di argomenti

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

Io stesso ho semplicemente preso l'esempio da Winston e aggiunto il log(...)metodo (perché Winston lo chiama 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;

Quindi utilizza semplicemente nel tuo codice:

const console = require('Console')

Ora puoi semplicemente usare le normali funzioni di registro nel tuo file e questo creerà un file E lo accederà alla tua console (durante il debug / lo sviluppo). A causa di if (process.env.NODE_ENV !== 'production') {(nel caso lo desideri anche in produzione) ...


Winston non aggiunge un mucchio di immondizia come "messaggio" e il livello di registro?
G_V

@G_V Cosa intendi? winston è molto flessibile, puoi configurarlo ... stai cercando ... github.com/winstonjs/winston#formats ?
TechupBusiness,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.