Blog
logger.ts in Motia.dev codebase.

logger.ts in Motia.dev codebase.

In this article, we review logger.ts in Motia.dev codebase. We will look at:

  1. logger class

  2. prettyPrint function

  3. colors.js package

Press enter or click to view image in full size

logger class

You will find the following code in packages/core/src/logger.ts.

export class Logger {
  /**
   * Why do we need two level of listeners?
   *
   * Core listeners pass along to children loggers.
   *
   * However, base listeners do not pass along to children loggers.
   * Those are specific to each logger in the hierarchy.
   */
  private readonly listeners: LogListener[] = []

  constructor(
    readonly isVerbose: boolean = false,
    private readonly meta: Record<string, unknown> = {},
    private readonly coreListeners: LogListener[] = [],
  ) {}

  child(meta: Record<string, unknown>): Logger {
    return new Logger(this.isVerbose, { ...this.meta, ...meta }, this.coreListeners)
  }

  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  private _log(level: string, msg: string, args?: any) {
    const time = Date.now()
    const meta = { ...this.meta, ...(args ?? {}) }
    prettyPrint({ level, time, msg, ...meta }, !this.isVerbose)
    this.coreListeners.forEach((listener) => listener(level, msg, meta))
    this.listeners.forEach((listener) => listener(level, msg, meta))
  }

  info(message: string, args?: unknown) {
    if (isInfoEnabled) {
      this._log('info', message, args)
    }
  }

  error(message: string, args?: unknown) {
    this._log('error', message, args)
  }

  debug(message: string, args?: unknown) {
    if (isDebugEnabled) {
      this._log('debug', message, args)
    }
  }

  warn(message: string, args?: unknown) {
    if (isWarnEnabled) {
      this._log('warn', message, args)
    }
  }

  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  log(args: any) {
    this._log('info', args.msg, args)
  }

  addListener(listener: LogListener) {
    this.listeners.push(listener)
  }
}

export const globalLogger = new Logger()

_log function is reused and accepts parameters as shown below:

private _log(level: string, msg: string, args?: any) {

Here, depending on the level, prettyPrint function applies a color to a text.

prettyPrint function

You will find prettyPrint function in packages/core/src/pretty-print.ts and it is defined as shown below:

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const prettyPrint = (json: Record<string, any>, excludeDetails = false): void => {
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
  const { time, traceId, msg, flows, level, step, ...details } = json
  const levelTag = levelTags[level]
  const timestamp = timestampTag(`[${new Date(time).toLocaleTimeString()}]`)
  const objectHasKeys = Object.keys(details).length > 0

  console.log(`${timestamp} ${traceIdTag(traceId)} ${levelTag} ${stepTag(step)} ${msg}`)

  if (objectHasKeys && !excludeDetails) {
    console.log(prettyPrintObject(details))
  }
}

Here, levelTag is assigned a value based on level as shown below:

const levelTag = levelTags[level]

levelTags is defined at line #7 in pretty-print.ts as shown below:

const levelTags: Record<string, string> = {
  error: colors.red('[ERROR]'),
  info: colors.blue('[INFO]'),
  warn: colors.yellow('[WARN]'),
  debug: colors.gray('[DEBUG]'),
  trace: colors.gray('[TRACE]'),
}

colors.js package

get color and style in your node.js console

Press enter or click to view image in full size

Usage

By popular demand, colors now ships with two types of usages!

  1. The super nifty way
var colors = require('colors');
 
console.log('hello'.green); // outputs green text
console.log('i like cake and pies'.underline.red) // outputs red underlined text
console.log('inverse the color'.inverse); // inverses the color
console.log('OMG Rainbows!'.rainbow); // rainbow
console.log('Run the trap'.trap); // Drops the bass

2. or a slightly less nifty way which doesn’t extend String.prototype

var colors = require('colors/safe');
 
console.log(colors.green('hello')); // outputs green text
console.log(colors.red.underline('i like cake and pies')) // outputs red underlined text
console.log(colors.inverse('inverse the color')); // inverses the color
console.log(colors.rainbow('OMG Rainbows!')); // rainbow
console.log(colors.trap('Run the trap')); // Drops the bass

Learn more about colors.js package.

About me:

Hey, my name is Ramu Narasinga. I study codebase architecture in large open-source projects.

Email: ramu.narasinga@gmail.com

Want to learn from open-source? Solve challenges inspired by open-source projects.

References:

  1. https://github.com/MotiaDev/motia/blob/main/packages/core/src/logger.ts

  2. https://github.com/MotiaDev/motia/blob/main/packages/core/src/pretty-print.ts#L61

  3. https://www.npmjs.com/package/color