Elegant Console Logs With Consola

Murtuzaali Surti
Murtuzaali Surti

• 3 min read

Console logs are not always well structured and eye-pleasing. Unpleasant and messy console takes away from the bliss of a developer. I recently came across a package named consola which does exactly this — making consoles meaningful and elegant.

It has browser support, pausing and resuming logs, prompt support and other useful features.

Installation #

You can install it by using npm, yarn or pnpm.

npm i consola

Trying it out

Spin up a new node/express app and start exploring.

Basics #

For a quick hands on experience, in your node application, throw an explicit error and then log it with the help of consola.

import { consola } from "consola"

try {
    throw Error("Unexpected error")
} catch (error) {
    consola.error(error)
}

consola.error("Error...")
consola.info("Info...")
consola.warn("Warning...")
consola.log("Logged...")

New Instance #

You can create a new consola instance with the help of the createConsola method and use that instead of the default global instance.

import { createConsola } from "consola"

const logger = createConsola({
    level: 0, // error/fatal logs
    fancy: true,
    formatOptions: {
        date: true,
        columns: 20
    },
})

logger.info("Info...") // this WON'T work
logger.error("Error...") // this will work

Set the log level to selectively allow only certain types of logs. Log level of 0 means only FATAL and ERROR logs are logged. The default log level is 3.

Reporters #

Reporters are representations of logs in the terminal. Consola (v3.2.3) provides 3 reporters out of the box, namely, basic, fancy and browser. They are configured based on log levels on the global consola instance.

To add a custom reporter to your newly created instance, you can use the reporters property which is an array of reporters.

import { LogLevels, consola, createConsola } from "consola"

const infoLogger = createConsola({
    fancy: true,
    formatOptions: {
        date: true,
        columns: 20
    },
    reporters: [
        {
            log: (log) => {
                if (log.level === LogLevels.info) {
                    consola.info(JSON.stringify({
                        date: new Date().toLocaleString("default", { dateStyle: "full" }),
                        logs: new Array().concat(log.args.map((l, i) => `${l}${i < log.args.length - 1 ? `,` : ``}`)).join(" "),
                    }, null, 4))
                } else {
                    consola.error(
                        new Error("invalid log method")
                    )
                }
            }
        }
    ]
})

Now, when you use any logging method on this instance, it will only log for the info method and throw an error for other methods. You just created a custom info message logger which you can further modify however you want.

// for the above instance
infoLogger.error("Won't work")
infoLogger.info("Will work") ✔️

Multiple reporters per instance are also supported allowing you to separate logs into desired representations.

reporters: [
    {
        log: (log) => {
            if (log.level === LogLevels.info) {
                consola.info(JSON.stringify({
                    date: new Date().toLocaleString("default", { dateStyle: "full" }),
                    logs: new Array().concat(log.args.map((l, i) => `${l}${i < log.args.length - 1 ? `,` : ``}`)).join(" "),
                }, null, 4))
            } else {
                consola.error(
                    new Error("invalid log method")
                )
            }
        }
    },
    {
        log: (log) => {
            createConsola({
                fancy: true,
                formatOptions: {
                    date: false
                }
            }).log(log)
        }
    }
]

Methods such as addReporter, setReporters and removeReporter are available to handle reporters for an instance.

Wrapping native console method with consola instance #

Doing so will redirect all the native console.log calls to the specified consola instance.

infoLogger.wrapConsole()
// consola instance `infoLogger` will print the table
console.table(["Info", "Second Info"])

restoreConsole will restore the native functionality of console.log and won't redirect to consola instance.

There are several util methods present in consola/utils which you can use to further customize the logs.

Prompts #

Prompts are supported in consola with the help of clack, a tool to build command-line apps. Check this out for some prompt examples in consola.

Conclusion

Correctly and elegantly representing console logs is an important task if you want to improve developer productivity and consola helps you with just that.


Sharing Localhost From VS Code - Port Forwarding

Previous

App Defaults 2023 — What I use

Next