Произносится как «Реклама»…

Недавно у меня появилась возможность начать новый проект с нуля, где мы могли выбрать новые блестящие инструменты и фреймворки. Прежде всего, я не хочу преуменьшать, насколько это круто; жаль, что мы не можем делать это чаще. Во всяком случае, для ведения внешнего интерфейса я вспомнил, как бывший коллега упомянул этот проект с открытым исходным кодом Adze.



Что оно делает?

На первый взгляд Adze JS — это оболочка для консольного API браузера, в которой есть все те же команды, которые вы знаете и любите. Вечные хиты, такие как console.log или горько-сладкий console.error, даже культовый классический console.dir. Вы знаете их, так что я не буду говорить о них слишком много. Тем не менее, есть несколько концепций Adze более высокого уровня, которые действительно помогают уберечь ваш код от превращения в большого спагетти-монстра. Вот краткое описание этих понятий.

Сарай

Централизованное место (в вашем коде) для кэширования ваших журналов, обеспечения глобальной конфигурации, добавления любой фильтрации (т. е. игнорирование уровня журнала DEBUG) или переопределений (т. е. не включайте смайлики огня при регистрации необработанных исключений в рабочей среде):

import { adze, createShed } from 'adze';

const shed = createShed();

shed.addListener([1, 2, 3], ({ definition, timestamp, args }, render, printed) => {
  if (printed) {
    const log = {
      level: definition.level,
      name: definition.levelName,
      timestamp: timestamp.utc,
      args,
    };
    // You could now write it to a file, send it to a rest API, etc.
  }
});

Фабрики

Вся регистрация начинается с фабрики в Адзе. У меня не было возможности использовать их все, но основной называется просто adze :

const cfg = { useEmoji: true };

adze(cfg).log('A log with emoji enabled.');

Тематика

Adze предоставляет конфигурацию, которую вы можете передать на фабрику adze по умолчанию. Это позволяет вам изменить стиль журнала с атрибутами, подобными CSS:

const config = {
  logLevel: 8,
  useEmoji: true,
  logLevels: {
    log: {
      emoji: '🔥',
      style: 'padding-right: 5px; background: red; color: white; border-color: black;',
      terminal: ['bgRed', 'white'],    
    },
  }
};

adze(config).log("I'm red");

Модификаторы

Как следует из названия, вы можете изменить все, что собираетесь регистрировать. Такие функции, как timestamp, count и namespace, могут предоставить дополнительную информацию о том, что регистрируется.

adze().label('my-label').timestamp.log('my message');
// Output: Log(1) 2022-10-25T16:33:43-4:00 [my-label] my message

Цепочка

Как и было обещано, есть несколько концепций более высокого уровня, которые отличают Adze, и это, на мой взгляд, главное. Когда у вас есть фабрика или модификатор, он становится цепным API, что означает, что вы можете сделать что-то вроде этого:

adze().label('my-label').namespace('my-ns').timestamp.count.info("my info");
adze().label('my-label').namespace('my-ns').timestamp.count.info("my info");
// Output: 
// Info(1) 2022-10-25T16:33:43-4:00 #my-ns [my-label] (Count: 1) my info
// Info(1) 2022-10-25T16:33:44-4:00 #my-ns [my-label] (Count: 2) my info

Как разработчики используют его в типичном приложении?

Я собираюсь дать краткое изложение того, как я использовал Adze JS в приложении React Native + Typescript. Сначала я установил его как зависимость:

# NPM
$ npm install --save adze
# Yarn
$ yarn add adze

В моем примере я собираюсь создать класс, который обрабатывает всю логику регистрации и может быть расширен.

import { adze, createShed, Constraints } from 'adze';
import { Log } from 'adze/dist/log';
import { Shed } from 'adze/dist/shed';

export default class LoggerClass {
  shed: Shed;
  logger: Log<Constraints>;

  constructor() {
    this.shed = createShed();

    this.shed.addListener('*', (data, render, printed) => {
      if (printed) {
        // TODO: Send to AWS CloudWatch here
      }
    });

    const sealed = adze({
      logLevel: 8,
      useEmoji: true,
    }).seal();

    this.logger = sealed().namespace(new.target.name);
  }

  error(message: string): Error {
    this.logger.error(message);
    throw new Error(message);
  }

  logGroup(messages: string[]) {
    if (messages.length < 1) return;
    if (messages.length === 1) return this.logger.group.log(messages[0]);
    const [first, ...rest] = messages;
    this.logger.groupCollapsed.log(first);
    rest.forEach(this.logger.log);
    this.logger.groupEnd.log();
  }

  logTime(message: string) {
    this.logger.timeNow.log(message);
  }

  logAssert(assertion: boolean, message: string) {
    this.logger.assert(assertion).log(message);
  }

  logTable(tabularData: [{ [key: string]: any }]) {
    this.logger.table.log(tabularData);
  }
}

Затем я могу расширить этот класс и вести журнал без необходимости каждый раз выполнять кучу настроек:

import Deck from "./Deck";
import Square from "../types/Square";
import LoggerClass from "./LoggerClass";
import { CardArray, CardName } from "../types/CardName";

const DECK_SIZE = 54;
const NUM_ROWS = 4;
const NUM_COLUMNS = 4;


export default class Board extends LoggerClass {
  private squares: Square[];

  constructor() {
    super();

    if (CardArray.length !== DECK_SIZE) this.error('Not Enough Cards');
    this.squares = [];
    const arr: CardName[] = Deck.sortRandomly<CardName>([...CardArray]);
    for (let row = 1; row <= NUM_ROWS; row++) {
      for (let column = 1; column <= NUM_COLUMNS; column++) {
        this.squares.push({
          row,
          column,
          cardType: arr.pop(),
        });
      }
    }
  }
 ...
}

Это потрясающе, есть ли способ внести свой вклад в проект с открытым исходным кодом?

Если вы всегда мечтали включить в свое резюме вклад в проект с открытым исходным кодом, теперь это ваш шанс.



Список открытых вопросов находится здесь: https://github.com/AJStacy/adze/issues. Обязательно следуйте инструкциям по внесению вклада. Создайте форк и откройте мерж-реквест, когда будете готовы.