Специально к старту нового потока курса «Frontend-разработчик» делимся с вами полезным переводом. Автор рассказывает, как использует методы логирования в производственной среде собственного проекта и в чём именно они помогают. Кроме того, нас знакомят с платформой AppSignal, созданной, чтобы напрямую уведомлять разработчика о возникающих у пользователя исключениях в приложении. Подробности под катом.




Я считаю себя инженером внутреннего программного обеспечения — и, как может подтвердить любой внутренний инженер, большая часть нашей жизни уходит на мониторинг, поиск и устранение неисправностей, а также отладку наших приложений. Фундаментальное правило разработки ПО: программное обеспечение будет давать сбои. Новых разработчиков от опытных отличает то, как они планируют эти сбои. Надежное и эффективное логирование — важная часть планирования на случай неудач и, в конечном счёте, смягчения их последствий. Как и в случае разработки бэкенда, логирование может быть полезно в разработке программного обеспечения фронтенда, но оно гораздо больше, чем просто поиск и устранение неисправностей и отладка. Эффективное фронтенд-логирование, кроме того, может сделать разработку продуктивной, быстрой и радостной.

Несмотря на то, что я разделяю и практикую разработку через тестирование, мне нравятся гибкость, богатство информации и надёжность кода, предоставляемые разработчикам фронтенда, которые эффективно используют console.log(). Я решил поделиться некоторыми советами и хитростями, которые изучил и включил в свой рабочий процесс во время работы над Firecode.io в надежде, что некоторые из них помогут сделать ваш рабочий процесс разработки немного продуктивнее и веселее. С удовольствием разделю эти советы на две широкие категории: быстрое и грязное логирование, когда вы активно собираете и отлаживаете приложение, и долговременная запись в лог для понимания, когда ваше приложение работает, как ожидалось, а когда нет.

Советы по быстрому, грязному логированию разработки с console.log()

.

Не используйте console.log()

.
Да, правда. Я не пользуюсь console.log(). Хотя… Ладно. Я пишу обёртки, которые используют console.log. Подробнее об этом — в разделе логирования в производственной среде. Но, если вы хотите логировать что-то в приложении, чтобы увидеть, что происходит, используйте console.trace(). В дополнение ко всему из console.log() этот метод выводит всю трассировку стека, чтобы вы точно знали, откуда идёт сообщение.



Используйте имена вычисляемых свойств ES6 для идентификации объектов и чтобы не путать их с именами переменных.


Это просто — используйте синтаксис вычисляемых свойств ES6: оберните объекты, которые вы хотите логировать, в фигурные скобки вот так: console.log({user}), а не console.log(user). Логирование аккуратное: ключ — имя переменной, а значение — сам объект. Такой подход особенно полезен, когда вы спешите и хотите логировать несколько объектов одной командой console.log().



Отображение уровней логирования: ERROR, WARN, INFO


console.log(param) по умолчанию имеет значение INFO — однако в вашем распоряжении 3 других уровня логирования, которыми вы не должны пренебрегать — console.debug(), console.warning() и console.error(). Помимо различий в форматировании (заметили разные цвета?) консоль разработчика в браузере позволяет легко отфильтровывать логи разных уровней с помощью удобного выпадающего списка, ненужные логи убираются вот так:





При логировании списков элементов пользуйтесь console.table()


Одна из моих любимых функций говорит сама за себя. Если вам когда-нибудь понадобится логировать список объектов, дайте шанс console.table().



Дебажим быстро с помощью debugger


Хотите сэкономить несколько драгоценных секунд? Вместо того чтобы искать файл в консоли разработчика, в который хотите добавить точку останова, впишите в код строку debugger эта строка остановит выполнение кода. Это всё, теперь можно отлаживать и переходить к функциям, как обычно.





Тонкое профилирование с console.profile() и console.time()


Хотите профилировать поток пользователя в вашем приложении, чтобы найти горячие точки? Укажите триггер console.profile(profileName) в начале профилируемого кода и console.profileEnd(profileName) в его конце, чтобы исследовать профиль процессора в потоке.





Кроме того, можно точно измерить, сколько времени занимает выполнение потока, поместив console.time(id) в его начале и console.timeEnd(id) в его конце.



Подсчёт количества выполнений кода через console.count()


Это одна из тех функций, для которых я не нашёл особого применения, тем не менее польза от нее есть: console.count(label) помогает точно узнать, сколько раз выполняется фрагмент кода, это полезно при поиске и устранении состояния гонки и в других ситуациях.



Красивое логирование с помощью CSS


Безусловно, это моя любимая консольная функция, которую я широко использую при логировании в производственной среде (подробнее об этом — в соответствующем разделе). Ближе к сути: мы можем использовать строки форматирования, чтобы форматировать сообщения лога. Здесь %c — модификатор для кода CSS, а всё, что после него, — это сообщение.



