Обзор
breadcrumbsIntegration собирает след хлебных крошек за вас, так что каждое пойманное исключение приходит с записью того, что делали пользователь и приложение прямо перед ним. Она собирает пять независимых источников:
| Источник | type крошки | Что записывается |
|---|---|---|
console | console | Каждый вызов console.log/info/warn/error/debug с аргументами |
dom | interaction | Клики и нажатия клавиш (keydown) на элементе, названном так, как его назвал бы человек, — button "Pay" in dialog "Confirm order", см. Как называется элемент. Какой символ напечатан, не записывается никогда; именованная клавиша (Enter, Escape, Tab, …) записывается в data.key |
fetch | fetch | Метод, адрес и статус каждого запроса fetch() (уровень error при сбое или статусе не 2xx) |
xhr | xhr | То же для XMLHttpRequest |
history | navigation | Переходы в SPA (pushState и назад/вперёд) с адресами from и to |
Без sendDefaultPii значения параметров в адресах записываются как [Filtered], а по тексту называется только элемент управления (кнопка, ссылка, вкладка, …), но не любой другой элемент — см. Текст и приватность и Чувствительные данные. Отдельные крошки отбрасывайте или переписывайте опцией beforeBreadcrumb в init().
Собственные запросы SDK на /api/envelope пропускаются, так что след они не засоряют. Как след хранится и показывается в панели — на странице Хлебные крошки.
Нажатия клавиш читаются из keydown (а не из устаревшего keypress, который не срабатывает для Escape). Автоповтор удерживаемой клавиши и одиночные модификаторы (Shift, Control, …) игнорируются.
Как называется элемент
Хлебная крошка взаимодействия говорит, на что нажали, одним коротким именем, собранным из того, что написали вы и видел пользователь, — и одинаковым в каждой сборке, так что одно и то же действие — один и тот же шаг во всех срабатываниях инцидента:
click on button "Pay" in dialog "Confirm order"Текст и приватность
Прочитайте эту часть первой: имя может содержать текст вашей страницы.
- Собственный текст элемента управления читается по умолчанию. Подпись кнопки, ссылки или вкладки — ваша, а не пользователя, и без неё у большинства кнопок не было бы имени вовсе.
- Текст любого другого элемента (клик по абзацу, ячейке таблицы) читается только с
sendDefaultPii. - Значение не читается никогда: ни у
input, ни уselect, ни уtextarea, ни содержимоеcontenteditable,[role=textbox]или[role=combobox]. - Каждая подпись очищается, откуда бы ни взялась: пробелы схлопываются, email заменяется на
[Filtered], последовательность из четырёх и более цифр — на<num>, длина обрезается до 40 символов.
Остаётся элемент управления, текст которого принадлежит человеку, — ссылка «Иван Иванов» в списке клиентов, кнопка с названием аккаунта. Замаскируйте его:
html
<ul data-buglapse-mask>
<li><a href="/customers/17">John Smith</a></li>
</ul>Внутри data-buglapse-mask текст не читается, и элемент называется только по атрибутам (link, link "Customer" с aria-label). Классы интеграции записи по умолчанию, buglapse-mask и buglapse-block, делают то же самое: скрытое из записи скрыто и из следа. Если вы переименовали эти классы (maskTextClass, blockClass), используйте атрибут.
Какой элемент
Клик попадает в иконку кнопки или в span с её текстом. Крошка же — про элемент управления: ближайший из самого элемента и его предков, который является button, a[href], input, select, textarea, label, summary, contenteditable, элементом с интерактивной role (button, link, tab, menuitem, checkbox, radio, switch, option, combobox, textbox, …) или элементом с data-buglapse-name. Всё остальное остаётся собой. Поэтому клики по иконке и по тексту одной кнопки — одна серия и один rage click.
Имя
Берётся первое подходящее:
data-buglapse-name— ваше собственное имя элемента, используется как есть:html<button data-buglapse-name="checkout.pay">…</button>→
click on checkout.pay. Его ничто не переименует: ни редизайн, ни перевод.Роль и подпись —
button "Pay",link "Cart",input "Email",checkbox "Remember me". Подпись — первое непустое из:aria-label; текст элементов, на которые указываетaria-labelledby; для поля — его<label>, затемplaceholder, затемname(у кнопки-input подпись — еёvalue);title;altкартинки внутри; собственный текст элемента.Test id —
data-testid, иначеdata-test:button[checkout-pay].{role}#{id}, иначе только роль:button#pay,div.
Роль — атрибут role элемента, если он есть, иначе по тегу: a → link; button и input-кнопки → button; input[type=checkbox|radio] → этот тип; input[type=range] → slider; любой другой input → input; всё остальное — имя тега. CSS-классы никогда не входят в имя.
Где на странице
Один уровень контекста различает две кнопки «Удалить» — ближайший предок, который является
- элементом с
data-buglapse-name→in cart; dialog(илиrole="dialog"/"alertdialog") →in dialog "Confirm order"илиin dialogбез подписи;formсaria-label,aria-labelledby,nameилиid→in form "login";nav,header,footer,asideили соответствующей ролью-ориентиром →in nav, с еёaria-label, если он есть.
Контейнер подписывается только по атрибутам, никогда по тексту.
В крошке
data.target — имя, из него же собирается сообщение. data.path — CSS-путь элемента (div.flex.gap-2 > button.px-4.py-2, до пяти уровней и 200 символов) — чтобы найти элемент в разметке; в имени он не участвует и свободно меняется между сборками.
Поведения
Сырой журнал событий не говорит, что произошло: пять кликов подряд — пользователь долбит кнопку, которая не отвечает, двадцать одинаковых запросов — цикл, а набор email съел бы половину следа из 50 крошек. Поэтому интеграция вливает повтор в предыдущую крошку, а начиная с порога называет серию в data.kind:
data.kind | type | Когда | Сообщение |
|---|---|---|---|
rage_click | interaction | 3 и более клика по одному элементу, каждый в пределах 500 мс от предыдущего | rage click on {target} |
input | interaction | подряд идущие символьные клавиши в одном input, textarea, select или contenteditable | typed in {target} |
key_mash | interaction | Enter или Escape 3 и более раз, каждый в пределах 500 мс от предыдущего | mashed {key} on {target} |
request_loop | fetch / xhr | тот же метод, адрес и статус 5 и более раз, каждый в пределах 2 с от предыдущего | без изменений (GET /api/cart 200) |
error_storm | console | одно и то же сообщение console.error 5 и более раз подряд | без изменений |
slow_interaction | interaction | клик или нажатие клавиши, на которое страница отвечала дольше 500 мс (Event Timing API; пропускается, если браузер его не поддерживает) | slow click on {target} / slow key press on {target} |
reload | navigation | документ открыт перезагрузкой | Reloaded {url} |
Каждая слитая крошка несёт data.count (сколько событий она представляет) и data.duration_ms (от первого до последнего из них) и сохраняет timestamp первого. Серия ниже порога тоже сливается и сохраняет простой вид: два быстрых клика — один click on {target} с count: 2, три одинаковых запроса — одна крошка с count: 3. Сообщение никогда не содержит счётчика, так что одинаковое поведение читается одинаково в каждом срабатывании.
Как различаются серии:
- Клики объединяются, пока попадают в один элемент управления — его иконка и текст одно целое, а две кнопки, у которых просто одинаковое имя («Удалить» в двух строках списка), нет — и идут не реже чем раз в 500 мс. Уровень rage click —
warn. - Набор текста не ограничен по времени: с паузами это по-прежнему одна крошка
input, пока между нажатиями ничего не записано;Tab,Backspace,Deleteи стрелки внутри считаются набором.EnterиEscapeвсегда начинают свою серию. Символьная клавиша вне редактируемого элемента (горячая клавиша) — крошкаkeydown, которая считается, но никогда не называется. - Запросы реже одного в 2 с (обычный опрос) не сливаются никогда. Уровень цикла запросов —
warnилиerror, если запросы падали. - Вызовы консоли объединяются при одинаковых методе и сообщении;
data.args— от первого вызова.error_stormстановится толькоconsole.error. - Сливаются только соседние крошки. Всё, что записано между ними, заканчивает серию, так что цикл вперемешку с кликами виден как несколько коротких серий.
slow_interaction— отдельная крошка, которая добавляется после крошки клика (это становится известно только после отрисовки), сdata.duration_msиdata.event(clickилиkeydown).
Элементы, по которым кликают быстро намеренно
Клики по input[type=number], [role=spinbutton] и [role=slider] или внутри них считаются, но rage click не называются никогда. Для всего остального, по чему законно кликают сериями, — «+» у степпера, стрелка карусели — пометьте элемент или одного из его предков:
html
<button data-buglapse-rage="off">+</button>Выключение
ts
use(breadcrumbsIntegration({ behaviors: false }))записывает по крошке на событие: без слияния, без data.count, без названных видов, без крошек slow_interaction и reload. С подключением через CDN это переключатель Поведение в опциях интеграции в Настройки → Скрипт загрузчика.
Хлебная крошка путешествует с исключением, так что о поведении сообщается, только если за ним последовала ошибка, — кнопка, которая молча ничего не делает и ничего не бросает, ничего и не сообщит.
Использование
ts
import { use } from '@buglapse/browser'
import { breadcrumbsIntegration } from '@buglapse/browser/integrations'
use(breadcrumbsIntegration())
// или выключить отдельные источники:
use(breadcrumbsIntegration({ console: false, xhr: false }))Опции
| Опция | Тип | По умолчанию | Описание |
|---|---|---|---|
console | boolean | true | Записывать вызовы консоли |
dom | boolean | true | Записывать клики и нажатия клавиш |
fetch | boolean | true | Записывать запросы fetch() |
xhr | boolean | true | Записывать запросы XMLHttpRequest |
history | boolean | true | Записывать переходы в SPA |
behaviors | boolean | true | Сливать повторы в одну крошку и называть rage click, многократные нажатия клавиш, циклы запросов, шквалы ошибок, медленные взаимодействия и перезагрузки — см. Поведения |
Крошки консоли и ConsoleIntegration можно включить вместе — одна добавляет крошку на каждый вызов, другая отправляет событие лога на каждый вызов.