Узел: войти в файл вместо консоли


174

Можно ли настроить console.logтак, чтобы журналы записывались в файл, а не печатались в консоли?


1
может, но для производственных приложений с длительным временем выполнения было бы трудно найти журналы только для определенного дня, верно? @racar

Ответы:


72

Обновление 2013 - это было написано вокруг Node v0.2 и v0.4; В настоящее время есть гораздо лучшие утилиты для ведения журнала. Я очень рекомендую Уинстон

Обновление, конец 2013 г. - мы по-прежнему используем Winston, но теперь с библиотекой регистратора, чтобы обернуть функциональность вокруг регистрации пользовательских объектов и форматирования. Вот пример нашего logger.js https://gist.github.com/rtgibbons/7354879


Должно быть так просто.

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
НВМ, это означает, что процесс, я думаю ... Как это работает? console.log(whatever);все еще идет в консоль, а не в файл.
trusktr

12
Из-за недавних изменений вы больше не можете вызывать stderr.pipe () - это происходит сейчас:process.__defineGetter__('stderr', function() { return fs.createWriteStream(__dirname + '/error.log', {flags:'a'}) })
damianb

15
Лично я бы держался подальше от Уинстона. Мы используем его уже более года и наконец решили полностью его удалить, поскольку это вызывало множество проблем в нашей производственной среде. Похоже, что сейчас проект находится в крайне плохом состоянии. Есть список проблем, пока ваша рука. У многих из этих проблем были запрошенные запросы от других пользователей, но разработчики проекта даже не нашли время, чтобы объединить их. В качестве альтернативы стоит обратить внимание на узел-буньян и гусеницу.
UpTheCreek

Отстой, что сопровождающие не реагируют. Я думал, что это было поддержано людьми Nodejitsu. Мы использовали его на нескольких сайтах, просматривая более миллиона страниц в день, и у нас не было проблем с ведением журнала. Возможно это имеет отношение к тому, что регистрируется и количеству этого.
Райан Гиббонс

1
Похоже, что по состоянию на апрель 2015 года Уинстон обновлен и получает значительную активность.
Майк Грейс,

181

Вы также можете просто перегрузить функцию 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');
};

Приведенный выше пример войдет в debug.log и stdout.

Изменить: См. Многопараметрическую версию Clément также на этой странице.


9
я бы не стал перезаписывать console.log. Просто создайте свою собственную функцию, которая регистрирует определенный файл.
Александр Миллс

Кроме того, это не работает для нескольких параметров. Например, console.log (p1, p2, p3)
user603749

10
Отличный ответ! Также, если вы хотите захватить несколько аргументов console.log, просто возьмите объект 'Arguments' вместо 'd' - developer.mozilla.org/en/docs/Web/JavaScript/Reference/…
Charlie

@AlexMills Привет, может быть, вы могли бы привести пример, как именно это будет сделано?
Джонатан

6
но мне нужно иметь это в каждом файле JS, возможно ли сделать его глобальным?
стек

60

Если вы ищете что-то в производстве, вероятно, Winston - лучший выбор.

Если вы просто хотите быстро выполнить разработку, выведите ее непосредственно в файл (я думаю, что это работает только для * nix систем):

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

7
Использование >перенаправления STDOUT работает и в Windows. nohupне делает.
Брэд

1
это работает счастливо без nohupна * NIX, то есть node simple-server.js > output.log. Тогда, если вы хотите следить за журналом, как написано простоtail -f output.log
противная выпечка

Это не сработало 2, когда у меня были аргументы переданы процессу
Эран Отзап

Какова обратная сторона этого в производстве?
Марселино

1
Кстати, в зависимости от вашей ОС, «делать что-то о нем» может быть просто ротация журналов, что является хорошим решением imo - abdussamad.com/archives/541-Log-rotation-in-CentOS-Linux.html
ferr

59

Я часто использую много аргументов для console.log () и console.error () , поэтому мое решение будет таким:

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 - очень популярный npm-модуль, используемый для регистрации.

Вот с практическими рекомендациями.
Установите winston в свой проект как:

npm install winston --save

Вот конфигурация, готовая к использованию «из коробки», которую я часто использую в своих проектах как logger.js в утилитах.

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

А затем просто импортируйте туда, где это необходимо:

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

Тогда вы можете зарегистрировать успех как:

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

и ошибки как:

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

Он также регистрирует все журналы успеха и журналы ошибок в файле в каталоге журналов по датам, как вы можете видеть здесь.
лог-директория


Логи видны в консоли. и файл не создается сразу !! Я что-то упускаю ?
Нигилан

1
Не могли бы вы поделиться своими конфигами? Или вы использовали это, как я предложил? Проверьте импорт ( winston& winston-daily-rotate-file) один раз, если с конфигами все в порядке. Они должны быть созданы в папке с именем logsв корневом каталоге проекта. Простите за задержку с ответом.
keshavDulal

