Creating a pretty console for your NodeJS Applications, using colors and icons (TypeScript Version)

Simone Scigliuzzi
8 min readNov 12, 2022

--

Days ago, I was working on a NodeJS project, incredibly full of console messages: logs, warning, errors, etc… But they where appearing all equals to each other in my VSCode terminal.

So, I’ve decided to create a simple JS to have a prittier and more colored console. I’ve used different colors and icons for any kind of console message, and the groups to group message by type… and this is the result

prettyConsole result

I shared my work with you in this article https://medium.com/@simonescigliuzzi/creating-a-pretty-console-for-your-nodejs-applications-81a713353554

Here you have the TypeScript version of that class: PrettyConsole!

Let’s create our prettyConsole

Save the following code into a ./src/prettyConsole.ts file

export class PrettyConsole {
public closeByNewLine: boolean;
public useIcons: boolean;
public logsTitle: string;
public warningsTitle: string;
public errorsTitle: string;
public informationsTitle: string;
public successesTitle: string;
public debugsTitle: string;
public assertsTitle: string;

constructor() {
this.closeByNewLine = true;
this.useIcons = true;
this.logsTitle ='LOGS';
this.warningsTitle = 'WARNINGS';
this.errorsTitle = 'ERRORS';
this.informationsTitle = 'INFORMATIONS';
this.successesTitle = 'SUCCESS';
this.debugsTitle = 'DEBUG';
this.assertsTitle = 'ASSERT';
}

private getColor(foregroundColor: string = '', backgroundColor: string = ''): string {
let fgc = '\x1b[37m'
switch (foregroundColor.trim().toLowerCase()) {
case 'black':
fgc = '\x1b[30m'
break;
case 'red':
fgc = '\x1b[31m'
break;
case 'green':
fgc = '\x1b[32m'
break;
case 'yellow':
fgc = '\x1b[33m'
break;
case 'blue':
fgc = '\x1b[34m'
break;
case 'magenta':
fgc = '\x1b[35m'
break;
case 'cyan':
fgc = '\x1b[36m'
break;
case 'white':
fgc = '\x1b[37m'
break;
}

let bgc = ''
switch (backgroundColor.trim().toLowerCase()) {
case 'black':
bgc = '\x1b[40m'
break;
case 'red':
bgc = '\x1b[44m'
break;
case 'green':
bgc = '\x1b[44m'
break;
case 'yellow':
bgc = '\x1b[43m'
break;
case 'blue':
bgc = '\x1b[44m'
break;
case 'magenta':
bgc = '\x1b[45m'
break;
case 'cyan':
bgc = '\x1b[46m'
break;
case 'white':
bgc = '\x1b[47m'
break;
}

return `${fgc}${bgc}`
}
private getColorReset(): string {
return '\x1b[0m'
}
print(foregroundColor: string = 'white', backgroundColor: string = 'black', ...strings: any) {
const c = this.getColor(foregroundColor, backgroundColor)
// turns objects into printable strings
strings = strings.map((item) => {
if (typeof item === 'object') item = JSON.stringify(item)
return item
})
console.log(c, strings.join(''), this.getColorReset())
if (this.closeByNewLine) {
console.log('')
}
}
clear(): void {
console.clear()
}
log(...strings: any): void {
const fg = 'white'
const bg = ''
const icon = '\u25ce'
const groupTile = ` ${this.logsTitle}`
if (strings.length > 1) {
const c = this.getColor(fg, bg)
console.group(c, (this.useIcons ? icon : '') + groupTile)
const nl = this.closeByNewLine
this.closeByNewLine = false
strings.forEach((item) => {
this.print(fg, bg, item, this.getColorReset())
})
this.closeByNewLine = nl
console.groupEnd()
if (nl) {
console.log()
}
} else {
this.print(fg, bg, strings.map((item) => {
return `${(this.useIcons ? `${icon} ` : '')}${item}`
}))
}
}
warn(...strings: any): void {
const fg = 'yellow'
const bg = ''
const icon = '\u26a0'
const groupTile = ` ${this.warningsTitle}`
if (strings.length > 1) {
const c = this.getColor(fg, bg)
console.group(c, (this.useIcons ? icon : '') + groupTile)
const nl = this.closeByNewLine
this.closeByNewLine = false
strings.forEach((item) => {
this.print(fg, bg, item, this.getColorReset())
})
this.closeByNewLine = nl
console.groupEnd()
if (nl) {
console.log()
}
} else {
this.print(fg, bg, strings.map((item) => {
return `${(this.useIcons ? `${icon} ` : '')}${item}`
}))
}
}
error(...strings: any): void {
const fg = 'red'
const bg = ''
const icon = '\u26D4'
const groupTile = ` ${this.errorsTitle}`
if (strings.length > 1) {
const c = this.getColor(fg, bg)
console.group(c, (this.useIcons ? icon : '') + groupTile)
const nl = this.closeByNewLine
this.closeByNewLine = false
strings.forEach((item) => {
this.print(fg, bg, item)
})
this.closeByNewLine = nl
console.groupEnd()
if (nl) {
console.log()
}
} else {
this.print(fg, bg, strings.map((item) => {
return `${(this.useIcons ? `${icon} ` : '')}${item}`
}))
}
}
info(...strings: any): void {
const fg = 'blue'
const bg = ''
const icon = '\u2139'
const groupTile = ` ${this.informationsTitle}`
if (strings.length > 1) {
const c = this.getColor(fg, bg)
console.group(c, (this.useIcons ? icon : '') + groupTile)
const nl = this.closeByNewLine
this.closeByNewLine = false
strings.forEach((item) => {
this.print(fg, bg, item)
})
this.closeByNewLine = nl
console.groupEnd()
if (nl) {
console.log()
}
} else {
this.print(fg, bg, strings.map((item) => {
return `${(this.useIcons ? `${icon} ` : '')}${item}`
}))
}
}
success(...strings: any): void {
const fg = 'green'
const bg = ''
const icon = '\u2713'
const groupTile = ` ${this.successesTitle}`
if (strings.length > 1) {
const c = this.getColor(fg, bg)
console.group(c, (this.useIcons ? icon : '') + groupTile)
const nl = this.closeByNewLine
this.closeByNewLine = false
strings.forEach((item) => {
this.print(fg, bg, item)
})
this.closeByNewLine = nl
console.groupEnd()
if (nl) {
console.log()
}
} else {
this.print(fg, bg, strings.map((item) => {
return `${(this.useIcons ? `${icon} ` : '')}${item}`
}))
}
}
debug(...strings: any): void {
const fg = 'magenta'
const bg = ''
const icon = '\u1367'
const groupTile = ` ${this.debugsTitle}`
if (strings.length > 1) {
const c = this.getColor(fg, bg)
console.group(c, (this.useIcons ? icon : '') + groupTile)
const nl = this.closeByNewLine
this.closeByNewLine = false
strings.forEach((item) => {
this.print(fg, bg, item)
})
this.closeByNewLine = nl
console.groupEnd()
if (nl) {
console.log()
}
} else {
this.print(fg, bg, strings.map((item) => {
return `${(this.useIcons ? `${icon} ` : '')}${item}`
}))
}
}
assert(...strings: any): void {
const fg = 'cyan'
const bg = ''
const icon = '\u0021'
const groupTile = ` ${this.assertsTitle}`
if (strings.length > 1) {
const c = this.getColor(fg, bg)
console.group(c, (this.useIcons ? icon : '') + groupTile)
const nl = this.closeByNewLine
this.closeByNewLine = false
strings.forEach((item) => {
this.print(fg, bg, item)
})
this.closeByNewLine = nl
console.groupEnd()
if (nl) {
console.log()
}
} else {
this.print(fg, bg, strings.map((item) => {
return `${(this.useIcons ? `${icon} ` : '')}${item}`
}))
}
}
}