Можно стилизовать несколько элементов, расширив строку через %s, вот так:



Я выраженный визуал, мне нравится тратить какое-то время на то, чтобы информационные и отладочные логи выглядели красиво и в то же время были полезны. Я широко использую эту функцию в производственном логировании Firecode.io. И это прекрасная тема для следующего раздела.



Логирование через console.log() в производственной среде

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

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

Не пользуюсь console.log()


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

Внимание! Впереди фрагменты кода TypeScript. Если вы не знакомы с TypeScript, думайте о нём, как о надмножестве JavaScript с типами, на которых сделан акцент (это грубое упрощение). Иначе говоря, const str = "some string"; превращается в const str: string = "some string" — типы добавляются после имени переменной с двоеточием.

Разрабатывая Firecode.io, я написал собственный фронтенд-фреймворк, который использует RxJS, но содержит знакомые концепции, такие как компоненты, из других популярных фреймворков, к примеру, React и Vue. При этом добавлены и другие концепции: движки для блоков тяжёлого для процессора кода, каналы для сообщений WebSocket и клиенты для HTTP-запросов. Очень важна была визуализация совместной работы всех этих частей, поэтому я реализовал пользовательское форматирование в классе-обёртке Logger, этот класс форматирует и визуально отделяет журналы от каждой части приложения.



Вместо вызова console.log("Cache SET to", {value}) я вызываю Logger.debug("Cache set to", {value}, Framework.Cache). В классе Logger есть перечисление TypeScript, сопоставляющее каждый компонент фреймворка с цветом:



Так я во время разработки визуально концентрируюсь на компонентах приложения. Например, когда я хочу посмотреть, что делает WsRequestCache, я могу «отключиться» от всех логов, кроме бирюзовых.

Защитите логи установкой уровня логирования на бэкенде


Я настроил Firecode.io на включение логирования на уровне отладки по умолчанию для пользователей-администраторов через переменную JavaScript, она устанавливается бэкендом. При этом предприимчивые пользователи все еще могут найти и установить соответствующие флаги в консоли разработчика, чтобы включить точный журнал. Это лучше, чем ситуация, когда каждому пользователю приложения по умолчанию представлены все логи, и лучше, чем постпроцессор, полностью удаляющий логи из приложения в производственной среде. Установка уровня логирования на бэкенде в Ruby on Rails:

const logLevel: number = <%= @app.get_log_level_for_user %>

И в классе Logger:

class Logger {
   ...
   ...
   static info(...) {
     shouldLog(Level.INFO) && console.log(...);
        ...
   }
}

Логируйте возможные ошибки и уведомляйте о них


И последнее, но не менее важное: хочется получать уведомления, когда пользователи сталкиваются с исключениями в приложении, не обязательно при этом с выводом на консоль разработчика. Это возможно. Включите вызов, передающий ваши ошибки в APM-сервис стороннего вендора (например AppSignal) в функцию ошибок вашего логгера. Пример:

class Logger {
   ...
   ...
   static error(e) {
     if (shouldLog(Level.ERROR)) {
       console.error(e);
     }
     appsignal.sendError(e);
   }
}

AppSignal содержит интеграции для передачи ваших ошибок в службы исходящих уведомлений, таких как Slack, PagerDuty и OpsGenie, — вы даже можете подключить инструмент управления проектами, например JIRA или Trello, чтобы автоматически создавать Issues и баги для удобства вашей команды.

Итоги


Я очень надеюсь, что эти советы и истории сделают вашу фронтенд-разработку немного продуктивнее и веселее! Очевидно, что в этом посте я коснулся только поверхности боевого искусства логирования, так что, если у вас есть еще какие-то советы, которыми можно поделиться, я бы с удовольствием прочитал их в своём Twitter.



И два дополнения. Я перестраиваю Firecode.io с нуля, добавляя совершенно новый набор вопросов для собеседований по кодированию JavaScript, Java, Python и Scala.

Если вы заинтересованы в написании кода для подготовки к собеседованию, который адаптируется к вашему стилю обучения и доставляет удовольствие, зарегистрируйтесь, указав свой адрес электронной почты здесь. При запуске нового Firecode.io я предоставлю вам бесплатную трёхмесячную подписку. Я буду размещать больше материалов о создании веб-приложений промышленного масштаба (таких как Firecode.io) с нуля в качестве стороннего проекта. Если вы новичок в JavaScript и хотите понять, как объектноориентированный JavaScript и прототипное наследование работают под капотом, ознакомьтесь с моей любимой книгой по этой теме — The Principles of Object-Oriented JavaScript, и, если вам интересно узнать больше о том, почему вместо JS следует использовать TypeScript, ознакомьтесь с Effective TypeScript.

А помимо специальной литературы вам поможет промокод HABR, добавляющий 10 % к скидке на баннере.

image



Рекомендуемые статьи