Knoten: Melden Sie eine Datei anstelle der Konsole an


174

Kann ich konfigurieren console.log, dass die Protokolle in eine Datei geschrieben werden, anstatt in der Konsole gedruckt zu werden?


1
könnte, aber für Produktions-Apps mit langer Laufzeit wäre es schwierig, Protokolle für nur einen bestimmten Tag zu finden, oder? @racar

Antworten:


72

Update 2013 - Dies wurde um Node v0.2 und v0.4 herum geschrieben. Es gibt jetzt viel bessere Funktionen für die Protokollierung. Ich kann Winston nur empfehlen

Update Ende 2013 - Wir verwenden immer noch Winston, aber jetzt mit einer Logger-Bibliothek, um die Funktionalität um die Protokollierung von benutzerdefinierten Objekten und die Formatierung zu erweitern. Hier ist ein Beispiel unserer logger.js https://gist.github.com/rtgibbons/7354879


Sollte so einfach sein.

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, es bedeutet Prozess, denke ich ... Wie funktioniert das? console.log(whatever);geht immer noch zur Konsole, nicht zur Datei.
Trusktr

12
Aufgrund einer kürzlichen Änderung können Sie stderr.pipe () nicht mehr aufrufen - dies dauert jetzt:process.__defineGetter__('stderr', function() { return fs.createWriteStream(__dirname + '/error.log', {flags:'a'}) })
damianb

15
Persönlich würde ich mich von Winston fernhalten. Wir verwenden es seit über einem Jahr und haben uns schließlich entschlossen, es vollständig zu entfernen, da es viele Probleme in unserer Produktionsumgebung verursacht hat. Das Projekt scheint jetzt äußerst schlecht gepflegt zu sein. Es gibt eine Problemliste, solange Ihr Arm. Bei vielen Problemen wurden Pull-Anfragen von anderen Benutzern gesendet, aber die Projektbetreuer nehmen sich nicht einmal die Zeit, diese zusammenzuführen. Für Alternativen könnten Node-Bunyan und Raupe einen Blick wert sein.
UpTheCreek

Es ist schade, dass die Betreuer nicht reagieren. Ich dachte, es wurde von den Nodejitsu-Leuten gepflegt. Wir haben es auf mehreren Websites verwendet, um mehr als eine Million Seitenaufrufe pro Tag zu erzielen, und hatten keine Probleme mit der Protokollierung. Vielleicht hat es damit zu tun, was protokolliert wird und wie viel davon.
Ryan Gibbons

1
Es sieht so aus, als ob Winston ab April 2015 auf dem neuesten Stand ist und viel Aktivität erhält.
Mike Grace

178

Sie können auch einfach die Standardfunktion console.log überladen:

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

Das obige Beispiel protokolliert in debug.log und stdout.

Bearbeiten: Siehe Multiparameter-Version von Clément auch auf dieser Seite.


9
Ich würde mich nicht darum kümmern, console.log zu überschreiben. Erstellen Sie einfach Ihre eigene Funktion, die sich bei einer bestimmten Datei anmeldet.
Alexander Mills

Außerdem funktioniert dies nicht für mehrere Parameter. ZB console.log (p1, p2, p3)
user603749

10
Gute Antwort! Wenn Sie mehrere Argumente für console.log erfassen möchten, greifen Sie einfach auf das Objekt 'Arguments' anstelle von 'd' - developer.mozilla.org/en/docs/Web/JavaScript/Reference/…
Charlie

@AlexMills Hallo, vielleicht könnten Sie ein Beispiel dafür geben, wie genau das gemacht würde?
Jonathan

6
aber ich muss dies in jeder js-Datei haben, ist es möglich, es global zu machen?
Stackdave

60

Wenn Sie nach etwas in der Produktion suchen, ist Winston wahrscheinlich die beste Wahl.

Wenn Sie nur schnell Entwicklerarbeiten erledigen möchten, geben Sie diese direkt in eine Datei aus (ich denke, dies funktioniert nur für * nix-Systeme):

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

7
Die Verwendung >zum Umleiten von STDOUT funktioniert auch unter Windows. nohupnicht.
Brad

1
dies funktioniert glücklich ohne nohupon * nix, dh node simple-server.js > output.log. Dann, wenn Sie dem Protokoll folgen möchten, wie es gerade geschrieben wurdetail -f output.log
böse Pastete

Dies funktionierte nicht, als ich Argumente an den Prozess übergeben hatte
eran otzap

Was ist der Nachteil davon in der Produktion?
Marcelino

1
Übrigens, abhängig von Ihrem Betriebssystem, könnte dieses "etwas dagegen tun" einfach eine Protokollrotation sein, was eine gute Lösung ist - abdussamad.com/archives/541-Log-rotation-in-CentOS-Linux.html
ferr

58

Ich verwende oft viele Argumente für console.log () und console.error () , daher lautet meine Lösung:

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 ist ein sehr beliebtes npm-Modul, das zur Protokollierung verwendet wird.

Hier ist eine Anleitung.
Installieren Sie Winston in Ihrem Projekt als:

npm install winston --save

Hier ist eine sofort einsatzbereite Konfiguration, die ich in meinen Projekten häufig als logger.js unter Utils verwende.

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

Und dann einfach importieren, wo immer dies erforderlich ist:

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

Dann können Sie den Erfolg wie folgt protokollieren:

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

und Fehler als:

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

Außerdem werden alle Erfolgsprotokolle und Fehlerprotokolle in einer Datei im Protokollverzeichnis datumsweise protokolliert, wie Sie hier sehen können.
Protokollverzeichnis