In your code, import the prettyConsole class, create an instance, then clear the console, and initialize a couple of properties

import { PrettyConsole } from './classes/prettyConsole.ts'
const prettyConsole = new PrettyConsole();
prettyConsole.clear();
prettyConsole.closeByNewLine = true;
prettyConsole.useIcons = true;

Both properties “closeByNewLine”, and “useIcons” are true as default. So these two lines are redundant, but useful to show how they work. The first one “tells” prettyConsole to print a blank line after a single message, and to close a group of message. The second one enables the icon to prepend each group title.

Let’s print some messages!

prettyConsole has 8 methods. You’ve already see the clear() method. Obiviously this is used to clear the console.
The other methods are meant to print different kind of messages. So, we have the log, info, success, warn, error, debug, assert methods

prettyConsole.log('this is a log message');
prettyConsole.info('this is a info message');
prettyConsole.success('this is a success message');
prettyConsole.warn('this is a warning message');
prettyConsole.error('this is an error message');
prettyConsole.debug('this is a debug message');
prettyConsole.assert('this is an assert message');

Let’s create groups of messages!

To group messages you only have to send more messages at the same time. Let’s take a look to the following sample

prettyConsole.warn('this is a warning message');
prettyConsole.warn('this the 1st warning of a group', 'this is the 2nd warning of a group');

