My Logo

PUBLISHED APRIL 25, 2024

Teghen Donald Ticha
Lastly Updated: 3 months ago
Reading time 14 mins

Writing Outputs to the Command Line in NodeJS

Learn essential techniques for writing outputs in nodeJS CLI. From basic logging to formatting and understanding stdout/stderr.
Writing Outputs to the Command Line in NodeJS

Prerequisite

Before carrying on with this part, it's helpful to have a basic understanding of JavaScript and nodeJS fundamentals.

Familiarity with terminal commands and navigating the command line interface is recommended but not required!

Additionally, it's recommended to start from the beginning of this chapter although it's not required.

Introduction

In the world of nodeJS development, logging and displaying output in the command line interface (CLI) is fundamental.

Whether it's for debugging, providing feedback to users, or monitoring the progress of tasks, a good mastery of writing outputs to the command line is essential.

In this introductory guide, we'll explore various techniques and tools for writing outputs to the command line in node, covering everything from basic logging with the console module to advanced features like progress bars and colored output.

Terminal Output

Before diving into the techniques for writing outputs to the command line in nodeJS, it's crucial to understand the significance of terminal output in the development process.

The CLI serves as the primary interface for interacting with nodeJS applications during development, testing, and deployment.

Logging messages, displaying errors, and providing status updates via the command line are indispensable for troubleshooting issues, tracking progress, and ensuring a smooth user experience.

NodeJS provides a console module which provides tons of very useful ways to interact with the command line.

Basic Output Using the Console Module

The `console` module in nodeJS provides essential functionality for writing output to the command line interface (CLI).

The console object is a global object, that provides(among other things) methods for writing output to the console. It serves as a versatile tool for debugging, logging messages, and monitoring application behavior during development.

The most basic and most used methods is console.log(), and console.error() which print the object you pass to it to the console.

  • console.log() method is the most commonly used for displaying messages to the console. It accepts multiple arguments of various types and automatically converts them to strings.
    Additionally, it supports string interpolation using placeholders (%s, %d, %j) for formatting complex messages.
console.log("Hello, world!"); // Output: Hello, world!
console.log("The value is %d", 42); // Output: The value is 42
console.log("My Object is: %j", { key: 13 }); // Output: My Object is: {"key":"value"}


  • console.error() method is specifically designed for logging error messages. It functions similarly to console.log() but typically displays error messages with a distinctive formatting or color to highlight their importance.
    This method is useful for logging critical errors that require immediate attention.
console.error(new Error('error occured!')); // Outputs: Error: error occured!
                                            // at Object.<anonymous> (/Users/donaldteghen/Desktop/play/play.js:2:15)
                                            // at Module._compile (node:internal/modules/cjs/loader:1376:14)
                                            // at Module._extensions..js (node:internal/modules/cjs/loader:1435:10)
                                            // at Module.load (node:internal/modules/cjs/loader:1207:32)
                                            // at Module._load (node:internal/modules/cjs/loader:1023:12)
                                            // at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:135:12)
                                            // at node:internal/main/run_main_module:28:49
                                            
console.error('A Severe Error occured!') // Outputs: A Severe Error occured!


Formating options

Use placeholders (`%s`, `%d`, `%j`) in the message string to interpolate variables or values into the output.

  • %s format a variable as a string
  • %d format a variable as a number
  • %i format a variable as its integer part only
  • %o format a variable as an object
  • %j format JavaScript objects as JSON strings.

Formatting with Styles

This allows for customizing the appearance of messages with colors, background colors, font styles, etc.

console.log("\x1b[32m%s\x1b[0m", "Success!"); // Output: Success! (in green color)

