Nó: efetue login em um arquivo em vez do console


174

Posso configurar console.logpara que os logs sejam gravados em um arquivo em vez de serem impressos no console?


1
poderia, mas para aplicativos de produção em tempo de execução longo, seria difícil encontrar logs para apenas um dia específico, certo? @racar

Respostas:


72

Atualização 2013 - Isso foi escrito em torno dos nós v0.2 e v0.4; Agora existem utilitários muito melhores para o registro. Eu recomendo Winston

Atualização no final de 2013 - Ainda usamos o winston, mas agora com uma biblioteca de criadores de log para envolver a funcionalidade no registro de objetos e formatação personalizados. Aqui está uma amostra do nosso logger.js https://gist.github.com/rtgibbons/7354879


Deve ser tão simples quanto isso.

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, eu acho ... Como isso funciona? console.log(whatever);ainda vai para o console, não para o arquivo.
trusktr

12
Devido a uma alteração recente, você não pode mais chamar stderr.pipe () - agora é necessário:process.__defineGetter__('stderr', function() { return fs.createWriteStream(__dirname + '/error.log', {flags:'a'}) })
damianb

15
Pessoalmente, eu ficaria bem longe de Winston. Nós o usamos há mais de um ano e finalmente decidimos removê-lo completamente, pois estava causando muitos problemas em nosso ambiente de produção. O projeto parece agora ser extremamente mal mantido. Há uma lista de problemas contanto que seu braço. Muitos dos problemas tiveram solicitações de recebimento enviadas por outros usuários, mas os mantenedores do projeto nem estão demorando para mesclá-los. Para alternativas node-bunyan e caterpillar, pode valer a pena procurar.
UpTheCreek #

É péssimo que os mantenedores não estejam respondendo. Eu pensei que era mantido pelo pessoal do Nodejitsu. Nós o usamos em vários sites, obtendo mais de um milhão de visualizações de página por dia e não tivemos problemas com o log. Talvez isso tenha a ver com o que está sendo registrado e com a quantidade.
Ryan Gibbons

1
Parece que em abril de 2015, Winston está atualizado e está recebendo uma grande quantidade de atividades.
Mike Grace

178

Você também pode sobrecarregar a função console.log padrão:

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

O exemplo acima registrará em debug.log e stdout.

Edit: Veja a versão multiparâmetros por Clément também nesta página.


9
eu não me incomodaria em substituir o console.log. Basta criar sua própria função que registra em um arquivo específico.
Alexander Mills

Além disso, isso não funciona para vários parâmetros. Por exemplo, console.log (p1, p2, p3)
user603749

10
Ótima resposta! Além disso, se você deseja capturar vários argumentos do console.log, basta pegar o objeto 'Arguments' no lugar de 'd' - developer.mozilla.org/en/docs/Web/JavaScript/Reference/…
Charlie

@AlexMills Oi, talvez você possa fornecer um exemplo de como exatamente isso seria feito?
Jonathan

6
mas eu preciso ter isso em cada arquivo js, ​​é possível torná-lo global?
stackdave

60

Se você está procurando algo em produção, o winston é provavelmente a melhor escolha.

Se você quiser fazer coisas rapidamente com dev, envie diretamente para um arquivo (acho que isso funciona apenas para sistemas * nix):

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

7
Usar >para redirecionar o STDOUT também funciona no Windows. nohupnão.
Brad

1
isso funciona felizmente sem nohupno * nix, ie node simple-server.js > output.log. Então, se você gostaria de seguir o log como a sua escrita apenastail -f output.log
pastosa desagradável

Isto não funcionou 2hen i teve argumentos passados para o processo
eran otzap

Qual é a desvantagem de fazer isso na produção?
marcelino

1
btw, dependendo do sistema operacional, esse "fazer algo sobre isso" pode ser simplesmente rotação de logs, o que é uma boa solução - abdussamad.com/archives/541-Log-rotation-in-CentOS-Linux.html
ferr

58

Costumo usar muitos argumentos para console.log () e console.error () , então minha solução seria:

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

O Winston é um módulo npm muito popular usado para registro.

Aqui está um tutorial.
Instale o winston no seu projeto como:

npm install winston --save

Aqui está uma configuração pronta para usar pronta para usar que eu uso frequentemente em meus projetos como logger.js em 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 então simplesmente importe onde for necessário, como este:

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

Então você pode registrar o sucesso como:

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

e erros como:

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

Ele também registra todos os logs de êxito e erros em um arquivo no diretório logs em data, como você pode ver aqui.
direcotry do log


