From 389827193ddd2f7a539f89e33a2482eae1c7146c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pasternak?= Date: Sat, 25 Jul 2026 00:29:25 +0200 Subject: [PATCH 1/2] =?UTF-8?q?fix(rollbar):=20odsiej=20z=20frontendu=20ob?= =?UTF-8?q?ce=20skrypty=20i=20zg=C5=82oszenia=20bez=20stack=20trace'u?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Trzy aktywne itemy browser-js okazały się nie-naszymi błędami: - #1477 "Invalid regular expression: invalid group specifier name" — plik to cdn.userway.org/widgetapp/.../widget_app_base.js, czyli bundle widgetu dostępności UserWay. Lookbehind w regexie, nieobsługiwany przez Safari < 16.4 (zgłoszenia z Safari 15.6.1). Ich kod, ich wydanie. - #444 "(unknown): {}" — original_arg_types to ["string","htmllinkelement", "undefined"], a w telemetrii tuż przed tym fetch do api.userway.org. To zdarzenie error na elemencie (nieudane ładowanie arkusza), które Rollbar serializuje do bezużytecznego "{}". - #502 "Unexpected token =" — Chrome 64 na Androidzie 8 (luty 2018). Brak filename i lineno; stack to sam komunikat. Pola klas w ciele `class` weszły w Chrome 72. Żadnego z nich nie da się naprawić w kodzie BPP ani nawet zdiagnozować. checkIgnore odsiewa więc: (a) błędy, których WSZYSTKIE ramki pochodzą z obcego origin, (b) zgłoszenia bez użytecznej ścieżki w żadnej ramce. Predykat siedzi w osobnym pliku statycznym, nie w szablonie, żeby dało się go przetestować (11 testów vitest). Jest zwykłym skryptem, nie modułem — rollbar.html ładuje go wcześnie w , a type="module" odroczyłby wykonanie i część błędów z czasu ładowania strony uciekłaby. Filtr jest fail-open: brak skryptu albo wyjątek w samym filtrze → raportuj. Filtr, który przez własną awarię chowa prawdziwe błędy, jest gorszy niż brak filtra. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01NcAqeqyqBzNEkkVnhpHDaH --- .../+rollbar-browser-szum.bugfix.rst | 4 + src/bpp/static/bpp/js/rollbar-filters.js | 93 ++++++++++++++ src/django_bpp/templates/rollbar.html | 19 +++ tests/js/rollbar-filters.test.js | 121 ++++++++++++++++++ 4 files changed, 237 insertions(+) create mode 100644 src/bpp/newsfragments/+rollbar-browser-szum.bugfix.rst create mode 100644 src/bpp/static/bpp/js/rollbar-filters.js create mode 100644 tests/js/rollbar-filters.test.js diff --git a/src/bpp/newsfragments/+rollbar-browser-szum.bugfix.rst b/src/bpp/newsfragments/+rollbar-browser-szum.bugfix.rst new file mode 100644 index 000000000..582f3e200 --- /dev/null +++ b/src/bpp/newsfragments/+rollbar-browser-szum.bugfix.rst @@ -0,0 +1,4 @@ +Monitoring błędów po stronie przeglądarki przestał zbierać zgłoszenia, na +które nie da się zareagować: awarie pochodzące wyłącznie z obcych skryptów +(np. widget dostępności ładowany z zewnętrznego serwera) oraz zdarzenia bez +informacji o pliku i linii. Błędy z kodu BPP są raportowane jak dotąd. diff --git a/src/bpp/static/bpp/js/rollbar-filters.js b/src/bpp/static/bpp/js/rollbar-filters.js new file mode 100644 index 000000000..48d6be062 --- /dev/null +++ b/src/bpp/static/bpp/js/rollbar-filters.js @@ -0,0 +1,93 @@ +// Filtr zgłoszeń dla frontendowego Rollbara (`checkIgnore`). +// +// Odsiewamy dwie klasy zgłoszeń, z którymi NIC nie da się zrobić: +// +// 1. Błędy pochodzące wyłącznie z obcych skryptów — u nas w praktyce widget +// dostępności UserWay, ładowany z ich CDN-u. Przykład: SyntaxError +// "invalid group specifier name" (lookbehind w regexie, nieobsługiwany +// przez Safari < 16.4). To ich bundle, ich wydanie — nie mamy jak tego +// naprawić ani nawet zdiagnozować. +// +// 2. Zgłoszenia bez użytecznego stack trace'u — brak ramek, filename +// "(unknown)" albo filename będący komunikatem błędu. Powstają m.in. gdy +// window.onerror dostaje zdarzenie zamiast Errora (nieudane ładowanie +// , serializowane przez Rollbara do "{}") albo gdy przeglądarka jest +// tak stara, że nie podaje lokalizacji (Chrome 64 na Androidzie 8). +// Bez pliku i linii nie ma czego szukać. +// +// ZASADA: w razie wątpliwości RAPORTUJ. Filtr, który przez własny błąd +// wycisza prawdziwe awarie, jest gorszy niż brak filtra — dlatego każda +// nierozpoznana sytuacja (brak payloadu, nieznany kształt) daje `false`. +// +// Ten plik jest ZWYKŁYM skryptem, nie modułem: rollbar.html ładuje go wcześnie +// w , a `type="module"` odroczyłby wykonanie i część błędów z czasu +// ładowania strony uciekłaby przed inicjalizacją Rollbara. +(function (root) { + "use strict"; + + // Czy `filename` w ogóle wskazuje na jakiś plik? Rollbar wstawia tu + // czasem "(unknown)" albo — dla przeglądarek nie podających lokalizacji — + // sam komunikat błędu ("SyntaxError: Unexpected token ="). + function czyUzytecznaSciezka(filename) { + if (!filename || typeof filename !== "string") { + return false; + } + return /^https?:\/\//.test(filename) || filename.charAt(0) === "/"; + } + + function czyNaszaSciezka(filename, origin) { + if (filename.charAt(0) === "/") { + // Ścieżka względna → zawsze z bieżącego origin. + return true; + } + return filename.indexOf(origin + "/") === 0 || filename === origin; + } + + // Rollbar zapisuje ramki w `body.trace.frames` albo — dla wyjątków + // łańcuchowych — w `body.trace_chain[].frames`. + function zbierzRamki(payload) { + var body = (payload && payload.body) || {}; + var ramki = []; + + if (body.trace && Array.isArray(body.trace.frames)) { + ramki = ramki.concat(body.trace.frames); + } + if (Array.isArray(body.trace_chain)) { + body.trace_chain.forEach(function (trace) { + if (trace && Array.isArray(trace.frames)) { + ramki = ramki.concat(trace.frames); + } + }); + } + return ramki; + } + + function czyPominac(payload, origin) { + if (!payload || !payload.body || !origin) { + return false; + } + + var sciezki = zbierzRamki(payload) + .map(function (ramka) { + return ramka && ramka.filename; + }) + .filter(czyUzytecznaSciezka); + + if (!sciezki.length) { + // Nic, co dałoby się zlokalizować w kodzie. + return true; + } + + var mamyNaszaRamke = sciezki.some(function (sciezka) { + return czyNaszaSciezka(sciezka, origin); + }); + + // Choć jedna ramka z naszego kodu → to może być nasz błąd, raportuj. + return !mamyNaszaRamke; + } + + root.bppRollbarFilters = { + czyPominac: czyPominac, + czyUzytecznaSciezka: czyUzytecznaSciezka, + }; +})(typeof window !== "undefined" ? window : this); diff --git a/src/django_bpp/templates/rollbar.html b/src/django_bpp/templates/rollbar.html index d0884d7c4..ba02fafd0 100644 --- a/src/django_bpp/templates/rollbar.html +++ b/src/django_bpp/templates/rollbar.html @@ -4,12 +4,31 @@ {# Biblioteka hostowana lokalnie ze static (nie CDN). #} {# Bez danych użytkownika (person) i bez gejtowania zgodą cookie. #} +{# Filtr szumu (obce skrypty, zgłoszenia bez stack trace'u) — testowany #} +{# jednostkowo w tests/js/rollbar-filters.test.js. #} +