# Пристальный взгляд на отладку JavaScript приложений

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Всем привет!


Меня зовут Паша Востриков, я делаю на JS/TS много разного в «Лаборатории Касперского»: фронт, облачные сервисы (Node.js), штуки для коробочной поставки (OnPrem), платформенные компоненты и библиотеки. И, конечно же, Open Source.


Сегодня хотел бы затронуть тему отладки веб-приложений на JavaScript.


Итак, как отлаживаться? Как-как? console.log(1)



1. Отладка Frontend


tl;dr: для отладки фронтового кода:


  • debugger;
  • browser breakpoint + conditional breakpoint;
  • logger with remote storage;
  • metrics.

Мы с вами фронтенд-разработчики. Нам нужно сделать yet another классную фичу. Но прежде нужно отладиться. Мало ли что пошло не так.


Конечно, запустили фронт-сборку в режиме отладки. Например, Webpack Dev Server или Vite, или вообще Next.js. Честно говоря, конкретный способ запуска проекта не так важен, давайте поговорим именно про подходы. Нам нужны Source Maps, минимальная транспиляция и уж точно выключенная минификация ;)


Так или иначе, dev server запущен. Мы поставили debugger или breakpoint в developer tools.
Здесь все понятно.


// debugger
const sum = (x, y) => {
  const result = x + y
  debugger
  return result
}

Breakpoint:


breakpoint


Conditional Breakpoint:


сonditional-breakpoint


Что еще нам может помочь? Логи и метрики.


Если этого нет, то начать стоит хотя бы с банального console.log с диагностической информацией. Но без отдельного логера нельзя будет получить данные с прода.


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


На ум приходят библиотеки Pino и Winston.


Конечно, это всего лишь для примера, и наверняка у вас есть своя любимая и проверенная библиотека для логирования. Важно, чтобы данные отправлялись в удаленное персистентное хранилище. Так можно будет разобраться с ситуацией на проде ahead of time.


Вместе с логами удобно сразу подключить метрики и собирать их (метрики) как для мониторинга состояния прода, так и для дальнейшего анализа со стороны бизнеса.


Разговор про метрики и прочую телеметрию продолжим в главе 3, а сейчас мы подошли к Node.js.


2. Отладка Node.js


tl;dr: для отладки кода Node.js:


  • флаги запуска --inspect и --inspect-brk;
  • node-inspector: debugger и breakpoint;
  • heap snapshot;
  • логи, трейсы и метрики.

Далеко не факт, что вам требуется Node.js для сбора логов и метрик — возможно, у вас frontend-only или бэкенд на другом языке. Но узнать, что есть в мире ноды, все равно считаю полезным для JS-разработчиков и разработчиц.


Итак, к этому моменту мы уже обложились логами и даже поотлаживали фронт нашего проекта. Но что делать, если наш сервер на Node.js упорно отвечает 400, 500 или другой ошибкой?


Если на проекте используется Node.js, то, скорее всего, мы запускаемся локальной командой вроде:


node index.js

Добавили к запуску --inspect — и по умолчанию на порту 9229 будет висеть отладчик. Можно зацепиться за него из хрома или из редактора/IDE. Подробнее в Debugging Guide в документации Node.js.


node --inspect index.js

node-inspector


Случается так, что нужно отследить всю инициализацию кода, тогда подойдет --inspect-brk. Брейкпойнт будет установлен на первой строке вашего index.js:


node --inspect-brk index.js

Более подробный гайд: https://www.builder.io/blog/debug-nodejs.


Что еще можно потестировать с ходу на ноде?


  1. Собрать Heap Snapshot, чтобы исследовать использование памяти и потенциальные утечки.


    Например, выбрав вариант с запуском ноды с включенным сигналом:


    node --heapsnapshot-signal=SIGUSR2 index.js

  2. Using Heap Snapshot гайд от Node.js.


  3. Загрузку и простой event loop с помощью Node.js API perfomance.eventLoopUtilization.



Статья, которая хорошо объясняет про Event Loop Utilization.


Вообще стоит добавить слой метрик, чтобы снимать показатели с фронтового и Node.js кода.


Давайте поговорим об этом подробней.


3. Observability: логи, трейсы, метрики


tl;dr: для обеспечения Observability:


  • логи, трейсы, метрики;
  • OpenTelemetry как точка старта.

Локальная разработка и тем более удаленная отладка сложных проектов невозможна без такого важного подхода, как Observability.


Observability держится на трех китах: logs, traces и metrics.


