Nodo: inicie sesión en un archivo en lugar de la consola


174

¿Puedo configurar console.logpara que los registros se escriban en un archivo en lugar de imprimirse en la consola?


1
podría, pero para aplicaciones de producción de tiempo de ejecución prolongado, sería difícil encontrar registros para un día específico, ¿verdad? @racar

Respuestas:


72

Actualización 2013: esto se escribió alrededor del Nodo v0.2 y v0.4; Hay utilidades mucho mejores ahora alrededor del registro. Recomiendo mucho Winston

Actualización a fines de 2013: todavía usamos winston, pero ahora con una biblioteca de registradores para ajustar la funcionalidad en torno al registro de objetos personalizados y el formato. Aquí hay una muestra de nuestro logger.js https://gist.github.com/rtgibbons/7354879


Debería ser tan simple como esto.

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 proceso, creo ... ¿Cómo funciona esto? console.log(whatever);Todavía va a la consola, no al archivo.
— trusktr

12
Debido a un cambio reciente, ya no puede llamar a stderr.pipe () - se necesita ahora:process.__defineGetter__('stderr', function() { return fs.createWriteStream(__dirname + '/error.log', {flags:'a'}) })
— damianb

15
Personalmente, me mantendría alejado de Winston. Lo hemos usado durante más de un año y finalmente hemos decidido eliminarlo por completo, ya que causaba muchos problemas en nuestro entorno de producción. El proyecto ahora parece estar extremadamente mal mantenido. Hay una lista de problemas tan larga como tu brazo. Muchos de los problemas han tenido solicitudes de extracción enviadas por otros usuarios, pero los encargados del proyecto ni siquiera se toman el tiempo para fusionarlas. Para alternativas, vale la pena mirar nodo-bunyan y oruga.
— UpTheCreek

Apesta que los mantenedores no sean receptivos. Pensé que era mantenido por la gente de Nodejitsu. Lo hemos utilizado en varios sitios que obtienen más de un millón de visitas al día y no hemos tenido ningún problema con el registro. Tal vez tenga que ver con lo que se está registrando y la cantidad que se está registrando.
— Ryan Gibbons

1
Parece que a partir de abril de 2015 Winston está actualizado y recibe mucha actividad.
— Mike Grace

181

También podría sobrecargar la función predeterminada 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');
};

El ejemplo anterior se registrará en debug.log y stdout.

Editar: Vea la versión multiparamétrica de Clément también en esta página.


9
No me molestaría en sobrescribir console.log. Simplemente cree su propia función que se registre en un archivo específico.
— Alexander Mills

Además, esto no funciona para múltiples parámetros. Ej. Console.log (p1, p2, p3)
— user603749

10
¡Gran respuesta! Además, si desea capturar múltiples argumentos de console.log, simplemente tome el objeto 'Argumentos' en lugar de 'd' - developer.mozilla.org/en/docs/Web/JavaScript/Reference/…
— Charlie

@AlexMills Hola, ¿tal vez podrías dar un ejemplo de cómo se haría exactamente eso?
— Jonathan

66
pero necesito tener esto en cada archivo js, ​​¿es posible hacerlo global?
— stackdave

60

Si está buscando algo en producción, Winston es probablemente la mejor opción.

Si solo quiere hacer cosas de desarrollo rápidamente, envíe directamente a un archivo (creo que esto funciona solo para sistemas * nix):

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

77
El uso >para redirigir STDOUT también funciona en Windows. nohupno lo hace
— Brad

1
esto funciona felizmente sin nohup* nix, es decir node simple-server.js > output.log. Entonces, si desea seguir el registro tal como está escritotail -f output.log
— desagradable pastel el

Esto no funcionó cuando tuve argumentos pasados ​​al proceso
— eran otzap

¿Cuál es la desventaja de hacer esto en producción?
— marcelino

1
por cierto, dependiendo de su sistema operativo, ese "hacer algo al respecto" podría ser simplemente la rotación de registros, que es una buena solución imo - abdussamad.com/archives/541-Log-rotation-in-CentOS-Linux.html
— ferr

59

A menudo uso muchos argumentos para console.log () y console.error () , por lo que mi solución sería:

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 es un módulo npm muy popular utilizado para el registro.

Aquí hay un tutorial.
Instale winston en su proyecto como:

npm install winston --save

Aquí hay una configuración lista para usar lista para usar que uso con frecuencia en mis proyectos como logger.js en 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
};

Y luego simplemente importe donde sea necesario como esto:

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

Entonces puede registrar el éxito como:

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

y errores como:

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

También registra todos los registros de éxito y de error en un archivo en el directorio de registros según la fecha, como puede ver aquí.
direcotry de registro


