Explore Console in Nodejs

Learn about the fundamentals of Console in NodeJs

Chidume Nnamdi 🔥💻🎵🎮
Bits and Pieces

--

Console is the most widely used utility in web development, starting from the browser to Nodejs and v8’s d8 shell. It is the most used debugging tool after alert — remember it? :) I personally used alert during my beginner days in web development. That time, after writing a script in my E71 phone, I used alert to add breakpoints so as to know where an error occurred, why a particular block of code isn’t executed or so many other things I want to check.

So when I bought a laptop, I discovered the Devtools after some time, though I still used alert, and the console.log(…) API, that was it, till today I still use console.log(…) for debugging.

In this post, we will look deep into the Console class in Nodejs and its methods to see how to use them.

Tip: Use Bit (GitHub) for your components. It will help you organize, share and reuse them between apps to build faster. It’s also fun to discover your components in a visual collection, try the playground and install in the code.

Console class

To use the console.log we simply write console.log() without importing any Console lib or anything. This is because the console instance has been initialized and present in the process object.

We are able to print to our terminal because the console is initialized with a stream pointing to the terminal:

new Console(process.stdout, process.stderr)

process.stdout is used for printing to the screen in Nodejs and process.stderr is used for printing error messages to the screen.

The Console class API is generally like this

Console(stdout, [stderr])

The first argument points to the stream where we want to print our messages.

The stream might be a terminal.

Like we said earlier, console.log and other console methods (console.*) print to our terminal because the console object is an instance of Console configured to print to process.stdout. process.stdout is a method in Nodejs process object that is used to print to the screen. It can be used like this:

process.stdout.write("Hello Nnamdi")
// Hello Nnamdi
process.stdout.write("Hello Nodejs")
// Hello Nodejs
process.stdout.write("Hello JS")
// Hello JS
process.stdout.write("Hello v8")
// Hello v8

The process.stdout's write(...) method is what is called with params we want to print to screen.

So, it is passed to Console class like this:

global.console = new Console(process.stdout, proces.stderr)

In the Console class, it is implemented like this:

function Console(stdout, stderr) {
this.stdout = stdout
this.stderr = stderr ? stderr : stdout
}
Console.prototype.log = function (whatToWrite) {
this.write(whatToWrite, this.stdout)
}
Console.prototype.error = function (whatToWrite) {
this.write(whatToWrite, this.stderr)
}
Console.prototype.write = function (whatToWrite, stream) {
stream.write(whatToWrite)
}

When we pass in process.stdout to Console (new Console(process.stdout)), its write method will be called in the Console.prototype.write method to print the params contained in whatToWrite to the screen.

So when we do this:

const log = new Cosnole(process.stdout, process.stderr)
log.log("Hello Nnamdi")
  1. this.stdout in Console is set to process.stdout
  2. On calling log.log with “Hello Nnamdi”, whatToWrite becomes “Hello Nnamdi” and this.write is called with (process.stdout, “Hello World”)
  3. in the write method, whatToWrite is “Hello Nnamdi” and stream becomes process.stdout. So stream.write(WhatToWrite) becomes process.stdout.write(“Hello Nnamdi”)
  4. “Hello Nnamdi” is printed on our terminal

The stream might be a file

A file stream can be printed to. We pass in a stream to a file to the Console class.

Let’s say we have a file we want to write messages or log our output to. First, we create a stream to the file:

const fsStream = fs.createWritestream('./log.log')

Our file is log.log, we created a writable stream to it using fs's createWriteStream API.

We can create another stream we can log our error report:

const errfsStream = fs.createWritestream('./error.log')

We can now pass the two streams to the Console class:

const log = new Console(fsStream, errfsStream)

When we call log.log("logging an input to ./log.log"), it won't print it to the screen, rather it will write the message to the ./log.log file in your directory.

//...
log.log("logging an input to ./log.log")

Nothing will be printed on our screen. Check in your current directory, you will see ./log.log file, open it you will see the message " logging an input to ./log.log" written in it.

If you log an error:

//...
log.error("This an error message")

Again, there will be no output on the screen. Check for error.log file in your current directory. Open it, you will see "This an error message" written in it.

The WriteStream that fs.createWriteStream(…) returns doesnt print to screen rather it writes to a file. We can use the fs.createWriteStream(…) standalone to write to our files:

const l = fs.createWriteStream('./log.log')
l.write("Message from the Konsole")

The WriteStream has a write method which enables the Console to write to the file via its write method.

