Написание обертки для console.log для лучшего контроля в JavaScript, часть I

Речь пойдет не о различных вариантах ведения консольного журнала, а о попытке создать организованный способ работы с ним в различных средах в браузерном JavaScript-приложении, будь то Angular, Vue, React или BinCurse.

Почему именно консоль?

JavaScript устаревает, и все же лучший способ узнать, что происходит, – это простой console.log в нужном месте. Читайте на сайте Chrome Dev все, что вам нужно знать о консоли. Отказ от ответственности, я не нахожу реальной пользы от большинства из них.

Работая со сложными фреймворками, которые абстрагируют ванильный JavaScript, нам нужно записывать все в консоль во время разработки, и это главное “почему”.

Что записывать в консоль?

Вот несколько примеров того, что нужно записывать в консоль:

  • Запрос и ответ на HTTP-вызов

  • Обновление состояния

  • Последовательность инициализации

  • Готовность конфигурации

  • Специальные сторонние события протоколирования.

  • Временные сообщения о внимании

Нам также нужен способ различать общие журналы, предупреждения и ошибки.

Куда в консоль?

Мы хотим отключать журналы при изменении окружения, особенно в продакшене. Поэтому console.log не должен вызываться напрямую, а должен быть обернут в другую функцию, которая различает окружение.

Скрипт

Работая в обратном направлении, нам нужен способ сделать это:

ourFunction(object);

Мы также хотим вызывать сообщение, но сообщение необязательно:

ourFunction(object, message);

И мы хотим различать разные типы протоколирования:

ourFunction.log(object, message);

ourFunction.info(object, message);

Но мы не хотим связывать их слишком жестко, поэтому мы просто передадим тип как необязательный параметр.

ourFunction(object, message, type);

Итак, давайте напишем нашу функцию

function ourFunction(o, message, type) {
  // switch type to have different flavors
  console.log(message, o);
}
Войти в полноэкранный режим Выйти из полноэкранного режима

Первым улучшением, очевидно, является имя функции. Я назову ее _debug. После многих лет использования различных имен, столкновений с третьими лицами и путаницы с журналом, это имя выдержало испытание временем.

Конечно, вы можете возразить, почему бы не поместить его в отдельный модуль? Вы можете. Я отказываюсь. Я хочу что-то такое же тупое, как console.log, даже еще тупее.

Второе усовершенствование – это добавление формата к логам, чтобы они выглядели примерно так:

console.log("%c " + message, style);

Что касается типов, то основные типы, которые мы хотим записывать в журнал, это общая информация (мы можем добавлять новые стили по каждому запросу), ошибки и сбои, трассировки, результаты вызовов API и предупреждения.

Третье усовершенствование – это определение переменной перед записью в журнал, переменной, которая в продакшене имеет значение false. И нет, эта переменная не берется напрямую из окружения, позже я расскажу почему. Это может быть глобальная константа:

window._indebug

Putting it together:

function _debug(o, message, type) {
  if (window && window._indebug) {
    switch (type) {
      case 'e': // error
        console.log('%c ' + message, 'background: red; color: #fff', o);
        break;
      case 't': // trace error
        console.trace('%c ' + message, 'background: red; color: #fff', o);
        break;
      case 'p': // http response
        console.info('%c ' + message, 'background: #222; color: #bada55', o);
        break;
      case 'w': // warning
        console.warn('%c ' + message, 'background: #4f560f; color: #e6ff07', o);
        break;
      case 'gtm': // gtm events, special
        console.info('%cGTM: ' + message, 'background: #03dbfc; color: #000', o);
        break;
      default:
        console.info('%c ' + message, 'background: #d9d9d9; color: #a82868; font-weight: bold;', o);
    }
  }
}

// set _indebug to true in your environment file, could be anywhere
window._inebug = !process.env.production
Вход в полноэкранный режим Выход из полноэкранного режима

Пример настройки окружения в Angular, находится в файле /environment.ts напрямую, а так как он в typescript и может работать на SSR, проверяем наличие окна, и обращаемся к нему косвенно.

window && (window['_indebug'] = true);

Последнее усовершенствование заключается в добавлении отдельной функции для “внимания”, которая необходима во время разработки. Это выглядит по-другому, и может быть легко найдено и удалено из кода. Эти функции не должны существовать, они существуют для того, чтобы заставить нас отказаться от привычки постоянно использовать “console.logging”.

function _attn(o, message) {
  if (window && window._indebug) {
    // use debug to filter in console window
    console.debug('%c ' + message, 'background: orange; font-weight: bold; color: black;', o);
  }
}
Вход в полноэкранный режим Выход из полноэкранного режима

Typescript

Чтобы сделать его доступным в typescript, нам нужно объявить его в файле типизации, это может быть typings.d.ts, который включен в tsconfig. Скрипт по-прежнему написан на JavaScript и добавлен в файлы, включенные в сборку, потому что, как вы уже знаете, он должен оставаться немым!

// in typing.d.ts
declare function _debug(o: any, message?: string, type?: string): void;
declare function _attn(o: any, message?: string): void;
Вход в полноэкранный режим Выход из полноэкранного режима

Использование

Самое популярное использование пользовательского консольного логирования – это перехват запросов на выборку. Ванильный способ перехватить все вызовы fetch – перезаписать fetch. Давайте сделаем это:

const oFetch = window.fetch;

window.fetch = async (...args) => {
  const response = await oFetch(...args);
  // let's console here, something like resource url and response
  _debug(response, 'GET ' + args[0], 'p');

  if (!response.ok) {
    // log errors
    _debug(response.statusText, 'Error', 'e');
    return Promise.reject(response);
  }
  return response;
};

// when used in client
fetch('https://saphire.sekrab.com/api/cats')
  .then((response) => response.json())
  .then((json) => {
    // use _attn for temporary logging
    _attn(json, 'after json call');
});
Войти в полноэкранный режим Выход из полноэкранного режима

При запуске в StackBlitz это выглядит следующим образом.

Другой пример – вызов события регистрации GTM:

function registerEvent(data){
  // ... call dataLayer push, then log
  _debug(data, 'register event', 'gtm');
}
Вход в полноэкранный режим Выход из полноэкранного режима

Бэкдор

Почему мы установили глобальную переменную? В SPA, после первой загрузки страницы, мы можем установить глобальную переменную в true в консоли devTools, и получить доступ к этим сообщениям на продакшене. Это безопасно, потому что в лог записывается только уже имеющаяся информация.

В других случаях, кроме SPA, или для того, чтобы переменная устанавливалась в true при загрузке, мы можем получить доступ к бэкдору с помощью параметра URL, и это опять же безопасно и безвредно:

const _insearch = window.location.search.indexOf('debug=true') > -1;
if (_insearch) {
    _indebug = true;
}
Войти в полноэкранный режим Выйти из полноэкранного режима

Итак, теперь вы можете поделиться ссылкой с ?debug=true в URL со своей командой, чтобы получить доступ к зарегистрированным сообщениям для лучшего понимания.

Angular

Мы можем использовать эту функцию в Angular для протоколирования изменений состояния, перехвата HTTP, обработки ошибок и многого другого. Возвращайтесь на следующей неделе, а может и раньше. 😴

Я заставил вас посмотреть? Не существует такого понятия, как BinCurse.

РЕСУРСЫ

  • Формат и стиль сообщений в консоли
  • Справочник по API консоли
  • Перехват запросов и ответов JavaScript Fetch API
  • На StackBlitz

Оцените статью
Procodings.ru
Добавить комментарий