Log Levels

The default logger uses the info log level which will make sure to log only info+ logs. Available log levels are:

  • false (disables logging altogether)
  • trace
  • debug
  • info default
  • warn
  • error

Lazy Arguments and Performance

Hive Logger supports "lazy" attributes for log methods. If you pass a function as the attributes argument, it will only be evaluated if the log level is enabled and the log will actually be written. This avoids unnecessary computation for expensive attributes when the log would be ignored due to the current log level.

import { Logger } from "@graphql-hive/logger";

const log = new Logger({ level: "info" });

log.debug(
  // This function will NOT be called, since 'debug' is below the current log level.
  () => ({ expensive: computeExpensiveValue() }),
  "This will not be logged",
);

log.info(
  // This function WILL be called, since 'info' log level is set.
  () => ({ expensive: computeExpensiveValue() }),
  "This will be logged",
);

Change on Creation

When creating an instance of the logger, you can configure the logging level by configuring the level option. Like this:

import { Logger } from "@graphql-hive/logger";

const log = new Logger({ level: "debug" });

log.trace(
  // you can suply "lazy" attributes which wont be evaluated unless the log level allows logging
  () => ({
    wont: "be evaluated",
    some: expensiveOperation(),
  }),
  "Wont be logged and attributes wont be evaluated",
);

log.debug("Hello world!");

const child = log.child("[prefix] ");

child.debug("Child loggers inherit the parent log level");

Outputs the following to the console:

2025-04-10T14:00:00.000Z DBG Hello world!
2025-04-10T14:00:00.000Z DBG [prefix] Child loggers inherit the parent log level

Change Dynamically

Alternatively, you can change the logging level dynamically during runtime. There's two possible ways of doing that.

Using log.setLevel(level: LogLevel)

One way of doing it is by using the log's setLevel method.

import { Logger } from "@graphql-hive/logger";

const log = new Logger({ level: "debug" });

log.debug("Hello world!");

const child = log.child("[prefix] ");

child.debug("Child loggers inherit the parent log level");

log.setLevel("trace");

log.trace(() => ({ hi: "there" }), "Now tracing is logged too!");

child.trace("Also on the child logger");

child.setLevel("info");

log.trace("Still logging!");

child.debug("Wont be logged because the child has a different log level now");

child.info("Hello child!");

Outputs the following to the console:

2025-04-10T14:00:00.000Z DBG Hello world!
2025-04-10T14:00:00.000Z DBG [prefix] Child loggers inherit the parent log level
2025-04-10T14:00:00.000Z TRC Now tracing is logged too!
  hi: "there"
2025-04-10T14:00:00.000Z TRC [prefix] Also on the child logger
2025-04-10T14:00:00.000Z TRC Still logging!
2025-04-10T14:00:00.000Z INF Hello child!

Using LoggerOptions.level Function

Another way of doing it is to pass a function to the level option when creating a logger.

import { Logger } from "@graphql-hive/logger";

let isDebug = false;

const log = new Logger({
  level: () => {
    if (isDebug) {
      return "debug";
    }
    return "info";
  },
});

log.debug("isDebug is false, so this wont be logged");

log.info("Hello world!");

const child = log.child("[scoped] ");

child.debug(
  "Child loggers inherit the parent log level function, so this wont be logged either",
);

// enable debug mode
isDebug = true;

child.debug("Now debug is enabled and logged");

Outputs the following:

2025-04-10T14:00:00.000Z INF Hello world!
2025-04-10T14:00:00.000Z DBG [scoped] Now debug is enabled and logged