We can plug fs.createWriteStream(…) into our custom Console class above and it will work:

function Console(stdout, stderr) {
this.stdout = stdout
this.stderr = stderr ? stderr : stdout
}
Console.prototype.log = function (whatToWrite) {
this.write(whatToWrite, this.stdout)
}
Console.prototype.error = function (whatToWrite) {
this.write(whatToWrite, this.stderr)
}
Console.prototype.write = function (whatToWrite, stream) {
stream.write(whatToWrite)
}
const l = new Console(fs.createWriteStream('./log.log'))
l.log('Hi, from a custom Console class')

Now, let’s look at the methods in the Console class.

assert(value[, message][, …args])

This method is a testing method that allows us to create tests on the fly in our code without having to deal with all those testing libraries available. With assert, we can test statements in our code to know where logic failed so we can trace it.

// csl.js
let number1 = 2;
let number2 = 3;
let result;
result = number1 + number2;console.assert(result == 5, "`result` should be 5")
console.log(result)

See the above code, we have two numbers, number1 and number2 each initialized to 2 and 3 respectively. We performed addition on the numbers, the result will be stored in the result var. Then we set up a test using the console.assert to make sure the result of the addition is 5. If the result is not equal to 5 an Assertion error is thrown on our console. Though the error doesn't halt the executing of a script the execution flow continues. This method just tells us where our tests failed so to aid in debugging.

If we run the code above, we will get the below in our terminal:

Admin@PHILIPSZDAVIDO MINGW64 /c/wamp/www/developerse/projects/trash
$ node csl
5

You see no error, the assert test console.assert(result == 5, "'result' should be 5") passed, so no error message is shown on the screen.

Let’s touch our code to throw an error:

// csl.jsconst c = consolelet number1 = 2;
let number2 = 3;
let result;
result = number1 + number2;c.assert(result == 55, "result should be 55")
c.log(result)

Now, testing that the result should be equal to 55, we know that won’t happen because after the addition result will have 5 so an assertion error will be thrown.

Admin@PHILIPSZDAVIDO MINGW64 /c/wamp/www/developerse/projects/trash
$ node csl
Assertion failed: result should be 55
5

See an error was thrown stating that result should be 55. The execution didn’t cut there, it continued to print the value of the result var.

NOTE: Assert method general method is this: assert(value[, message][, ...args])

  • value: The truthy boolean checked. If false, error is thrown.
  • message: The message to be shown on the screen when the test fails.

clear()

This method is used to clear the terminal. When you have to many messages in your terminal, you can run console.clear() to remove all those messages. It is like running cls in Windows cmd and clear in bash.

count([label])

This method is used to set the number of times a certain string label is called with the method.

c.count('sys')Admin@PHILIPSZDAVIDO MINGW64 /c/wamp/www/developerse/projects/trash
$ node csl
sys: 1

You see we passed in a string sys, being only called with the string sys it outputs 1. Let's see what will happen if we continually call it with the sys string.

c.count('sys')
c.count('sys')
c.count('sys')
c.count('sys')
Admin@PHILIPSZDAVIDO MINGW64 /c/wamp/www/developerse/projects/trash
$ node csl
sys: 1
sys: 2
sys: 3
sys: 4

We called the method with the sys string four times in our script. That’s why we saw sys: 4 in the end telling us that the method encountered sys four times.

The string defaults to default, this means that when the method is called with no string, the string is chosen to be default by the method.

c.count()Admin@PHILIPSZDAVIDO MINGW64 /c/wamp/www/developerse/projects/trash
$ node csl
default: 1

This method is useful in debugging to know how many times a function/method is called and how many times a code was executed.

countReset([label=’default’])

This method resets the count of the label set by calling the console.count method.

c.count('sys')
c.count('sys')
c.count('sys')
c.countReset('sys')
c.count('sys')
$ node csl
sys: 1
sys: 2
sys: 3
sys: 1

See we called sys three times, then we called the countReset with the sys stirng, then the next count('sys') will print 1 (instead of 3) because countReset('sys') reset the counter of three to 1.

debug(data[, …args])

Same as console.log.

error([data][, …args])

This method is used for printing errors in the terminal. This prints in the stderr pipe to display the error messages.

c.error("error message")Admin@PHILIPSZDAVIDO MINGW64 /c/wamp/www/developerse/projects/trash
$ node csl
error message

group([…label])

This method adds indentation to the label passed to it.

