3

I am working on a game using NodeJs, and realized it would be immensly helpful to have access to old console.log output. The mechanics and calculations get rather complicated, and it would be nice to have access to them later to search through and do some data analysis on them to find the correct values for my modifiers (battle mechanics). At the same time, I want to see console.log in the console as well.


I know this isn't possible with regular javascript, (see This), but I was hoping npm had a package of some way to intercept logs and log them to a file on the server. Any thoughts?

Community
  • 1
  • 1
perennial_
  • 1,798
  • 2
  • 26
  • 41
  • So the end goal is to log to stdout *and* write to a file? Instead of trying to catch your `console.log` just make your own log method that writes to a file and stdout. Or, just use `tee` when you launch your application if you're in a *nix environment. – dvlsg Aug 19 '16 at 23:46
  • You can also use a program like forever to run your program and it will redirect console.log and console.err output to files automatically. – jfriend00 Aug 20 '16 at 03:38

3 Answers3

12

You can intercept console.log like so

var cl = console.log

console.log = function(...args){
  // your custom logging logic here
  cl.apply(console, args)
}
jshawl
  • 3,315
  • 2
  • 22
  • 34
6

An NPM option to log to stdout and to a file at the same time could be Winston. Winston is a logging library that allows you to define your own loggers, specifying their transports (a transport being what do you do with these log lines). In your case, you could define a logger with two transports, stdout and a log file. Example (inspired by the Winston documentation):

const winston = require('winston');

let logger = new (winston.Logger)({
    transports: [
        new (winston.transports.Console)(),
        new (winston.transports.File)({ filename: 'somefile.log' })
    ]
});

logger.info('hello, world!');

If you run this code above, you'll see the logs in the console and in somefile.log.

Mauri Edo
  • 377
  • 1
  • 7
2

The purest form would be by overriding stdout and stderr methods, e.g.

process.stdout.write = (data) => {
  w(data);
};

process.stderr.write = (data) => {
  w(data);
};

Here w is whatever mechanism that you would like to use to record this data, e.g.

const w = (...args) => {
  appendFileSync(
    path.resolve(__dirname, "test.json"),
    JSON.stringify(args, null, "  ")
  );
};

Beware that you cannot output anything from this function as that would cause an infinite loop.

The above behaviour would discard any output though. If you want the program to continue producing output, then you need to call the original write methods, e.g.

const stdoutWrite = process.stdout.write.bind(process.stdout);
const stderrWrite = process.stderr.write.bind(process.stderr);

process.stdout.write = (data, callback) => {
  w(data);

  return stdoutWrite(data, callback);
};

process.stderr.write = (data, callback) => {
  w(data);

  return stderrWrite(data, callback);
};
Gajus
  • 69,002
  • 70
  • 275
  • 438