@ Нигилан, как ты это исправил? Я сталкиваюсь с той же проблемой.
user2180794

@ user2180794 Посмотрите на мой комментарий над комментарием Нигилана. Дайте нам знать, если вы все еще не можете сделать это.
keshavDulal

1
Не забудьте добавить их поверх logger-util const winston = require('winston'); const winstonRotator = require('winston-daily-rotate-file'); и const errorLog = require('../util/logger').errorlog; const successlog = require('../util/logger').successlog; там, где вы хотите что-то записать.
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;

Чтобы использовать это, сделайте что-то вроде:

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

можно просто сохранить ошибки?
стэкдэйв

Вместо того, чтобы перебирать Console.prototypeключи, просто устанавливайте this.errorтолько явно .
Богатый Ремер

Это ломает console.log?
G_V

Это не ломается console.log. Он меняет свое поведение, хотя вы можете восстановить старое поведение с помощью вызова console.file().
богатый ремер

10

Если это для приложения, вам, вероятно, лучше использовать модуль регистрации. Это даст вам больше гибкости. Несколько предложений.


3
Ваша ссылка на log4js теперь не работает. Как насчет этого? github.com/nomiddlename/log4js-node
Джо Хильдебранд,

1
Да, я думаю, что проект перешел на другую сторону Спасибо.
Марко

6

Другое решение, которое еще не упомянуто, заключается в подключении Writableпотоков process.stdoutи process.stderr. Таким образом, вам не нужно переопределять все функции консоли, которые выводятся в stdout и stderr. Эта реализация перенаправляет как stdout, так и stderr в файл журнала:

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

Должен печатать в консоли

a
b
c
d
e
f

и в файле журнала:

c
d

Для получения дополнительной информации, проверьте эту суть .


Правильный ответ.
Никк Вонг

6

Для простых случаев мы могли бы перенаправить потоки Standard Out (STDOUT) и Standard Error (STDERR) напрямую в файл с помощью '>' и '2> & 1'

Пример:

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

узел test.js> test.log 2> & 1

Согласно стандарту POSIX, потоки 'input', 'output' и 'error' идентифицируются дескрипторами файлов с положительным целым числом (0, 1, 2). то есть stdin равен 0, stdout равен 1 и stderr равен 2.

'2> & 1' будет перенаправлять с 2 (stderr) на 1 (stdout)

'>' перенаправит из 1 (стандартный вывод) в файл (test.log)


5

Перезапись console.log - это путь. Но для того, чтобы он работал в необходимых модулях, вам также нужно его экспортировать.

module.exports = console;

Чтобы избавить себя от необходимости записывать файлы журналов, вращаться и все такое, вы можете рассмотреть возможность использования простого модуля регистрации, такого как 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;

Ага. Сожалею. Мой плохой
Симон Ригет

Вы можете перезаписать консольные свойства globalобъекта. почему module.exports?
r3wt

3

МЕТОД РАЗВЕДЕНИЯ И СТДЕРРА

Этот подход может помочь вам (я использую нечто подобное в моих проектах) и работает для всех методов, включая console.log, console.warn, console.error, console.info

Этот метод записывает байты, записанные в stdout и stderr, в файл. Это лучше, чем изменение методов console.log, console.warn, console.error, console.info, потому что выходные данные будут точно такими же, как эти методы


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)

Я собираюсь использовать это в моем модуле npm и приписать вам этот код. это круто?
r3wt

2

Прямо из API документов nodejs на консоли

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

Теперь вы можете использовать Caterpillar, которая представляет собой систему ведения журналов на основе потоков, которая позволяет вам регистрироваться в ней, а затем направлять вывод в различные преобразования и местоположения.

Вывод в файл так же прост, как:

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

Полный пример на сайте Caterpillar



0

Я взялся за идею обмена выходного потока на мой поток.

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

Улучшение Andres Riofrio, чтобы обрабатывать любое количество аргументов

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

Я для себя просто взял пример от Уинстона и добавил log(...)метод (потому что Уинстон называет его так 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;

Тогда просто используйте в своем коде:

const console = require('Console')

Теперь вы можете просто использовать обычные функции журнала в вашем файле, и он создаст файл и зарегистрирует его на консоли (во время отладки / разработки). Из-за if (process.env.NODE_ENV !== 'production') {(если вы хотите, чтобы это также в производстве) ...


Разве Уинстон не добавляет кучу мусора типа «сообщения» и уровня журнала?
G_V

@G_V Что ты имеешь в виду? Winston очень гибок, вы можете настроить его ... вы ищете ... github.com/winstonjs/winston#formats ?
TechupBusiness
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.