c.group("error message")
c.group("error message")
Admin@PHILIPSZDAVIDO MINGW64 /c/wamp/www/developerse/projects/trash
$ node csl
error message
error message

You see the label error message was printed with two spaces in the last group call.

groupCollapsed()

Same as group

groupEnd()

This method collapses the label passed to it by two spaces.

c.group("error message")
c.group("error message")
c.groupEnd()
c.groupEnd()
c.groupEnd()
c.group("error message")
Admin@PHILIPSZDAVIDO MINGW64 /c/wamp/www/developerse/projects/trash
$ node csl
error message
error message
error message

info([data][, …args])

Same as log

log([data][, …args])

This the general method used to prints messages to the screen. This method uses stdout to display the message.

let animal = "Lions"
c.log('I like %d', animal)
c.log('I like ', animal)
c.log(`I like ${animal}`)
c.log("I like " + animal)
Admin@PHILIPSZDAVIDO MINGW64 /c/wamp/www/developerse/projects/trash
$ node csl
I like Lions
I like Lions
I like Lions
I like Lions

numbers: %d

let num = 10
c.log('I like number %d', num)
Admin@PHILIPSZDAVIDO MINGW64 /c/wamp/www/developerse/projects/trash
$ node csl
I like number 10

string: %s

let animal = "Lions"
c.log('I like %s', animal)
Admin@PHILIPSZDAVIDO MINGW64 /c/wamp/www/developerse/projects/trash
$ node csl
I like Lions

float: *f

c.log("PI: %f", 22/7)

integer: %i

c.log("Integer: %f", 2 * (22/7))

object: %o

const o = {val: 90}
c.log("o object: %o", o)

css styles: %c

c.log("CSS styles: %c", 'color:green: top: 90px')

time(label)

This method is used in profiling. It starts a timer identified by a unique label used to compute the duration of an operation in milliseconds.

timeEnd(label)

This method is used in conjunction with the above time method. This stops the timer started by the time method based on a particular label.

c.time("timer start")for(var i = 0; i < 90;i++) {}c.timeEnd("timer start")Admin@PHILIPSZDAVIDO MINGW64 /c/wamp/www/developerse/projects/trash
$ node csl
timer start: 24.536ms

See we started a timer with the label timer start using the time method. When we call the timeEnd with the same label timer start this will stop the timer start timer and display the time that passed between them. In the above example, it took 24.536 ms for the empty for loop to execute.

trace([message][, …args])

This method is used to print the stack of execution up to the current position.

function one() {
console.log("one function")
}
function two() {
console.log("two function")
}
one()
two()
c.trace('two executed')
Admin@PHILIPSZDAVIDO MINGW64 /c/wamp/www/developerse/projects/trash
$ node csl
one function
two function
Trace: two executed
at Object.<anonymous> (C:\wamp\www\developerse\projects\trash\csl.js:24:3)
at Module._compile (internal/modules/cjs/loader.js:678:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:689:10)
at Module.load (internal/modules/cjs/loader.js:589:32)
at tryModuleLoad (internal/modules/cjs/loader.js:528:12)
at Function.Module._load (internal/modules/cjs/loader.js:520:3)
at Function.Module.runMain (internal/modules/cjs/loader.js:719:10)
at startup (internal/bootstrap/node.js:228:19)
at bootstrapNodeJSCore (internal/bootstrap/node.js:575:3)

This function is very useful in debugging. See the execution stared from the base of Nodejs ‘s internal files:

  • internal/bootstrap/
  • internal/modules/

up to our file csl.js.

warn([data][, …args])

This is used to print warning messages on the screen. This is the same as the error method.

table(array[, columns])

This method is used to display array in a formatted table style.

c.table([90, 67, 45])Admin@PHILIPSZDAVIDO MINGW64 /c/wamp/www/developerse/projects/trash
$ node csl
┌─────────┬────────┐
│ (index) │ Values │
├─────────┼────────┤
│ 0 │ 90 │
│ 1 │ 67 │
│ 2 │ 45 │
└─────────┴────────┘

:) Nice huh?

Conclusion

In this post, we looked at the different methods in the Console class. Which one do you find most useful and interesting? Lemme know in the comments :)

If you have any question regarding this or anything I should add, correct or remove, feel free to comment, email or DM me

Thanks !!!

Learn More

--

--

JS | Blockchain dev | Author of “Understanding JavaScript” and “Array Methods in JavaScript” - https://app.gumroad.com/chidumennamdi 📕