Breakdown:

  • \x1b[32m is the ANSI escape code for setting text color to `green`.
  • %s is a placeholder for the string "Success!".
  • \x1b[0m is the ANSI escape code for resetting text formatting to default.

For a complete list, check out this guide ANSI Escape Sequence.

Clearing the Console

Clearing the console is a handy technique for maintaining a clean and organized command line interface. It allows developers to focus on the most relevant information and avoid clutter.

The console.clear() method clears all previous output from the console, providing a fresh slate for new messages.

This can be particularly useful when running scripts or applications with extensive output, as it helps keep the console tidy and facilitates easier debugging.

const LIMIT = 50;

for (let i = 1; i <= LIMIT; i++) {
    console.log(`Logging line ${i}`);
    if (i === LIMIT) {
        console.log('Clearing the console in \x1b[31m%s!\x1b[0m', '2s' );
        setTimeout(console.clear, 2000);
    }
}

Logs 50 times to the console, then schdules timer that clears the console after 2 seconds.

Counting Elements

Counting elements in the console output is a useful technique for tracking occurrences of specific events or conditions during program execution.

console.count()

This method increments the counter associated with a specified label and logs the label along with the current count to the console.

This allows you to monitor the frequency of certain events and identify patterns or anomalies in the application behavior.

const LIMIT = 50;

for (let i = 1; i <= LIMIT; i++) {    
    if (i % 2 === 0) {
        console.count('EVEN');
    } 
    else {
        console.count('ODD');
    }
}


Resetting Counting

Resetting counting in the console output allows you to start counting from a specified value, providing flexibility in tracking events or conditions.

console.countReset():

This method resets the count associated with a specific `label` back to `zero`.

This is useful when developers need to reset the count and start tracking the occurrences of an event or condition from the beginning.

const LIMIT = 10;

for (let i = 1; i <= LIMIT; i++) {    
    if (i % 2 === 0) {
        console.count('EVEN');
    } 
    else {
        console.count('ODD');
    }
}

console.log('\n ***** Resetting count for the label :EVEN: ********\n')
console.countReset('EVEN'); 
console.count('EVEN'); // EVEN: 1
console.count('ODD'); // ODD: 26

Printing the Stack Trace

There might be cases where it's useful to print the call stack trace of your code to figure out how the execution reached that part of the code.

console.trace():

This method outputs the current call stack to the console, including function calls and their respective locations in the code.

This helps us identify the sequence of function calls leading to a specific point in the code and diagnose issues such as unexpected behavior or errors.

function func() {
    console.trace();
}
func();


You get something similar to what we have below, this in your console. Obviously the directory paths will be different.

Trace
    at func (/Users/donaldteghen/Desktop/play/play.js:2:13)
    at Object.<anonymous> (/Users/donaldteghen/Desktop/play/play.js:4:1)
    at Module._compile (node:internal/modules/cjs/loader:1376:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1435:10)
    at Module.load (node:internal/modules/cjs/loader:1207:32)
    at Module._load (node:internal/modules/cjs/loader:1023:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:135:12)
    at node:internal/main/run_main_module:28:49


Calculating Time Spent

Measuring the time spent in specific blocks of code is crucial for performance optimization and understanding the efficiency of algorithms or operations.

console.time() & console.timeEnd():

These methods provide a convenient way to measure the elapsed time between two points in the code.

By wrapping the code to be measured between these two methods, we can accurately track the execution time and identify potential bottlenecks.

For example:


function task (limit) {
    let eventCount = 0;
    for (let i = 1; i <= limit; i++) {    
        if (i % 2 === 0) {
            eventCount++ ;
        }         
    }
    console.log(`There are ${eventCount} even numbers between 0 and ${limit}`)
}

function tester () {
    const _limit = Math.round(Math.random() * 10000);
    for (let x = 1; x < 10; x++) {
        console.log(`\n ********** Run number ${x}: limit is ${_limit} ********** `)
        console.time("Timer");
        task(_limit);
        console.timeEnd("Timer");
    }
}

tester();

When you run the code, you get different time lapses for each run for various reasons. Play around with this code to find out exactly and perhabs start a discussion in the comment section 😉.


stdout and stderr

Understanding the concepts of standard output (stdout) and standard error (stderr) streams is essential for managing different types of output in nodeJS applications.

  1. 1.stdout: The stdout stream is used for normal program output. It typically displays information, warnings, or other non-error messages to the console.
  2. 2.stderr: The stderr stream is reserved for error messages and warnings. Unlike stdout, stderr is typically displayed with a different formatting or color to distinguish it from regular output.


Streams are not covered in this series, but you can read more on it from the official documentation.

console.error prints to the stderr stream.

It will not appear in the console, but it will appear in the error log.

NB: To use stderr and stdout, we use the node `process` object like so:

process.stdout.write("This is stdout message\n"); // Output: This is stdout message
process.stderr.write("This is stderr message\n"); // Output: This is stderr message


Creating a Progress Bar

Progress bars provide visual feedback on the completion status of tasks, enhancing the user experience by indicating the progress of ongoing operations.

  • Popular Libraries:
    • cli-progress: A popular library for creating customizable progress bars in the command line interface. It offers various styling options, such as bar characters, colors, and progress update intervals.
    • progress: Another library for creating progress bars, offering similar functionality to cli-progress with customizable features and options.


Let's have some examples:

1. With progress

const ProgressBar = require('progress');

// util function that consumes resources
function randomTask () {
    const evenArray = [];
    const limit = Math.random() * 300000;
    for (let i = 0; i < limit; i++) {
        if (i % 2 === 0) {
            evenArray.push(i);
        }
    }
    return evenArray.length;
}

// define the format of the progress bar
const barFormat = '[:bar] :percent :etas';

// create a new progress bar instance with the defined format and total number of steps
const progressBar = new ProgressBar(barFormat, { total: 100 });

// update the progress bar incrementally
const timer = setInterval(() => {
  progressBar.tick(); // increment the progress bar
  randomTask()
  if (progressBar.complete) {
    clearInterval(timer); // stop the timer when the progress bar reaches 100%
  }
}, 100); // bar progress interval

In this example, the progress bar will increment with each tick until it reaches 100%.

You can adjust the format and total number of steps according to your specific needs.

2. Using cli-progress

const ProgressBar = require('cli-progress');

// util function that consumes resources
function randomTask () {
    const evenArray = [];
    const limit = Math.random() * 30000000;
    for (let i = 0; i < limit; i++) {
        if (i % 2 === 0) {
            evenArray.push(i);
        }
    }
    return evenArray.length;
}


// create a new progress bar instance and customize its appearance
const progressBar = new ProgressBar.SingleBar({
  format: '{bar} {percentage}% | ETA: {eta}s | {value}/{total}'
});

// start the progress bar
progressBar.start(100, 0);

// update the progress bar incrementally
for (let i = 0; i <= 100; i++) {
  progressBar.update(i);
  randomTask()
}

// stop the progress bar when the task is complete
progressBar.stop();

Coloring Console Output

Coloring console output is a powerful technique for visually distinguishing different types of messages and enhancing readability in the command line interface.

  • Ways to achieve this?
    • ANSI Escape Codes: ANSI escape codes allow us to apply colors and formatting to console output by inserting special control characters into the message strings.
      These codes are supported by most modern terminals and command line interfaces.
    • Color Libraries: There are also libraries available, such as chalk, colors, and kleur, that provide an easy-to-use API for coloring console output.
      These libraries offer a wide range of predefined colors and formatting options, making it simple to apply styles to messages.


Quick example using ANSI escpase code VS chalk

const chalk = require('chalk');


// Example of coloring console output using ANSI escape codes
console.log("\x1b[31mError!\x1b[0m"); // Output: Error! (in red color)
console.log("\x1b[36mInfo\x1b[0m: This is an informational message."); // Output: Info: This is an informational message. (in cyan color)


// Example of coloring console output using the chalk library
console.log(chalk.red('Error!')); // Output: Error! (in red color)
console.log(chalk.green('Success!')); // Output: Success! (in green color)
NB: For CJS module, use chalk@4.1.2


Obviously, using ANSI escape codes is the low-level way to do this and it's quick inconvinient.
The simplest way to go about coloring the console output is by using a library like `chalk`. In addition to coloring, it also helps with other styling facilities, like making text bold, italic or underlined.


Conclusion

Uderstanding and mastering concepts around writing outputs to the command line interface in nodeJS is essential for effective development, debugging, and user interaction.

Throughout this guide, we've explored various techniques and tools for managing console output, from basic logging with the console module to advanced features like progress bars and formatted output.

By leveraging these techniques and understanding the nuances of stdout, stderr, and formatting options, you can enhance the readability, usability, and visual appeal of console output in their node applications.

Whether you're a beginner or an experienced developer, honing your skills in writing outputs to the command line will undoubtedly contribute to your success in node application development.

In the next part, we'll discuss "Reading Inputs from the command line".

All Chapter Parts for NodeJs In Theory, An absolute Beginner’s Overview
  1. Chapter 1 , Part 1 : Introduction to NodeJS

    In this series part, I introduce nodeJS and some technical concepts associated with it. I also show how easy it is to setup and start a simple nodeJS web server.

  2. Chapter 1 , Part 2 : How to Install and Setup NodeJS

    In this series part, I run you through the various ways to install nodeJS. I also discuss how to install nvm and use it to switch between different node versions.

  3. Chapter 1 , Part 3 : How much JavaScript do you need to learn NodeJS

    In this series part, we explore the nuanced relationship between JavaScript and NodeJS, highlighting some subtle distinctions between the two environments.

  4. Chapter 1 , Part 4 : The v8 Engine and the difference Between NodeJS and the browser

    In this series part, we explore the V8 engine and how it interacts with nodeJS. We also discuss node’s event loop and uncover the mystery behinds node’s ability to handle concurrent operations.

  5. Chapter 1 , Part 5 : NPM, the NodeJS package manager

    Discover the essentials of npm, the powerful package manager for Node.js. Learn installation, management, publishing, and best practices

  6. Chapter 1 , Part 6 : NodeJS in Development Vs Production

    Explore how Node.js behaves differently in development and production environments. Learn key considerations for deploying Node.js applications effectively.

  7. Chapter 2 , Part 1 : Asynchronous Flow Control

    In this series part, we'll explore various aspects of asynchronous flow control in Node.js, from basic concepts to advanced techniques.

  8. Chapter 2 , Part 2 : Blocking vs Non-blocking I/O

    Explore the differences between blocking and non-blocking I/O in Node.js, and learn how to optimize performance and scalability.

  9. Chapter 2 , Part 3 : Understanding NodeJS Event loop

    Exploring the Node.js event loop by understanding its phases, kernel integration, and processes enabling seamless handling of asynchronous operations in your applications.

  10. Chapter 2 , Part 4 : The NodeJS EventEmitter

    Explore the power of Node.js EventEmitter: an essential tool for building scalable and event-driven applications. Learn how to utilize it effectively!

  11. Chapter 3 , Part 1 : Working with files in NodeJS

    Gain comprehensive insights into file management in Node.js, covering file stats, paths, and descriptors, to streamline and enhance file operations in your applications.

  12. Chapter 3 , Part 2 : Reading and Writing Files in NodeJS

    Uncover the fundamentals of reading and writing files in nodeJS with comprehensive examples and use cases for some widely used methods.

  13. Chapter 3 , Part 3 : Working with Folders in NodeJS

    Unlock the secrets of folder manipulation in Node.js! Explore essential techniques and methods for working with directories efficiently

  14. Chapter 4 , Part 1 : Running NodeJS Scripts

    Master the command line interface for executing nodeJS scripts efficiently. Learn common options and best practices for seamless script execution

  15. Chapter 4 , Part 2 : Reading Environment Variables in NodeJS

    Learn how to efficiently manage environment variables in nodeJS applications. Explore various methods and best practices for security and portability

  16. Chapter 4 , Part 3 : Writing Outputs to the Command Line in NodeJS

    Learn essential techniques for writing outputs in nodeJS CLI. From basic logging to formatting and understanding stdout/stderr.

  17. Chapter 4 , Part 4 : Reading Inputs from the Command Line in NodeJS

    Learn the various ways and strategies to efficiently read command line inputs in nodeJS, making your program more interactive and flexible.

  18. Chapter 4 , Part 5 : The NodeJS Read, Evaluate, Print, and Loop (REPL)

    Explore the power of nodeJS's Read, Evaluate, Print, and Loop (REPL). Learn how to use this interactive environment for rapid prototyping, debugging, and experimentation.

  19. Chapter 5 , Part 1 : Introduction to Testing in NodeJS

    Discover the fundamentals of testing in nodeJS! Learn about testing types, frameworks, and best practices for building reliable applications.

  20. Chapter 5 , Part 2 : Debugging Tools and Techniques in NodeJS

    Explore essential debugging tools and techniques in Node.js development. From built-in options to advanced strategies, and best practices for effective debugging.

  21. Chapter 6 , Part 1 : Project Planning and Setup

    Discuss the planning and design process for building our interactive file explorer in Node.js, focusing on core features, UI/UX design, and implementation approach and initial setup.

  22. Chapter 6 , Part 2 : Implementing Basic functionalities

    In this guide, we'll implement the basic functionalities of our app which will cover initial welcome and action prompts.

  23. Chapter 6 , Part 3 : Implementating Core Features and Conclusion

    In this guide, we'll complete the rest of the more advanced functionalities of our app including, create, search, sort, delete, rename and navigate file directories.