consola icon indicating copy to clipboard operation
consola copied to clipboard

Async log function

Open Sparticuz opened this issue 10 months ago • 2 comments

Describe the feature

I'm attempting to write certain log levels to a database, but that requires async/await compatibility on the log function. It doesn't appear to support that, but I can't find any info on that.

import { createConsola, type LogObject } from "consola";

import database, { auditTable } from "@/database";

const databaseReporter = {
  log: async (logObject: LogObject) => {
    if (logObject.type === "trace") {
      console.log("in trace");
      await database.insert(auditTable).values({
        data: JSON.stringify({ message: "test" }),
        databaseTableName: "test",
        dateStamp: logObject.date,
        operation: "TEST",
        primaryKeyFields: "",
        primaryKeyValue: "0",
        userId: "TEST",
      });
    }
    console.log({ ...logObject, reporter: "database" });
  },
};

export const consola = createConsola({
  level: 5,
  // Keep default reporters and add our database reporter
  reporters: [
    // This gives you the nice console output
    {
      log: (logObj) => {
        console.log(JSON.stringify(logObj));
      },
    },
    // This handles database writing
    databaseReporter,
  ],
});

Additional information

  • [ ] Would you be willing to help implement this feature?

Sparticuz avatar Feb 27 '25 17:02 Sparticuz

Currently your code just works, except that the consola.log won't await.

Do you want consola.log to be asynchronously blocking?

kricsleo avatar Mar 21 '25 07:03 kricsleo

There is usually no async/await support for loggers, because most of those are stream-based and allow for more creative performance optimisation (like logging through a worker thread in Pino), having a log function sometimes return a promise is not a good design either

As a result, you might experience data loss on service shutdown(or in a short-lived environment like AWS Lambda)

To work around this, you could wrap your async call as a Writable stream, and wait for it to be drained at the end of your service life-cycle

You can take a look at my custom implementation with DataDog https://github.com/marklai1998/datadog-logger-integrations?tab=readme-ov-file#use-the-stream-directly

and how to drain the stream here: https://github.com/marklai1998/datadog-logger-integrations?tab=readme-ov-file#usage-with-lambda

marklai1998 avatar May 25 '25 20:05 marklai1998