151

My node.js application has a lot of console logs, which are important for me to see (it's quite a big app so runs for a long time and I need to know that things are still progressing) but I'm ending up with thousands of lines of console logs.

Is it somehow possible to do a console.update that erases/replaces a console line rather than creating a new line?

JVG
  • 20,198
  • 47
  • 132
  • 210
  • 1
    Why not write to a log file that you can monitor or search? – Nelson Jun 26 '13 at 00:35
  • 3
    I can do that easily enough in PowerShell, but it's more that I have about 5,000 lines of console being written that could easily take up 10 lines (most of it is just calls that let me know that things are progressing, which is important as the app runs for about 20min and I need feedback on whether things are breaking/still running). – JVG Jun 26 '13 at 00:38
  • Does this answer your question? [How to erase characters printed in console](https://stackoverflow.com/questions/11600890/how-to-erase-characters-printed-in-console) – Wex Mar 15 '20 at 03:30

8 Answers8

191

Try playing with process.stdout methods instead on console:

process.stdout.write("Hello, World");
process.stdout.clearLine(0);
process.stdout.cursorTo(0);
process.stdout.write("\n"); // end the line

TypeScript: clearLine() takes -1, 0, or 1 as a direction parameter with the following meanings:

-1: to the left from cursor.
0: the entire line.
1 - to the right from cursor

Matthew Rideout
  • 7,330
  • 2
  • 42
  • 61
michelek
  • 2,380
  • 1
  • 13
  • 15
  • 12
    TypeError: process.stdout.clearLine is not a function. Can't be run in webstorm if anyone else encounters this. – Trevor Apr 18 '18 at 13:39
  • @TrevorD my approach to this was to add a `webstorm=true` in Application parameters in webstorm node configuration and check for `process.argv.find(x => x.startsWith('webstorm=true')` using this answer – Luiz Eduardo Oct 26 '18 at 20:28
  • 2
    @Luiz Eduardo Would it not be simpler to just wrap in `if (process.stdout.clearLine) { process.stdout.clearLine() }` ? – Trevor Oct 26 '18 at 20:49
  • Good catch! For some reason, I didn't even think of that. As I was building a little simple tool to run in the console, I didn't give it a thorough though, but I'll definitely change it, thanks! – Luiz Eduardo Oct 27 '18 at 21:29
  • I would do this: `node -e "for(let i=1;i<=1000;i++){process.stdout.write('Hello, World'); if(i<10)process.stdout.clearLine(); process.stdout.cursorTo(0);}"` or `node -e "for(let i=1;i<=1000;i++){process.stdout.clearLine(); process.stdout.cursorTo(0); process.stdout.write('hello, world')}"` – Cerberus Nov 08 '18 at 21:05
  • @Trevor, I wrote a comment below regarding that error - https://stackoverflow.com/a/55893009/836723 – Maksim Shamihulau Sep 23 '19 at 13:32
  • 1
    This is what solved my problem when I got 'TypeError: process.stdout.clearLine is not a function': https://stackoverflow.com/a/34570694/3411285 – José Manuel Blasco Jan 05 '22 at 16:39
92

Following @michelek's answer, you can use a function somewhat like this:

function printProgress(progress){
    process.stdout.clearLine(0);
    process.stdout.cursorTo(0);
    process.stdout.write(progress + '%');
}
Maxime Lafarie
  • 2,172
  • 1
  • 22
  • 41
Bruno Peres
  • 2,980
  • 1
  • 21
  • 19
  • 1
    When using this with a for loop, it is flickering, is there any way to fix this? – Ank i zle Jan 18 '20 at 20:33
  • 3
    to fix flicker, get rid of `process.stdout.clearLine()` – buycanna.io Mar 13 '20 at 13:21
  • 1
    i realized adding this to a large loop increases the calculation time drasticallyyyy. For example I am running 100mil random tries and assigning to variables. It should take 3 seconds. with this function. it takes like a minute – Mohamed Aljamil Jul 03 '20 at 06:07
  • 4
    nevermind my above comment. I guess all console logs cost a lot. and Since I was trying to print a progress by percentage I had to write a function that only prints on certain intervals like 1% 2% etc – Mohamed Aljamil Jul 03 '20 at 06:22
35

Sure, you can do this using a module I helped create: fknsrs/jetty

Install via

npm install jetty

Here's a usage example

// Yeah, Jetty!
var Jetty = require("jetty");

// Create a new Jetty object. This is a through stream with some additional
// methods on it. Additionally, connect it to process.stdout
var jetty = new Jetty(process.stdout);

// Clear the screen
jetty.clear();

// write something
jetty.text("hello world");
jetty.moveTo([0,0]);
jetty.text("hello panda");

Jetty is not super useful when used on it's own. It is much more effective when you build some abstraction on top of it to make your jetty calls less verbose.

Mulan
  • 129,518
  • 31
  • 228
  • 259
  • 6
    I downvoted this because of the restrictive license on this package. – mmmeff Nov 10 '18 at 18:25
  • 40
    It's a standard [BSD 3-clause licsense](https://opensource.org/licenses/BSD-3-Clause). Pretty bad reason for a down-vote, imo. – Mulan Nov 10 '18 at 20:09
  • 14
    @mmmeff, if you think a BSD 3-clause license is restrictive, I fear you'll die when you hear about GPL and AGPL licenses. – Michael Pfaff Apr 18 '20 at 22:20
28

Just use \r to terminate your line:

process.stdout.write('text\r');

Here's a simple example (wall clock):

setInterval(() => process.stdout.write(`clock: ${new Date()}\r`), 1000);
Bart Theeten
  • 551
  • 6
  • 6
  • 2
    This works, but if the 'changed' line is shorter than the previous line, it will keep some of the old characters in the terminal. – Matthijn Sep 25 '20 at 13:24
  • This is awesome. Anyone know how this works? – Raphael Rafatpanah Aug 12 '21 at 23:32
  • 5
    @RaphaelRafatpanah pretty simple: `\r` means carriage return. After `\r` the cursor goes to line start, so the previous output will be overriden by new. – khokm Aug 26 '21 at 23:55
16

To write a partial line.

process.stdout.write('text');
process.stdout.write('more');
process.stdout.write('\n'); // end the line

If the volume of output is the real issue then you'll probably to rethink your logging. You could use a logging system that allows selective runtime logging to narrow your output to what you need.

// The sections we want to log and the minimum level
var LOG_LEVEL = 4;
var LOG_SECTIONS = ['section1', 'section2', 'section3'];

function logit(msg, section, level) {
  if (LOG_SECTIONS.includes(section) && LOG_LEVEL >= level) {
    console.log(section + ':' + msg);
  }
}

logit('message 1', 'section1', 4); // will log
logit('message 2', 'section2', 4); // will log
logit('message 3', 'section3', 2); // wont log, below log level
logit('message 4', 'section4', 4); // wont log, not in a log section
TheBotlyNoob
  • 369
  • 5
  • 16
SpliFF
  • 38,186
  • 16
  • 91
  • 120
7

We can use log-update

const logUpdate = require('log-update');
logUpdate('this will be gone');
logUpdate('this will stay');
Praveen Kumar
  • 181
  • 2
  • 6
6

if you see stdout exceptions like TypeError: process.stdout.clearLine is not a function in Debug Console window of Visual Studio Code (or Webstorm), run the app as external terminal application instead of internal console. The reason is that Debug Console window is not TTY (process.stdout.isTTY is false). Therefore update your launch configuration in launch.json with "console": "externalTerminal" option.

Maksim Shamihulau
  • 1,219
  • 1
  • 15
  • 17
4

Among others, the answer by @michelek does the trick. However, when you start using this, you may run into Exception trouble when output gets redirected to a file or you are in a debugger or running in a linux screen-session, etc. You may see messages such as process.stdout.clearLine is not a function.

Therefore, at least add a test to check that the output is a 'TTY' and is able to do such things as 'clearLine()' and 'cursorTo()':

if (process.stdout.isTTY) {
   process.stdout.write("Hello, World");
   process.stdout.clearLine(0);
   process.stdout.cursorTo(0);
   process.stdout.write("\n"); // end the line
}
anneb
  • 5,510
  • 2
  • 26
  • 26