Blog
logger in storybook codebase.

logger in storybook codebase.

In this article, we review logger in storybook codebase. We will look at:

  1. client-logger.ts file.

I study patterns used in an open source project found on Github Trending. For this week, I reviewed some parts of Storybook codebase and wrote this article.

client-logger.ts file

logger

In storybook/code/core/src/client-logger.ts, you will find the following code:

export const logger = {
  trace: (message: any, ...rest: any[]): void => {
    if (currentLogLevelNumber <= levels.trace) {
      console.trace(message, ...rest);
    }
  },
  debug: (message: any, ...rest: any[]): void => {
    if (currentLogLevelNumber <= levels.debug) {
      console.debug(message, ...rest);
    }
  },
  info: (message: any, ...rest: any[]): void => {
    if (currentLogLevelNumber <= levels.info) {
      console.info(message, ...rest);
    }
  },
  warn: (message: any, ...rest: any[]): void => {
    if (currentLogLevelNumber <= levels.warn) {
      console.warn(message, ...rest);
    }
  },
  error: (message: any, ...rest: any[]): void => {
    if (currentLogLevelNumber <= levels.error) {
      console.error(message, ...rest);
    }
  },
  log: (message: any, ...rest: any[]): void => {
    if (currentLogLevelNumber < levels.silent) {
      console.log(message, ...rest);
    }
  },
} as const;

Here is an example, demonstrated in storybook/code/core/src/theming/ensure.ts

import { logger } from 'storybook/internal/client-logger';
...
  const missing = deletedDiff(light, input);
    if (Object.keys(missing).length) {
      logger.warn(
        dedent`
            Your theme is missing properties, you should update your theme!
  
            theme-data missing:
          `,
        missing
      );
    }

once

once is another method defined to show a log only once:

const logged = new Set();
export const once =
  (type: keyof typeof logger) =>
  (message: any, ...rest: any[]) => {
    if (logged.has(message)) {
      return undefined;
    }
    logged.add(message);
    return logger[type](message, ...rest);
  };

once.clear = () => logged.clear();
once.trace = once('trace');
once.debug = once('debug');
once.info = once('info');
once.warn = once('warn');
once.error = once('error');
once.log = once('log');

pretty

pretty is defined in the same file as shown below:

export const pretty =
  (type: keyof typeof logger) =>
  (...args: Parameters<LoggingFn>) => {
    const argArray: Parameters<LoggingFn> = [] as any;

    if (args.length) {
      const startTagRe = /<span\s+style=(['"])([^'"]*)\1\s*>/gi;
      const endTagRe = /<\/span>/gi;

      let reResultArray;
      argArray.push(args[0].replace(startTagRe, '%c').replace(endTagRe, '%c'));

      while ((reResultArray = startTagRe.exec(args[0]))) {
        argArray.push(reResultArray[2]);
        argArray.push('');
      }

      // pass through subsequent args since chrome dev tools does not (yet) support console.log styling of the following form: console.log('%cBlue!', 'color: blue;', '%cRed!', 'color: red;');

      for (let j = 1; j < args.length; j++) {
        argArray.push(args[j]);
      }
    }

    // eslint-disable-next-line prefer-spread
    logger[type].apply(logger, argArray);
  };

pretty.trace = pretty('trace');
pretty.debug = pretty('debug');
pretty.info = pretty('info');
pretty.warn = pretty('warn');
pretty.error = pretty('error');

About me:

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

Email: ramu.narasinga@gmail.com

Study the patterns used in large OSS projects at Think Throo.

References:

  1. https://github.com/storybookjs/storybook/blob/next/code/core/src/client-logger/index.ts#L58

  2. https://github.com/storybookjs/storybook/tree/next/code/core/src/client-logger

  3. https://github.com/storybookjs/storybook/blob/next/code/core/src/theming/ensure.ts#L1