Los registros son visibles en la consola. ¡y no se crea ningún archivo de inmediato! Me estoy perdiendo de algo ?
— Nigilan

1
¿Podrías compartir tus configuraciones? ¿O lo usaste como te sugerí? Verifique las importaciones ( winston& winston-daily-rotate-file) una vez si las configuraciones están bien. Deben crearse dentro de una carpeta nombrada logsen el directorio raíz del proyecto. Perdón por la respuesta tardía.
— keshavDulal

@Nigilan, ¿cómo arreglaste esto? Estoy enfrentando el mismo problema.
— user2180794

@ user2180794 Echa un vistazo a mi comentario sobre el comentario de Nigilan. Háganos saber si aún no puede hacerlo.
— keshavDulal

1
No te olvides de agregar estos en la parte superior de logger-util const winston = require('winston'); const winstonRotator = require('winston-daily-rotate-file'); Y const errorLog = require('../util/logger').errorlog; const successlog = require('../util/logger').successlog; donde quieras registrar algo.
— 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;

Para usarlo, haga 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

es posible solo salvar a los erros?
— stackdave

En lugar de recorrer las Console.prototypeteclas, solo configúrelas explícitamente this.error.
— rico remer

Esto rompe console.log?
— G_V

No se rompe console.log . Cambia su comportamiento, aunque puede restaurar el comportamiento anterior llamando console.file().
— rico remer


6

Otra solución que aún no se menciona es enganchar las Writablesecuencias en process.stdouty process.stderr. De esta manera, no necesita anular todas las funciones de la consola que salen a stdout y stderr. Esta implementación redirige tanto stdout como stderr a un archivo de 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')

Debería imprimir en la consola

a
b
c
d
e
f

y en el archivo de registro:

c
d

Para obtener más información, consulte esta esencia .


Respuesta correcta.
— Nikk Wong

6

Para casos simples, podríamos redirigir las secuencias de Salida estándar (STDOUT) y Error estándar (STDERR) directamente al archivo mediante '>' y '2> & 1'

Ejemplo:

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

Según el estándar POSIX, los flujos de 'entrada', 'salida' y 'error' se identifican mediante los descriptores de archivo entero positivo (0, 1, 2). es decir, stdin es 0, stdout es 1 y stderr es 2.

'2> & 1' redirigirá de 2 (stderr) a 1 (stdout)

'>' redirigirá desde 1 (stdout) al archivo (test.log)


5

Sobrescribir console.log es el camino a seguir. Pero para que funcione en los módulos necesarios, también debe exportarlo.

module.exports = console;

Para ahorrarse la molestia de escribir archivos de registro, rotar y demás, puede considerar usar un módulo de registro simple como 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í. Lo siento. My bad
— Simon Rigét

puede sobrescribir las propiedades de la consola en el globalobjeto. ¿por qué module.exports?
— r3wt

3

MÉTODO STDOUT Y STDERR

Este enfoque puede ayudarlo (uso algo similar en mis proyectos) y funciona para todos los métodos, incluidos console.log, console.warn, console.error, console.info

Este método escribe los bytes escritos en stdout y stderr en el archivo. Es mejor que cambiar los métodos console.log, console.warn, console.error, console.info, porque la salida será exactamente la misma que la salida de estos 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)

Voy a usar esto en mi módulo npm y atribuirle este código. ¿está bien?
— r3wt

2

Directamente desde los documentos API de nodejs en la consola

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

Ahora puedes usar Caterpillar que es un sistema de registro basado en flujos, que le permite iniciar sesión en él y luego canalizar la salida a diferentes transformaciones y ubicaciones.

La salida a un archivo es tan fácil como:

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

Ejemplo completo en el sitio web de Caterpillar



0

Asumí la idea de cambiar la secuencia de salida a mi secuencia.

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

Mejora en Andres Riofrio, para manejar cualquier cantidad 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

Yo mismo simplemente tomé el ejemplo de Winston y agregué el log(...)método (porque Winston lo nombrainfo(..) :

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;

Luego simplemente use en su código:

const console = require('Console')

Ahora puede simplemente usar las funciones de registro normales en su archivo y creará un archivo Y lo registrará en su consola (mientras se depura / desarrolla). Debido a if (process.env.NODE_ENV !== 'production') {(en caso de que lo desee también en producción) ...


¿Winston no agrega un montón de basura como "mensaje" y el nivel de registro?
— G_V

@G_V ¿Qué quieres decir? winston es muy flexible, puedes configurarlo ... ¿estás buscando ... github.com/winstonjs/winston#formats ?
— TechupBusiness
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.