Вузол: увійдіть у файл замість консолі


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

Це гадно, що обслуговуючі не реагують на реагування. Я думав, що це підтримують люди Нодейджіцу. Ми використовували його на кількох сайтах, щодня перетягували понад мільйон переглядів сторінок і не мали жодних проблем із реєстрацією. Можливо, це має відношення до того, що реєструється, та кількості його.
— Райан Гіббонс

1
Схоже, станом на квітень 2015 року Вінстон оновлюється та отримує велику активність.
— Майк Грейс

180

Ви також можете просто перевантажити функцію 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)
— користувач603749

10
Чудова відповідь! Крім того, якщо ви хочете зафіксувати кілька аргументів console.log, просто захопіть об’єкт "Аргументи" замість "d" - developer.mozilla.org/en/docs/Web/JavaScript/Reference/…
— Чарлі

@AlexMills Привіт, можливо, ви можете навести приклад того, як саме це буде зроблено?
— Джонатан

6
але мені це потрібно мати у кожному js-файлі, чи можна зробити його глобальним?
— stackdave

60

Якщо ви шукаєте щось у виробництві, Вінстон - це, мабуть, найкращий вибір.

Якщо ви просто хочете зробити Dev речі швидко, виведіть безпосередньо у файл (я думаю, що це працює лише для * 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, і я мав аргументи, передані до процесу
— eran otzap

Який мінус робити це у виробництві?
— marcelino

1
До речі в залежності від вашої операційної системи, що «робити-що - то-о-он» може бути просто поворот журналу, який є хорошим рішенням ІМО - abdussamad.com/archives/541-Log-rotation-in-CentOS-Linux.html
— Ferr

58

Я часто використовую багато аргументів для 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

@Nigilan, як це ви виправили? Я стикаюся з тим же питанням.
— користувач2180794

@ 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

можна просто зберегти помилки?
— stackdave

Замість того, щоб перебирати 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

Для отримання додаткової інформації перегляньте цю суть .


Правильна відповідь.
— nikk wong

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 потоки 'введення', 'вихід' та 'помилка' ідентифікуються дескрипторами файлів додатних цілих чисел (0, 1, 2). тобто stdin дорівнює 0, stdout - 1, а stderr - 2.

'2> & 1' переспрямує з 2 (stderr) на 1 (stdout)

'>' буде перенаправляти з 1 (stdout) у файл (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;

Так. Вибачте. Мій поганий
— Simon Rigét

ви можете перезаписати властивості консолі на 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

Поліпшити Андреса Ріофріо, щоб обробити будь-яку кількість аргументів

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 Що ти маєш на увазі? Вінстон дуже гнучкий, ви можете налаштувати його ... Ви шукаєте ... github.com/winstonjs/winston#formats ?
— TechupBusiness
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.