Die Protokolle werden in der Konsole angezeigt. und keine Datei wird sofort erstellt !! Vermisse ich etwas
Nigilan

1
Könnten Sie möglicherweise Ihre Konfigurationen teilen? Oder hast du es benutzt, wie ich vorgeschlagen habe? Überprüfen Sie die Importe ( winston& winston-daily-rotate-file) einmal, wenn die Konfigurationen in Ordnung sind. Sie sollten in einem Ordner erstellt werden, der logsim Stammverzeichnis des Projekts benannt ist. Entschuldigen Sie die verspätete Antwort.
KeshavDulal

@ Nigilan wie hast du das behoben? Ich stehe vor dem gleichen Problem.
user2180794

@ user2180794 Schauen Sie sich meinen Kommentar über Nigilans Kommentar an. Lassen Sie uns wissen, wenn Sie es immer noch nicht schaffen.
KeshavDulal

1
Vergessen Sie nicht, diese zusätzlich zu logger-util hinzuzufügen. const winston = require('winston'); const winstonRotator = require('winston-daily-rotate-file'); Und const errorLog = require('../util/logger').errorlog; const successlog = require('../util/logger').successlog; wo immer Sie etwas protokollieren möchten.
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;

Um es zu benutzen, machen Sie etwas wie:

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

ist es nur möglich die erros zu retten?
Stackdave

Anstatt die Console.prototypeSchlüssel zu durchlaufen, setzen Sie sie nur explizit this.error.
Rich Remer

Dies bricht console.log?
G_V

Es bricht nicht console.log. Es ändert sein Verhalten, obwohl Sie das alte Verhalten durch Aufrufen wiederherstellen können console.file().
Rich Remer


6

Eine andere noch nicht erwähnte Lösung besteht darin, die WritableStreams in process.stdoutund einzubinden process.stderr. Auf diese Weise müssen Sie nicht alle Konsolenfunktionen überschreiben, die an stdout und stderr ausgegeben werden. Diese Implementierung leitet sowohl stdout als auch stderr in eine Protokolldatei um:

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

Es sollte in der Konsole gedruckt werden

a
b
c
d
e
f

und in der Protokolldatei:

c
d

Weitere Informationen finden Sie in dieser Übersicht .


Korrekte Antwort.
Nikk Wong

6

In einfachen Fällen könnten wir die Streams Standard Out (STDOUT) und Standard Error (STDERR) direkt durch '>' und '2> & 1' in die Datei umleiten.

Beispiel:

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

Knoten test.js> test.log 2> & 1

Gemäß dem POSIX-Standard werden die Streams "Eingabe", "Ausgabe" und "Fehler" durch die positiven Ganzzahl- Dateideskriptoren (0, 1, 2) identifiziert . dh stdin ist 0, stdout ist 1 und stderr ist 2.

'2> & 1' leitet von 2 (stderr) zu 1 (stdout) um

'>' leitet von 1 (stdout) in die Datei (test.log) um


5

Das Überschreiben von console.log ist der richtige Weg. Damit es jedoch in den erforderlichen Modulen funktioniert, müssen Sie es auch exportieren.

module.exports = console;

Um sich die Mühe zu ersparen, Protokolldateien, Rotationen und ähnliches zu schreiben, sollten Sie ein einfaches Logger-Modul wie Winston verwenden:

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

Ja. Es tut uns leid. Mein schlechtes
Simon Rigét

Sie können Konsoleneigenschaften für das globalObjekt überschreiben . warum module.exports?
r3wt

3

METHODE STDOUT UND STDERR

Dieser Ansatz kann Ihnen helfen (ich verwende in meinen Projekten etwas Ähnliches) und funktioniert für alle Methoden, einschließlich console.log, console.warn, console.error, console.info

Diese Methode schreibt die in stdout und stderr geschriebenen Bytes in die Datei. Ist besser als das Ändern der Methoden console.log, console.warn, console.error und console.info, da die Ausgabe genau der Ausgabe dieser Methoden entspricht


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)

Ich werde dies in meinem npm-Modul verwenden und Ihnen diesen Code zuweisen. Ist das cool?
r3wt

2

Direkt aus den API-Dokumenten von nodejs in der Konsole

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

Sie können jetzt Caterpillar verwenden , ein auf Streams basierendes Protokollierungssystem, mit dem Sie sich anmelden und die Ausgabe an verschiedene Transformationen und Speicherorte weiterleiten können.

Die Ausgabe in eine Datei ist so einfach wie:

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

Vollständiges Beispiel auf der Caterpillar-Website



0

Ich kam auf die Idee, den Ausgabestream gegen einen meiner Streams auszutauschen.

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

Verbessere Andres Riofrio, um mit einer beliebigen Anzahl von Argumenten umzugehen

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

Ich selbst habe einfach das Beispiel von Winston genommen und die log(...)Methode hinzugefügt (weil Winston sie benenntinfo(..) :

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;

Dann verwenden Sie einfach in Ihrem Code:

const console = require('Console')

Jetzt können Sie einfach die normalen Protokollfunktionen in Ihrer Datei verwenden und es wird eine Datei erstellt UND an Ihrer Konsole protokolliert (während des Debuggens / Entwickelns). Wegen if (process.env.NODE_ENV !== 'production') {(falls Sie es auch in der Produktion wollen) ...


Fügt Winston nicht eine Menge Müll wie "Nachricht" und die Protokollstufe hinzu?
G_V

@G_V Was meinst du? winston ist sehr flexibel, Sie können es konfigurieren ... suchen Sie ... github.com/winstonjs/winston#formats ?
TechupBusiness
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.