The messages grouping works with all methods except the clear method.
So, here for you the full example (that results into the first image you saw above in this article)

import { PrettyConsole } from './classes/prettyConsole.ts';
const prettyConsole = new PrettyConsole();

prettyConsole.clear();
prettyConsole.closeByNewLine = true;
prettyConsole.useIcons = true;
prettyConsole.log('this is a log message');
prettyConsole.log('this the 1st log of a group', 'this is the 2nd log of a group');
prettyConsole.info('this is a info message');
prettyConsole.info('this the 1st info of a group', 'this is the 2nd info of a group');
prettyConsole.success('this is a success message');
prettyConsole.success('this the 1st success of a group', 'this is the 2nd success of a group');
prettyConsole.warn('this is a warning message');
prettyConsole.warn('this the 1st warning of a group', 'this is the 2nd warning of a group');
prettyConsole.error('this is an error message');
prettyConsole.error('this the 1st error of a group', 'this is the 2nd error of a group');
prettyConsole.debug('this is a debug message');
prettyConsole.debug('this the 1st debug of a group', 'this is the 2nd debug of a group');
prettyConsole.assert('this is an assert message');
prettyConsole.assert('this the 1st assert of a group', 'this is the 2nd assert of a group');

What if we’d need more color combinations?

No problem! prettyConsole also has a method print that allows you to specify the foreground color, the background one, and the text or group of messages to print.

prettyConsole.print('red', 'yellow', 'Hola! This is my red text on a yellow background');

The available colors, for both foreground and background:

  • black
  • red
  • green
  • yellow
  • blue
  • magenta
  • cyan
  • white

but you can also specify an empty string as color, so to use your default — foreground or background — console color

prettyConsole.print('blue', '', 'This is only blue');

What about additional icons?

You can certainly customize your console messages with icons! The only thing you have to do is find out the unicode symbol coresponding to your desired icon, and insert it into your message’s text.

To do that, I refer the web site https://unicode-table.com/.
Here you can search for any icon, and find out its coresponding unicode char. Let’s see an example!

Assume we’re lookin’ for a star icon.

Once you found it, just copy its unicode (just the part after U+) and paste it into your text, prepending it with a \u, as the following example

prettyConsole.print('yellow', '', '\u2606 This is my shining Star!');

More examples with icons

prettyConsole.print('red', '', '\u2665 I Love coding!');
prettyConsole.print('green', '', '\u2705 Test Passed!');
prettyConsole.print('blue', '', '\u270c Good Luck!');
prettyConsole.print('magenta', '', '\u27a4 Take a look at this');

Would you like to customize group titles?

Using prettyConsole in my projects, I needed to group a group of console messages by topic: presenting them as error, but with a different group-title. So, I’ve introduced the following properties:

  • logsTitle
  • warningsTitle
  • errorsTitle
  • informationsTitle
  • successesTitle
  • debugsTitle
  • assertsTitle

These poperties are used by the PrettyConsole Class to title each group, an their default values are: ‘LOGS’, ‘WARNINGS’, ‘ERRORS’, ‘INFORMATIONS’, ‘SUCCESS’, ‘DEBUG’, ‘ASSERT’.

So, now you can do something like this

prettyConsole.clear();
prettyConsole.logsTitle = 'Stages';
prettyConsole.info('Please, select an API Gateway Stage');
prettyConsole.useIcons = false;
prettyConsole.log(...stages);

We’re done for today!

I hope this article is useful for you.
If you have any questions or suggestions, please feel free to contact me.
Finally, if you liked this article, please click “Follow” on my name at the top of this page.

Greetings! Simone

--

--

Simone Scigliuzzi

Hello, I am Simone Scigliuzzi, Developer. Web, APP, and Software Developer since 2000's: Software, Web Portals, SPA, Mobile APPs, DataBase, and more...