Я считаю себя инженером внутреннего программного обеспечения и, как может подтвердить любой внутренний инженер, большая часть нашей жизни уходит на мониторинг, поиск и устранение неисправностей, а также отладку наших приложений. Фундаментальное правило разработки ПО: программное обеспечение будет давать сбои. Новых разработчиков от опытных отличает то, как они планируют эти сбои. Надежное и эффективное логирование важная часть планирования на случай неудач и, в конечном счёте, смягчения их последствий. Как и в случае разработки бэкенда, логирование может быть полезно в разработке программного обеспечения фронтенда, но оно гораздо больше, чем просто поиск и устранение неисправностей и отладка. Эффективное фронтенд-логирование, кроме того, может сделать разработку продуктивной, быстрой и радостной.
Несмотря на то, что я разделяю и практикую разработку через тестирование, мне нравятся гибкость, богатство информации и надёжность кода, предоставляемые разработчикам фронтенда, которые эффективно используют
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 % к скидке на баннере.
- Обучение профессии Data Science
- Обучение профессии Data Analyst
- Онлайн-буткемп по Data Analytics
- Курс Python для веб-разработки
- Продвинутый курс Machine Learning Pro + Deep Learning
- Курс Математика и Machine Learning для Data Science
- Курс по Machine Learning
- Разработчик игр на Unity
- Курс по JavaScript
- Профессия Веб-разработчик
- Профессия Java-разработчик
- C++ разработчик
- Курс по аналитике данных
- Курс по DevOps
- Профессия iOS-разработчик с нуля
- Профессия Android-разработчик с нуля