Приведу доклад, который мы делали в пандемию. Он абсолютно актуален и сегодня: «Логи, трейсы, метрики: как не заблудиться в собственном приложении»


logs-talk


Если вкратце и по-простому, то:


  1. Логи — это наши с вами console.log, отправляемые в хранилище и доступные для пост-анализа. Логи позволяют отследить конкретный запрос или вызов функции.
  2. Трассировки — это отдельные записи логов, связанные сквозным идентификатором. Трассировки позволяют отследить сквозной сценарий, увидеть всю цепочку вызовов и понять контекст произошедшей ошибки.
  3. Метрики — это численные показатели работы приложения. Метрики позволяют понять, сколько раз пользователь зашел на страницу или как долго грузился определенный раздел.

В качестве метрик рекомендую Prometheus и соответственно prom-client, или сразу весь Open Telemetry, чтобы закрыть весь слой Observability: логи, трейсы и метрики.


После того, как настроены логи, метрики, и, скорее всего трассировки (здравствуй, Jaeger и Open Telemetry), следует задуматься о способе визуализации и чтения логов.


Мы в команде для себя так решили эту задачу.


  1. При локальной отладке — форматированные строки вида:
    [23:14:18][ServiceA] Operation #135 finished successfully
    [23:14:19][ServiceB] Subscriber: clear unsubscribe timeout #246
  2. При просмотре информации из хранилища — JSON-строки:
    { datetime: "13.09.2023 23:14:18.01", service: "ServiceA", message: "Operation #135 finished successfully", payload: {} }
    { datetime: "13.09.2023 23:14:19.55", service: "ServiceB", message: "Subscriber: clear unsubscribe timeout #246" }

Хочу добавить несколько слов про UI для работы с логами. Мы с командой пользовались в разное время несколькими системами (картинки из Интернета):


  • Splunk


    Splunk UI


  • Kibana


    Kibana UI


  • Grafana UI


    Grafana



Лично мне больше нравится Kibana, хотя для большинства команд, в том числе со своей лицензией, думаю больше подойдет Grafana.


Также отдельно упомяну Sentry. Если вы ее не использовали, то рекомендую хотя бы попробовать. Весь комбайн в одном сервисе. Безусловно, где-то это хорошо, но кому-то не подойдет — например, в контексте хранения персональных данных клиентов.


Но вы просто попробуйте демо-песочницу Sentry. Уверен, что в следующем проекте попробуете, если сейчас только узнали ;)


4. Стенды для отладки


tl;dr: для получения удобного для работы стенда:


  • для простых кейсов: обычный запуск а ля npm run dev;
  • для более сложных интеграционных сценариев: Inrastructure as Code, контейнеризованное окружение;
  • docker compose — простейший способ для локального контейнеризованного окружения;
  • Storybook и другие песочницы для изолированной разработки фичи.

Мы уже поговорили об отладке фронтенда, отладке Node.js-кода и таком важном моменте, как Observability.


Но что делать, когда нужно воспроизвести поведение бага или новая фича требует преднастроенного окружения?


Безусловно, небольшой проект просто запустится на локальной машине — нет проблем.


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


С чего можно начать? Да хотя бы с локального docker-compose. Полностью изолированное контейнеризованное окружение. Это плюс.
Главных минусов, на мой взгляд, два:


  1. не удобно менять код в контейнере
  2. вряд ли ваш прод в docker-compose
Источник: https://habr.com/ru/companies/kaspersky/articles/760922/


Интересные статьи

Интересные статьи

Привет, Хабр! Снова с вами те, кто отчитываются, что в вашем приложении не хватает заголовков безопасности, а именно инженеры по динамическому анализу. В нашей прошлой статье мы описали плагин для OWA...
Начнем цикл статей нашей компании легко и непринужденно, с темы из мира front-end. Надеюсь, что статья будет полезна тем, кто хоть как то связан с миром front-end. Предупреждаю, что backend разработчи...
Продолжаем разбираться с линейной алгеброй для 3D-приложений вместе Александром Паничевым — ведущим разработчиком логики в UNIGINE. В прошлом уроке мы поговорили про предназначение математики в трехме...
От переводчика. Привет! Про Kotlin есть стереотип, будто бы это язык для разработки только под Android. На самом деле, это совсем не так: язык официально поддерживает несколько платформ ...
В предыдущей публикации мы рассказали о нескольких дипломных проектах семестрового курса «Разработка на iOS» Технопарка (МГТУ им. Баумана). А в этот раз расскажем о двух самых инт...