Трассировка и оборудование приложений
Термин инструментирование относится к возможности мониторинга и измерения уровня производительности продукта и диагностики ошибок. В программировании это означает способность приложения включать следующие возможности.
Трассировка кода — получение информационных сообщений о работе приложения во время выполнения.
Отладка — отслеживание и устранение ошибок программирования в приложении при разработке. Дополнительные сведения см. в разделе Отладка.
Счетчики производительности — компоненты, позволяющие отслеживать производительность приложения. Дополнительные сведения см. в статье Performance Counters.
Журналы событий — компоненты, которые позволяют принимать и относить основные события при выполнении приложения. Дополнительные сведения см. в описании класса EventLog.
Инструментирование приложения путем добавления операторов трассировки в стратегически важных местах кода особенно полезно для распределенных приложений. С помощью операторов трассировки можно инструментировать приложение не только для отображения сведений о неправильных моментах, но также отслеживать, насколько хорошо работает приложение.
Класс TraceSource предоставляет улучшенные функции трассировки и может использоваться вместо статических методов более старых классов трассировки Trace и Debug. Знакомые классы Trace и Debug по-прежнему широко используются, однако рекомендуется использовать класс TraceSource для новых команд трассировки, таких как TraceEvent и TraceData.
Классы Trace и Debug идентичны, за исключением того, что процедуры и функции класса Trace по умолчанию компилируются в сборки выпуска, а процедуры и функции класса Debug — нет.
Классы Trace и Debug предоставляют средства для мониторинга и исследования производительности приложения как во время разработки, так и после развертывания. Например, возможно использование класса Trace для отслеживания в развернутом приложении отдельных типов действий по мере их выполнения (например, создание новых подключений к базе данных) и последующего мониторинга производительности приложения.
Отладка и трассировка кода
Использование методов вывода класса Debug при разработке приложения позволяет отображать сообщения в окне вывода, доступном в интегрированной среде разработки Visual Studio. Пример:
В каждом из этих примеров в окне вывода будет отображаться сообщение «Hello World!» при запуске приложения в отладчике.
Это позволяет отлаживать приложения и оптимизировать их производительность на основе их поведения в среде тестирования. Возможна отладка приложения при отладочном построении с включенным условным атрибутом Debug, что позволяет получать все выходные данные отладки. Когда приложение будет готово к выпуску, можно скомпилировать построение выпуска, не включая условный атрибут Debug, чтобы код отладки не включался компилятором в конечный исполняемый файл. Дополнительные сведения см. в разделе Практическое руководство. Условная компиляция с использованием атрибутов Trace и Debug. Дополнительные сведения о различных конфигурациях сборок для приложения см. в разделе Компиляция и сборка.
С помощью методов класса Trace можно отслеживать выполнение кода в установленном приложении. Процессом и масштабом трассировки можно управлять. Для этого добавьте в код переключатели трассировки. Так вы сможете отслеживать состояние приложения в рабочей среде. Это особенно важно в бизнес-приложениях, которые используют различные компоненты, выполняющиеся на нескольких компьютерах. Вы можете управлять порядком использования переключателей после развертывания с помощью файла конфигурации. Дополнительные сведения см. в разделе Практическое руководство. Создание, инициализация и настройка переключателей трассировки.
При разработке приложения, для которого предполагается использовать трассировку, в код приложения обычно включают сообщения трассировки и отладки. Когда все будет готово для развертывания приложения, можно скомпилировать сборку выпуска без включения условного атрибута Debug. Тем не менее можно включить условный атрибут Trace, чтобы компилятор включил код трассировки в исполняемый файл. Дополнительные сведения см. в разделе Практическое руководство. Условная компиляция с использованием атрибутов Trace и Debug.
Этапы трассировки кода
Существует три этапа трассировки кода.
Инструментирование — добавление кода трассировки в приложение.
Трассировка — код трассировки записывает сведения в указанный целевой объект.
Анализ — оценка сведений трассировки для определения и понимания проблем в приложении.
Во время разработки все методы вывода трассировки и отладки записывают сведения в окне вывода Visual Studio по умолчанию. В развернутом приложении эти методы записывают сведения трассировки в указанные целевые объекты. Дополнительные сведения об указании целевого объекта выходных данных трассировки и отладки см. в разделе Прослушиватели трассировки.
Ниже приведен полный обзор основных шагов, обычно выполняемых при использовании трассировки для анализа и исправления возможных проблем в развертываемом приложении. Дополнительные сведения о выполнении этих шагов см. по соответствующей ссылке.
Использование трассировки в приложении
Обдумайте, какие выходные данные трассировки вы хотите получить на месте после развертывания приложения.
Создайте набора переключателей. Дополнительные сведения см. в статье How to: Configure Trace Switches (Настройка переключателей трассировки).
Добавьте операторы трассировки в код приложения.
Определите, где вы хотите получать выходные данные трассировки, и добавьте соответствующие прослушиватели. Дополнительные сведения см. в разделе Создание и инициализация прослушивателей трассировки.
Выполните тестирование и отладку своего приложения и содержащегося в нем кода трассировки.
Скомпилируйте приложение в исполняемый код с помощью одной из следующих процедур.
Используйте меню Сборка со страницей Отладка диалогового окна Страницы свойств в обозревателе решений. Используйте эту процедуру при компиляции в Visual Studio.
Используйте директивы компилятора Trace и Debug для компиляции из командной строки. Дополнительные сведения см. в разделе Условная компиляция с использованием атрибутов Trace и Debug. Используйте эту процедуру при компиляции из командной строки.
Если во время выполнения возникает проблема, включите соответствующий переключатель трассировки. Дополнительные сведения см. в разделе Настройка переключателей трассировки.
Код трассировки записывает сообщения трассировки в указанный целевой объект, например в экран, текстовый файл или журнал событий. Целевой объект определяется типом прослушивателя, который вы включили в Trace.Listeners коллекцию.
Проанализируйте сообщения трассировки, чтобы обнаружить и понять проблемы в приложении.
Инструментирование трассировки и распределенные приложения
При создании распределенного приложения тестирование приложения способом, которым оно будет использоваться, может показаться сложной задачей. Немногие группы разработчиков имеют возможность протестировать все возможные сочетания операционных систем или веб-браузеров (в том числе все параметры локализованных версий) или смоделировать большое число пользователей, которые будут обращаться к приложению одновременно. В таких обстоятельствах невозможно протестировать реакцию распределенного приложения на большую нагрузку, различные настройки и разные действия конечных пользователей. Кроме того, многие компоненты распределенного приложения не имеют пользовательского интерфейса, с которым можно взаимодействовать напрямую или просматривать активность этих компонентов.
Однако вы можете компенсировать это, позволив распределенным приложениям описывать определенные события, интересующие системных администраторов, особенно то, что работает неправильно, путем инструментирования приложения, то есть путем размещения операторов трассировки в стратегически важных местах кода. Затем, если во время выполнения произойдет что-либо неожиданное (например, слишком большое время отклика), можно будет определить вероятную причину.
Операторы трассировки помогают избежать сложностей проверки исходного кода, его изменения, перекомпиляции, а также попыток воспроизвести ошибку времени выполнения в среде отладки. Помните, что можно инструментировать приложение не только для отображения ошибок, но также для наблюдения за производительностью.
Стратегическое размещение операторов трассировки
Необходимо уделить особое внимание размещению операторов трассировки для использования во время выполнения. Вы должны учесть, какие сведения трассировки скорее всего потребуются в развертываемом приложении, чтобы в полной мере охватить все вероятные сценарии трассировки. Поскольку приложения, использующие трассировку, могут быть самыми разными, не существует общих принципов стратегического размещения трассировки. Дополнительные сведения о размещении операторов трассировки см. в разделе Практическое руководство. Добавление операторов трассировки в код приложения.
Выходные данные трассировки
Выходные данные трассировки собираются объектами, которые называются прослушивателями. Прослушиватель — это объект, который принимает выходные данные трассировки и записывает их в устройство вывода (обычно это окно, журнал или текстовый файл). При создании прослушиватель трассировки, как правило, добавляется к коллекции Trace.Listeners, что позволяет ему получать все выходные данные трассировки.
Сведения трассировки всегда записываются как минимум в целевой объект вывода Trace по умолчанию, DefaultTraceListener. Если по каким-то причинам объект DefaultTraceListener был удален, а другие прослушиватели не были добавлены в коллекцию Listeners, сообщения трассировки получены не будут. Дополнительные сведения см. в разделе прослушиватели трассировки.
В следующей таблице перечислены шесть членов класса Debug и методов класса Trace, которые записывают сведения трассировки.
| Метод | Выходные данные |
|---|---|
| Assert | Указанный текст; если ничего не указано, то стек вызовов. Выходные данные записываются только в том случае, если условие, указанное в качестве аргумента в Assert инструкции, имеет значение false. |
| Fail | Указанный текст; если ничего не указано, то стек вызовов. |
| Write | Указанный текст. |
| WriteIf | Указанный текст, если удовлетворено условие, заданное в качестве аргумента в WriteIf инструкции. |
| WriteLine | Заданный текст и возврат каретки. |
| WriteLineIf | Указанный текст и символ возврата каретки, если удовлетворяется условие, заданное в качестве аргумента в WriteLineIf инструкции. |
Трассировка сервисов, OpenTracing и Jaeger
В наших проектах мы используем микросервисную архитектуру. При возникновении узких мест в производительности достаточно много времени тратится на мониторинг и разбор логов. При логировании таймингов отдельных операций в лог-файл, как правило, сложно понять что привело к вызову этих операций, отследить последовательность действий или смещение во времени одной операции относительно другой в разных сервисах.
Для минимизации ручного труда мы решили воспользоваться одним из инструментов трассировки. О том, как и для чего можно использовать трассировку и как это делали мы, и пойдет речь в этой статье.
Какие проблемы можно решить с помощью трассировки
Что умеет логировать трассировка. Span
В трассировке есть понятие спан, это аналог одного лога, в консоль. У спана есть:
Opentracing, Jagger и как мы реализовали это для своих проектов
Есть общий стандарт Opentracing, который описывает как и что должно собираться, не привязываясь трассировкой к конкретной реализации в каком-либо языке. Например, в Java вся работа с трейсами ведется через общий API Opentracing, а под ним может скрываться, например, Jaeger или пустая дефолтная реализация которая ничего не делает.
У нас используется Jaeger как имплементация Opentracing. Он состоит из нескольких компонент:
Отдельным компонентом можно назвать реализацию opentracing jaeger под конкретные языки, через которую спаны отправляются в jaeger-agent.
Подключение Jagger в Java сводится к тому, чтобы заимплиментить интерфейс io.opentracing.Tracer, после чего все трейсы через него будут улетать в реальный агент.
Так же для компонент спринга можно подключить opentracing-spring-cloud-starter и имплементацию от Jaeger opentracing-spring-jaeger-cloud-starter которая законфигурит автоматически трассировку на все что проходит через эти компоненты, например http запросы в контроллеры, запросы к БД через jdbc и т.д.
Логирование трейсов в Java
Где-то на самом верхнем уровне должен быть создан первый Span, это может быть сделано автоматически например контроллером спринга при получении запроса, либо вручную если такого нет. Дальше он передается через Scope ниже. Если какой-то метод ниже хочет добавить Span, он берет из Scope текущий activeSpan, создает новый Span и говорит что его родительский полученный activeSpan, и делает новый Span active. При вызове внешних сервисов им передается текущий активный спан, и те сервисы создают новые спаны с привязкой к этому спану.
Вся работа идет через инстанс Tracer, получить его можно через механизм DI, либо GlobalTracer.get() как глобальную переменную, если механизм DI не работает. По дефолту если tracer не был проинициализирован вернется NoopTracer который ничего не делает.
Дальше из tracer через ScopeManager достается текущий scope, создается новый scope от текущего с привязкой нового спана, а в дальнейшем закрывается созданный Scope, который закрывает созданный спан и возвращает в активное состояние прошлый Scope. Scope привязан к потоку, поэтому при многопоточном программировании надо не забывать передавать активный спан в другой поток, для дальнейшей активации Scope другого потока с привязкой к этому спану.
Для многопоточного программирования так же есть TracedExecutorService и аналогичные обертки, которые автоматически пробрасывают текущий спан в поток при запуски асинхронно таски:
Для внешних http запросов есть TracingHttpClient
Проблемы, с которыми мы столкнулись
Семплирование, хранение и просмотр трейсов
Для того, чтобы посмотреть трейсы нужно:
Трасси… что? Доклад Яндекса
Отладка приложения занимает бо́льшую часть нашего времени. Кто-то пользуется DevTools, кто-то обходится обычным console.log, кто-то использует профайлеры. Зачастую этих инструментов более чем достаточно. Но есть еще один, не такой известный и популярный в JavaScript-мире. О нем я и рассказал в докладе.
— Всем привет! Надеюсь, вы бодры, веселы, перекусили, заварили себе кофейку, потому что сейчас будет очень интересная и при этом доступная тема: «Трасси… что?». Правильнее было бы называть доклад «Трасси… что-о-о?!», но не будем так.
Давайте познакомимся. Меня зовут Алексей Охрименко, я разработчик Яндекс.Музыки. У Музыки 12 стран присутствия, 15 млн активных слушателей и больше 65 млн активных треков. Там я работаю разработчиком и стараюсь делать этот проект лучше.
Помимо того, что я пишу в Яндексе на React, я еще и Google Developer Expert по Angular. Кому еще нравится фильм «Сплит»?
Также, кому интересно, заходите в созданное мной телеграм-комьюнити tensorflow_js. Если вы когда-то интересовались машинным обучение и знаете JavaScript или Python, обязательно заходите в эти группы, будем рады вам помочь. Подписывайтесь на мои социальные сети, там я под никнеймом obe’njiro или obenjíro, как удобно. И у меня есть телеграм-канал obenjiro_notes, в котором я периодически выкладываю самое интересное и классное, что только бывает.
Я обожаю странные инструменты, которые экономят огромное количество времени. Сейчас хочу с вами поговорить о трассировщиках.
Что такое трассировка?
Смотрите, у нас у всех есть некий словарный запас: трассировка, отладка, профилирование, логирование. Мы все эти термины слышали. Но как их поделить, как сделать четкую иерархию?
Самое главное: у нас есть одна главная цель — отладить наше приложение. С помощью отладки мы пытаемся улучшить качество, скорость, еще что-то.
А вот трассировка, профилирование, логирование — это всего лишь некие подходы/методологии, позволяющие достичь нашей цели.
Кстати, есть огромное количество разных интересных способов достичь целей отладки. К примеру, Wolf fence algorithm, Delta Debugging, Saff Squeeze, Causality tracking, PostMortem debug.
Сейчас вы подумаете: «Вот это классные темы! Поговорим о них».
Но что мы скажем богу прокрастинации? Не сегодня! В этот раз мы поговорим только про трассировку и существующие инструменты.
И еще раз. Что такое трассировка?
Трассировка — это получение информации о каждом шаге выполнения. Самое важное отличие от других подходов — в том, что мы получаем информацию о каждом шаге. Но что означает «шаг»?
Для трассировки нет необходимости получать информацию о каждой строчке кода.
Нам достаточно, к примеру, получать информацию о том, какие функции были вызваны, с какими аргументами, и что они вернули. Этой информации часто более чем достаточно, чтобы понять, как наш код отработал и как его исправить/оптимизировать.
Базовые способы трассировки
Трассировка может быть сделана множеством разных способов. Вы можете банально вставить console.log везде.
Если вам не хочется делать это вручную, настраивать, есть огромное количество хороших библиотек: Winston, Log4js, Scribe и многие другие — я тут не перечислял все.
Есть наш замечательный Chrome DevTools со своим пошаговым отладчиком. Мы можем трассировать нашу программу с помощью него.
Есть огромное количество профессиональных инструментов: Dtrace, Ptrace и многие другие. Но у них есть ряд ограничений. Я поговорю о них чуть попозже.
И, конечно, есть некие специализированные инструменты, которые и являются предметом доклада.
Именно о них я и хочу вам рассказать. Но прежде чем мы приступим, посмотрим на существующие подходы к трассировке.
console.log (Winston, Log4js, Scribe)
Сначала про логи. Самое простое, банальное, но при этом проверенное временем решение.
Простейший вариант — я вставляю console.log вначале, и в конце нашей функции вывожу информацию об аргументах и результате выполнения функции.
Естественно, я не хочу выводить trace-логи каждый раз. Они нужны мне только во время отладки.
Поэтому я добавляю некое условие — проверку на то, что у нас есть, к примеру, environment-переменная Trace. Или, если мы в браузере, я могу взять за основу какой-нибудь query-параметр либо проверить наличие определенной куки.
Также я могу это делать более автоматизированно — воспользоваться библиотекой, у которой уже настроены специальные транспорты, есть огромное количество настроек.
Теперь я могу просто указать, какой тип уровня логирования мне нужен и в зависимости от этого типа выводить или не выводить эту трассировочную информацию. Я могу ее включить и выключить, когда мне нужно.
Я видел некоторые библиотеки и проекты, которые делают прямо хорошую работу и покрывают логами каждую функцию, но это огромное количество работы, которой хочется избежать.
Chrome DevTools, Step Debugger
Давайте посмотрим что-нибудь более автоматизированное. К примеру, Chrome DevTools и его Step Debugger.
Как только мы откроем DevTools, у нас будет панелька, которая позволяет выполнять пошаговую отладку нашего приложения, и мы будем, скажем так, близки к термину трассировка. То есть будем выполнять программу шаг за шагом, каждый раз нажимать на следующий шаг и получать информацию о каждом шаге.
Круто? Увы, не очень.
Dtrace, Ptrace, etc.
Безусловно, есть профессиональные инструменты, которые были очень давно сделаны. Dtrace — один из самых популярных.
Для эффективного использования, чтобы вы получали именно хорошую отладочную информацию, необходимо подключить провайдер и создать так называемые пробы. И эти пробы будут использоваться как некий объект, через который вы будете сообщать Dtrace о происходящих событиях.
И все замечательно, но, к сожалению, это не все. Вам не только JavaScript придется писать, но и Dtrace скрипт. То есть есть такая штука. Она не сильно сложная, но, в любом случае, вам придется с ней ознакомиться.
Написав ее, вы можете получить эту интересную отладочную информацию и получать ее на нативном, скажем так, уровне — то, что делают ребята из C++, из других языков программирования.
Всё это, конечно, замечательно. Но в основном все эти инструменты для Node.js, они слишком низкоуровневые, ну правда. Те, кто знают C/C++, будут чувствовать себя как рыба в воде. А остальным будет тяжеловато. И требуется некая поддержка кодовой базы. То есть вам придется дополнять ваш код в зависимости от изменений. Это дополнительная работа, которой все-таки хочется избежать.
Специализированные инструменты
И теперь самое интересное. Есть специально созданные инструменты для трассировки, именно под JavaScript, под веб и Node.js.
Давайте взглянем на некоторые из них. Лично я знаю два засветившихся в мире фронтенда: TraceGL от Рика Арендса и SpyJS от Артема Говорова.
TraceGL
Это инструмент, который изначально был бесплатен, но вы могли заплатить за него дополнительно, как бы поддержать автора. В какой-то момент, к сожалению, этот инструмент просто перестал существовать. К сожалению, поддержка комьюнити оказалась не такая большая, как ожидал автор, плюс наложились проблемы самого инструмента. Но есть ряд разработчиков, которые форкнули когда-то выложенный TraceGL, запатчили основные существенные баги, и мы можем склонировать этот репозиторий и воспользоваться trace-сервером из этого репозитория.
После чего мы можем указать нашу программу и передать ее в TraceGL клиент как аргумент. Она запустится, то есть TraceGL аугментирует вашу кодовую базу и добавит отладочную информацию.
Давайте взглянем на этот инструмент. Всё очень быстро и качественно работает. И огромное количество отладочной информации, которую вы видите на экране, — все это отрисовано с помощью WebGL. Вы всё рисуете с помощью WebGL и шейдеров: шрифты, кнопки, тексты, скроллы. Автор проделал огромную работу. Но в связи с этим появились и дополнительные проблемы — не на всех машинах доступны и хорошо работают шейдеры. Кто пытался сделать качественные кроссбраузерные и кроссплатформенные веб-игры — поймет, о чем речь.
Если мы посмотрим на программу, то увидим три замечательные особенности: мини-карту, то есть некую общую карту того, что вообще произошло; набор stack traces, нажав на которые, мы можем перейти к нашей кодовой базе и увидеть, к примеру, как выполнялись те или иные if, else, switch statements, операторы условного перехода. То есть мы можем проанализировать, как выполнялась наша программа в реальном времени. Не знаю, как для вас, а для меня это безумно круто. Когда я впервые это увидел, был просто в безумном восторге.
Но, как и говорил, инструмент устарел, он не поддерживает TypeScript, не поддерживает современный JavaScript, поэтому нам он не подойдет.
SpyJS
Есть инструмент для трассировки, который действительно полезен и при этом ближе к вам, чем вы можете думать.
SpyJS — это инструмент, который интегрирован в WebStorm. Все, что нужно, чтобы прямо сейчас начать трассировку вашего приложения с помощью SpyJS: вместо профиля отладки создать профиль для SpyJS. Вы также запускаете через WebStorm ваше приложение — как Node.js, так и фронтенд…
SpyJS через проксирование дополняет вашу кодовую базу, добавляет все необходимое для трассировки вашего приложения.
Если посмотреть, что происходит, то у вас появляется дополнительная отладочная информация либо в момент прогона, либо после него, и вы можете по stack traces, по событиям исследовать и открывать так называемый trace view. Это view, в котором есть вся отладочная информация, необходимая, чтобы понять, какие операторы условного перехода отработали, какие функции когда и при каких условиях были вызваны.
SpyJS встроен в среду разработки, и вы можете отлаживать ваше приложение вообще без браузера. Ну, класс!
У этого инструмента есть ряд нюансов. Все-таки он накладывает довольно большой overhead по производительности, имейте это в виду. Вообще SpyJS изначально конкурировал с TraceGL, и TraceGL выигрывал как раз за счет производительности, наличия мини-карты и более понятного и простого интерфейса. Но SpyJS сейчас монополист в плане специализированных инструментов по отладке.
Фатальный недостаток
Но все вышеперечисленные инструменты обладают фатальным недостатком. Они написаны не мной. 🙂 Поэтому была начата разработка инструмента под названием TraceMePlz.
Зачем?
Это важный вопрос, всегда задавайте его себе, прежде чем что-то писать.
Если кто-то его еще не видел — попробуйте, реально классный инструмент. К примеру, у нас есть простой файл main.ts без типов:
Мы запускаем TypeWiz:
И в нашем коде магически появляются типы:
Он в рантайме, добавляя в вашу кодовую базу некий код и собирая с помощью него информацию о типах объектов во время выполнения, превратить ваш TypeScript, у которого, допустим, нет типов, в TypeScript, у которого указаны все типы. Он использует информацию из рантайма, берет эти типы и вставляет их обратно в файл. Вы можете за считанные минуты получить полный type coverage вашего приложения.
Это все, конечно, круто. Но чем TypeWiz меня так вдохновил?
У него есть режим под названием CLI. Он вам позволяет просто добавить в готовый исходный код вот эти консоль-логи, эту необходимую отладочную информацию.
И как?
Давайте посмотрим, как это происходит.
Чтобы все это сделать, достаточно использовать Babel. У него есть парсер, который позволяет получить поддержку почти всей современной кодовой базы. Есть traverse, позволяющий ходить по AST, которые мы распарсили, и получать из этого информацию. Есть генератор и типы, которые позволяют нам создавать дополнительную кодовую базу и с помощью генератора обратно сгенерировать это синтаксическое дерево в файл.
Самое простое, что можем сделать: создать этот парсер и подключить вообще все существующие плагины, за исключением Flow. Flow и TypeScript несовместимы, поэтому приходится выбирать, что вам нужно поддерживать в текущий момент.
Дальше мы проходимся по нашему дереву и для ArrowFunctionExpression, FunctionExpression, FunctionDeclaration, Method вставляем дополнительный код, то есть вызов функции, который позволит передать трассировочную информацию.
Теперь мы берем типы и делаем call expression, вызов функции. В нем мы передаем наши параметры, аргументы, текущее название файла, что мы вызываем и в каком месте мы это делаем.
Всё это превращается в некую строчку в нашей кодовой базе, которая автоматически расставляется во всех местах, необходимых для сбора информации о трассировке.
Помните, как я показывал консоль-логи, когда мы расставляли вручную? Мы всё это можем автоматизировать. Затем генерируем и вставляем это в кодовую базу.
Но есть одна проблема. babel/generator ломает форматирование кода. Тут пришлось прибегнуть к магии MagicString (подробнее о нем можете прочитать у меня в статье). MagicString решило не только проблему с форматированием кода, упростило добавление новых языков в будущем и увеличило производительность инструмента.
И всё. Неважно, что вы используете: Webpack, Babel, TypeScript, Flow или вообще PHP. Подход будет одним и тем же, абсолютно. Поменяется лишь некий набор библиотек. И этот подход универсален, он подходит для всего. Неважно, как вы деплоите, есть ли у вас свой сборщик, язык и парсер или вы делаете что-то свое, уникальное. У вас все будет работать.
Смотрите, как это выглядит со стороны. Вы запускаете инструмент для трассировки и указываете, к примеру, что в папке public лежит все, что связано с фронтендом. Я туда передаю, соответственно, некий паттерн, по которому найдутся все фронтенд-файлы, и указываю channel (это именно параметр «с»), что это информация о фронтенде для сервера.
Для сервера делаю аналогично: указываю некий паттерн, который позволит нам понять, что эти файлы связаны именно с серверной разработкой, и указываю канал, отмечаю, что это бэкенд. Теперь здесь есть некая информация, которая поможет мне потом разделить кодовую базу: что выполняется на фронтенде, а что на бэкенде.
Затем надо запустить сервер, который будет получать эту информацию в реальном времени и отображать ее.
Рассмотрим на максимально простом примере. У нас есть некая кнопка. При нажатии на нее мы делаем fetch, это уходит на бэкенд, бэкенд идет за какими-то моковыми данными и возвращает результат на фронтенд.
Давайте глянем, как это выглядит в TraceMePlz. Не обращайте внимания на код. Я хочу лишь показать две особенности. Смотрите, слева находится фронтенд, клики и всё, что происходит, а справа бэкенд. Как видите, это одна из особенностей, о которых я рассказывал: side by side.
То есть я вижу в реальном времени, что сначала выполнился такой кусок фронтедной кодовой базы, а потом справа выполнился совершенно другой кусочек кодовой базы, но уже на бэкенде, и все это с помощью определенного алгоритма матчится и отображается в реальном времени. Вы в реальном времени видите, что это нажатие на кнопку вызвало некие действия на бэкенде, а они потом вызвали ответные действия на фронтенде. Причем этих каналов может быть сколько захотите. Естественно, в разумных пределах, так, чтобы ваш браузер с этим справлялся.
Один из дополнительных плюсов, которые есть уже из коробки, — мини-карта. То, чего не хватает в SpyJS, и то, что было в TraceGL.
Еще один бонус — «быстрый поиск».
Все это возможно благодаря тому, что мы просто используем Monaco Editor. Он из коробки поддерживает множество вариантов, умеет делать fallback для старых систем. Мало того, из коробки получилось сделать syntax highlight для более полумиллиона строчек трассировочного кода. Этого более чем достаточно даже для очень большой сессии трассировки.
Единственный шаг, который необходимо будет потом сделать: почистить нашу кодовую базу как для фронтенда, так и для бэкенда.
Просто убрать всю эту отладочную информацию, когда она нам больше не нужна.
Теперь немножко про трасировочную информацию. Как она сейчас выглядит?
У нас есть названия наших функций, если у функции нет имени — оно формируется по некоему алгоритму в зависимости от того, где, когда и при каких условиях вызывается метод. В любом случае мы получаем информацию о том, когда мы зашли в функцию, когда из нее вышли, какой метод инициировал вызов другого метода и что это за методы. То есть мы получаем эту цепочку вызовов stack trace.
Также мы получаем информацию, где находится этот файл, его позицию, строку и колонку. Мы можем перейти в редактор по данному пути и продолжить исследование нашей кодовой базы там.
Мы получаем информацию об аргументах, которые были переданы. Изначально мы это делаем, копируя только верхнюю часть свойств объекта. Остальное превращается в запись вида [Object object]. Делаем мы это, потому что объекты иногда могут достигать множества мегабайтов в размере, поэтому по умолчанию ограничивается максимальный размер дампа. Но вы это сможете регулировать.
TraceMePlz — крут, но.
Возможно, неожиданное применение
Прежде чем мы закончим, я хочу рассказать про одно очень странное и неожиданное, возможно, применение. Все инструменты трассировки — замечательные, классные, но всегда возникает спор: «А он мне точно нужен?»
Однако есть один кейс, в котором инструменты трассировки мне помогали. А именно — увеличение bus factor (фактора автобуса). Для тех, кто не знает, bus factor — это когда один автобус сбивает одного программиста. Сколько таких автобусов нужно, чтобы остановилась разработка нашего проекта, то есть сколько людей должен сбить автобус, чтобы мы перестали понимать, что происходит в нашем проекте?
Так вот, в проектах с большой кодовой базой, которые еще и живут очень долго, bus factor часто стремится к нулю. Чтобы этого избежать, у нас есть один маленький трюк — трассировщик. Вы не представляете, сколько раз он меня спасал. Он помогал мне вливаться в кодовую базу очень быстро без какой-либо помощи. Я просто запускал трассировщик, выполнял некие действия и тут же в реальном времени понимал, что происходит с системой, как она работает. И это очень-очень круто.
Мало того, в TraceMePlz есть встроенная возможность сделать Diff и визуально понять, в чем отличие работающего кода от неработающего.
Вы можете даже не разбираться в кодовой базе, а просто найти место первого отличия. Часто проблема будет именно в нем.
Прислушивайтесь к себе и своему коду, обязательно пользуйтесь инструментами для трассировки.
Подписывайтесь на мой телеграм-канал. Там обязательно будет отдельный анонс о релизе TraceMePlz.