Os logs são visíveis no console. e nenhum arquivo é criado imediatamente !! Estou esquecendo de algo ?
Nigilan

1
Você poderia compartilhar suas configurações? Ou você o usou como sugeri? Verifique as importações ( winston& winston-daily-rotate-file) uma vez se as configurações estiverem corretas. Eles devem ser criados dentro de uma pasta nomeada logsno diretório raiz do projeto. Perdoe-me pela resposta atrasada.
precisa saber é o seguinte

@ Nigigan, como você resolveu isso? Eu estou enfrentando o mesmo problema.
precisa saber é o seguinte

@ user2180794 Dê uma olhada no meu comentário acima do comentário de Nigilan. Deixe-nos saber se você ainda não pode fazê-lo.
precisa saber é o seguinte

1
Não se esqueça de adicioná-los em cima do 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; onde você quiser registrar algo.
precisa saber é o seguinte

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;

Para usá-lo, faça algo como:

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

é possível apenas salvar os erros?
stackdave

Em vez de repetir as Console.prototypeteclas, apenas defina explicitamente this.errorapenas.
rich remer

Isso quebra o console.log?
G_V 04/10/19

Não quebra console.log. Ele muda seu comportamento, embora você possa restaurar o comportamento antigo chamando console.file().
rich remer 13/11/19


6

Outra solução ainda não mencionada é conectar os Writablefluxos em process.stdoute process.stderr. Dessa forma, você não precisa substituir todas as funções do console que geram stdout e stderr. Esta implementação redireciona stdout e stderr para um arquivo de log:

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

Ele deve imprimir no console

a
b
c
d
e
f

e no arquivo de log:

c
d

Para mais informações, consulte esta essência .


Resposta correta.
Nikk wong 15/09/2017

6

Em casos simples, poderíamos redirecionar os fluxos de saída padrão (STDOUT) e erro padrão (STDERR) diretamente para o arquivo por '>' e '2> & 1'

Exemplo:

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

nó test.js> test.log 2> & 1

De acordo com o padrão POSIX, os fluxos 'input', 'output' e 'error' são identificados pelos descritores de arquivos inteiros positivos (0, 1, 2). ou seja, stdin é 0, stdout é 1 e stderr é 2.

'2> & 1' redirecionará de 2 (stderr) para 1 (stdout)

'>' será redirecionado de 1 (stdout) para o arquivo (test.log)


5

Substituir console.log é o caminho a percorrer. Mas para que ele funcione nos módulos necessários, você também precisa exportá-lo.

module.exports = console;

Para poupar o trabalho de gravar arquivos de log, girar e outras coisas, considere usar um módulo simples de logger como o 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;

Sim. Desculpe. Meu mal
Simon Rigét 7/11

você pode substituir as propriedades do console no globalobjeto. por que module.exports?
R3wt 11/08/19

3

MÉTODO STDOUT AND STDERR

Essa abordagem pode ajudá-lo (eu uso algo semelhante em meus projetos) e funciona para todos os métodos, incluindo console.log, console.warn, console.error, console.info

Este método grava os bytes escritos em stdout e stderr no arquivo. É melhor do que alterar os métodos console.log, console.warn, console.error, console.info, porque a saída será exatamente igual à saída dos métodos


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)

vou usar isso no meu módulo npm e atribuir esse código a você. isso é legal?
R3wt 11/08/19

2

Diretamente dos documentos da API do nodejs no 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

Agora você pode usar a Caterpillar, que é um sistema de registro baseado em fluxos, permitindo que você faça logon nele e depois canalize a saída para diferentes transformações e locais.

A saída para um arquivo é tão fácil quanto:

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

Exemplo completo no site da Caterpillar



0

Tomei a ideia de trocar o fluxo de saída para o meu fluxo.

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

Melhore em Andres Riofrio, para lidar com qualquer número de argumentos

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

Eu, por mim mesmo, simplesmente peguei o exemplo do winston e adicionei o log(...)método (porque o winston o nomeia 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;

Em seguida, basta usar no seu código:

const console = require('Console')

Agora você pode simplesmente usar as funções normais de log no seu arquivo e ele criará um arquivo E registrará no seu console (durante a depuração / desenvolvimento). Por causa de if (process.env.NODE_ENV !== 'production') {(no caso de você querer também em produção) ...


O winston não adiciona um monte de lixo como "message" e o nível do log?
G_V 04/10/19

@G_V O que você quer dizer? O winston é muito flexível, você pode configurá-lo ... está procurando ... github.com/winstonjs/winston#formats ?
TechupBusiness 5/10/19
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.