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

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

28 ответов

Решение

Обновление 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);

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

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

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

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

Я часто использую много аргументов для 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;

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

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

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

Пример:

(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 (стандартный вывод)

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

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

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

Если вы используете Linux, вы также можете использовать перенаправление вывода. Не уверен насчет Windows.

      node server.js >> file.log 2>> file.log

>> file.log перенаправить в файл

2>> file.log перенаправить в файл

другие используют сокращение &>> для обоих stdout а также stderr но он не принимается как моим Mac, так и ubuntu :(

дополнительный: > перезаписывает, в то время как >> добавляется.

Кстати, что касается логгеров NodeJS, я использую pino + pino-pretty регистратор

Прямо из 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

Еще одно решение, которое еще не упомянуто, заключается в 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

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

Перезапись 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;

Вы можете использовать nodejsConsoleконструктор

      const mylog = new console.Console(
  fs.createWriteStream("log/logger.log"),
  fs.createWriteStream("log/error.log")
);

И тогда вы можете использовать его так же, как обычноconsoleкласс, например:

      mylog.log("Ok!"); // Will be written into 'log/logger.log'
mylog.error("Bad!"); // Will be written into 'log/error.log'

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

Этот подход может помочь вам (я использую нечто подобное в моих проектах) и работает для всех методов, включая 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)

Большинство средств ведения журнала избыточны и неправильно поддерживают сборку в console.log. Следовательно, я создаю консоль-журнал-файл :

      import { consoleLogToFile } from "console-log-to-file";
// or `const { consoleLogToFile } = require("console-log-to-file/dist/index.cjs.js")`

consoleLogToFile({
  logFilePath: "/log/default.log",
});

// all of your console.log/warn/error/info will work as it does and save to file now.

Если вы ищете решение без изменения кода , вот простое решение.

Для этого требуется pm2, просто добавьте его в свои модули узлов и запустите приложение с

      pm2 start server.js

Готово, теперь console.logs автоматически регистрируется в home / .pm2 / logs / server-out.log .

Добавляя к ответу выше, небольшое расширение к короткому и эффективному переопределению кода console.log. Незначительные дополнения: установите имя файла с датой, функцию оболочки, а также выполните исходную console.logging, чтобы консоль оставалась активной с информацией.

Использование: в начале кода запустите setConsoleLogToFile([FILENAME]).

      const fs = require("fs"),
    util = require('util');


const getPrettyDate = ()=> new Date().toString().replace(":","-").replace(/00\s\(.*\)/, "").replace(` ${new Date().getFullYear()}`, ",").replace(/:\d\d\s/, " ");

module.exports.getPrettyDate = getPrettyDate;

module.exports.setConsoleLogToFile = (filename) => {
    const log_file = fs.createWriteStream(`${__dirname}/${filename} -  ${getPrettyDate()}.log`, { flags: 'w' }),
        log_stdout = process.stdout;

    const origConsole = console.log;
    console.log = (d) => { 
        origConsole(d);
        log_file.write(util.format(d) + '\n');
        log_stdout.write(util.format(d) + '\n');
    };
}

Для будущих пользователей. @keshavDulal ответ не работает для последней версии. И я не смог найти правильного решения проблем, о которых сообщается в последней версии.3.3.3.

В любом случае я, наконец, исправил это после небольшого исследования. Вот решение для версии Winston3.3.3

Установите winston и winston-daily-rotate-file

npm install winston 
npm install winston-daily-rotate-file

Создайте новый файл utils/logger.js

const winston = require('winston');
const winstonRotator = require('winston-daily-rotate-file');

var logger = new winston.createLogger({
  transports: [
    new (winston.transports.DailyRotateFile)({
      name: 'access-file',
      level: 'info',
      filename: './logs/access.log',
      json: false,
      datePattern: 'yyyy-MM-DD',
      prepend: true,
      maxFiles: 10
    }),
    new (winston.transports.DailyRotateFile)({
      name: 'error-file',
      level: 'error',
      filename: './logs/error.log',
      json: false,
      datePattern: 'yyyy-MM-DD',
      prepend: true,
      maxFiles: 10
    })
  ]
});


module.exports = {
  logger
};

Затем в любом файле, в котором вы хотите использовать ведение журнала, импортируйте модуль, например

const logger = require('./utils/logger').logger;

Используйте регистратор следующим образом:

logger.info('Info service started');
logger.error('Service crashed');

Улучшение 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');
};

если вы используете навсегда, чтобы ваше приложение узла работало, введите forever list покажет вам путь к файлу журнала, который также пишет console.log

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

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

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

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

Создайте файл utils / logger.js с:

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

console.log = function () { //
    [...arguments].forEach(element => {
        log_file.write(util.format(element) + '\n');
        log_stdout.write(util.format(element) + '\n');
    });
};

module.exports = {
    console
}

Включите файл logger.js из любого файла, в который вы хотите добавить console.log, например:

      const console = require('./utils/logger').console;

Создайте папку журналов, создайте в ней пустой файл server.log и запустите приложение :)

Вы также можете взглянуть на этот модуль npm: https://www.npmjs.com/package/noogger

noogger

просто и прямо вперед...

На основе многопараметрической версии Клемана , только без цветовых кодов для текстового файла.

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

console.log = function () {
  // Storing without color codes
  logFile.write(util.format.apply(null,arguments).replace(/\033\[[0-9;]*m/g,"") + '\n');
  // Display normally, with colors to Stdout
  logStdout.write(util.format.apply(null, arguments) + '\n');
}

Примечание: отвечаю, так как не могу комментировать

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

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;

Я просто собираю пакет для этого, надеюсь, вам понравится;) https://www.npmjs.com/package/writelog

Я для себя просто взял пример с Уинстона и добавил 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') { (если вы хотите, чтобы это также в производстве)...

Решение Rudy Huynh сработало для меня очень хорошо. Я добавил немного, чтобы он выдавал файлы с сегодняшней датой и временем.

      var dateNow = new Date();
var timeNow = dateNow.getHours() + '-' + dateNow.getMinutes();
var logPath = "log/" + dateNow.toDateString() + ' -' + ' Start Time - ' + timeNow + ".log"

consoleLogToFile({
logFilePath: logPath
});

Это не очень элегантно, но таким образом он будет сохранять разные, легко читаемые файлы журналов, а не просто обновлять один и тот же файл «default.log».

Другие вопросы по тегам