Sentry-javascript: Instrumentar EventTarget.prototype.addEventListener leva a problemas no Chrome

Criado em 14 mai. 2019  ·  28Comentários  ·  Fonte: getsentry/sentry-javascript

Pacote + Versão

  • [X] @sentry/browser 5.2.0

Descrição

Estamos recebendo este erro:

Cannot convert undefined or null to object

Parece que está acontecendo aqui, de acordo com o Chrome:

https://github.com/getsentry/sentry-javascript/blob/master/packages/browser/src/integrations/trycatch.ts#L88

Aqui está o rastreamento de pilha:

Screen Shot 2019-05-14 at 10 54 20 AM

Aqui está um instantâneo do erro no Chrome DevTools:

Screen Shot 2019-05-14 at 10 56 18 AM

Parece que o OpenLayers está gerando um erro, mas o Sentry não está lidando com isso corretamente e gerando um erro.

Help Wanted Needs Reproduction

Comentários muito úteis

Além disso, @kamilogorek , acho que esse problema deve ser reaberto.

Todos 28 comentários

Também estou encontrando esse erro. Isso ocorre às vezes ao chamar a função global addEventListener ou removeEventListener , ex:

addEventListener("someevent", callback)

Chamá-lo com um "este parâmetro" resolve o problema:

window.addEventListener("someevent", callback)

Infelizmente, não o reproduzo de forma consistente. A única coisa que consigo pensar é que, no primeiro caso, this é undefined (por causa do modo "use strict" ) e, no último caso, this seria window .

Estou usando @sentry/[email protected] . Parece ocorrer apenas nas versões recentes do Chrome / Chromium (74.0.3729 e 75.0.3770, veja os detalhes abaixo). O fato "engraçado" é: esse erro é relatado com bastante frequência, então esse é o principal motivo pelo qual minha cota de eventos Sentry se esgotou.

EDITAR: juntando uma captura de tela da lista detalhada de navegadores afetadosScreenshot_20190516_194938
Como você pode ver, isso parece começar a partir do Chrome 74.0.3729, que está no mercado desde 23 de abril.

Isso só acontece quando estamos usando OpenLayers para criar um novo mapa. Como resultado, decidi trocar OL por Leaflet (provavelmente uma boa jogada em geral), e estou apenas esperando que isso resolva meu problema.

Consegui escrever um programa mínimo para reproduzir isso de forma consistente. Basta executá-lo no seu console de devtools:

const original = EventTarget.prototype.addEventListener
EventTarget.prototype.addEventListener = function (eventName, fn, options) {
  "use strict"
  original.call(this, eventName, fn, options)
}

for (var i = 0; i < 100000; i += 1) {
  if (i % 100 === 0) console.log(i)
  addEventListener("mouseup", () => {})
}

No meu caso, ele lança após a 4600ª iteração.

Em uma nota semi-relacionada, quando eu removo o Sentry, LogRocket tropeça de uma maneira muito semelhante.

@BenoitZugmeyer @ffxsam obrigado pelo caso repro. Após uma investigação mais aprofundada, posso dizer que não é nosso problema SDK, é apenas o limite do Chrome para ouvintes de evento por objeto.

Quando você chama o repro acima em qualquer página (seja http://example.com), ele também não funciona. Não é necessário SDK.

listeners-repro

Sim, este é um problema do Chrome. Mas incluir seu SDK aciona esse problema, quebrando nosso código. Sorte minha que isso pode ser facilmente corrigido em minha base de código, mas eu ficaria um pouco irritado se ocorresse em uma dependência como @ffxsam

@BenoitZugmeyer como assim? Nós _não_ adicionamos nossos próprios ouvintes. Nós apenas interceptamos as chamadas do usuário para addEventListener . Se você não ligar, nós também não ligaremos.
E o problema não é acionado por nós, mas é relatado em nossa base de código, já que este é o lugar onde a invocação original termina.

Basicamente, em seu SDK, você está fazendo isso para interceptar addEventListener chamadas:

const original = EventTarget.prototype.addEventListener
EventTarget.prototype.addEventListener = function (eventName, fn, options) {
  "use strict"
  original.call(this, eventName, fn, options)
}

Remover essas linhas do trecho que forneci a você (ou seja: remover o SDK do meu código) corrige o problema: podemos adicionar quantos ouvintes de evento forem necessários. Portanto, é claro que você não adiciona ouvintes por conta própria, mas o bug do Chrome é acionado pela maneira como você está interceptando addEventListener chamadas.

@BenoitZugmeyer você está bem aqui, meu mal. É por causa do modo estrito mencionado. A única coisa que podemos fazer aqui é desabilitar, e tudo funcionará bem 🤷‍♂

const original = EventTarget.prototype.addEventListener
EventTarget.prototype.addEventListener = function (eventName, fn, options) {
  original.call(this, eventName, fn, options)
}

for (var i = 0; i < 100000; i += 1) {
  if (i % 100 === 0) console.log(i)
  addEventListener("mouseup", () => {})
}

Acho que você também pode fazer algo como original.call(this || window, ...) . O modo estrito não é adicionado na função como em meu snippet, mas nos arquivos dist gerados por sua configuração de compilação.

this || window alteraria efetivamente o comportamento do código dos desenvolvedores, então não tenho certeza sobre este.
use strict tem escopo de função e, como bundle.js define no topo (bem, o TypeScript faz isso para nós), também afeta o método de empacotamento mencionado acima:

/*! @sentry/browser 5.2.1 (a5b87c1e) | https://github.com/getsentry/sentry-javascript */
var Sentry = (function (exports) {
    'use strict';

Embora this || window corrija o problema, então ...: S e é como se 99,9% usecase que está vindo do proto da janela de qualquer maneira.

Relatei o problema aqui: https://bugs.chromium.org/p/chromium/issues/detail?id=964249

Eu acho que isso não alteraria o comportamento do código porque chamar a função addEventListener com undefined parece equivalente a chamá-la com o objeto global. Mas posso não pensar em todos os casos aí ...

Incrível, obrigado! Enquanto isso, https://github.com/getsentry/sentry-javascript/pull/2078

EDIT: encontrou uma solução alternativa mais limpa:

Sentry.init({
    ...
    // XXX: Workaround for https://github.com/getsentry/sentry-javascript/issues/2074
    defaultIntegrations: Sentry.defaultIntegrations.filter(({ name }) => name !== 'TryCatch'),
});

coisas antigas

Estou optando por esta solução alternativa por enquanto.

EventTarget.prototype.addEventListener = EventTarget.prototype.addEventListener.__sentry_original__;
EventTarget.prototype.removeEventListener = EventTarget.prototype.removeEventListener.__sentry_original__;

Esse problema está causando muito ruído para nós: Dezenas de milhares de eventos por hora, aproximadamente 1,8 milhões no total. Ansioso por uma correção. 😬

Screen Shot 2019-05-20 at 11 22 24 AM

@javan corrigiu os testes de relações públicas pendentes, lançaremos o patch esta semana.

Ainda estou vendo isso em @sentry/[email protected] .

Executar este trecho no console ainda lança quando o sentinela está habilitado.

for (var i = 0; i < 100000; i += 1) {
  if (i % 100 === 0) console.log(i)
  addEventListener("mouseup", () => {})
}

Mesmo. O problema ainda está presente na v5.3.0.

Exemplo: https://sentry-browser-chrome-bug.glitch.me
Fonte: https://glitch.com/edit/#!/sentry -browser-chrome-bug? Path = src / main.js: 18: 0


Captura de tela

Screen Shot 2019-05-24 at 8 39 53 PM


Parece que usar apply() vez de call() resolve o problema. Não tenho certeza se é uma solução viável para a implementação do Sentry.

Por exemplo, este snippet estimula o bug do Chrome:

const original = EventTarget.prototype.addEventListener
EventTarget.prototype.addEventListener = function(eventName, fn, options) {
  "use strict"
  original.call(this, eventName, fn, options)
}

let count = 0
while (count++ < 10000) addEventListener("click", console.log)

Este não:

const original = EventTarget.prototype.addEventListener
EventTarget.prototype.addEventListener = function() {
  "use strict"
  original.apply(this, arguments)
}

let count = 0
while (count++ < 10000) addEventListener("click", console.log)

Além disso, @kamilogorek , acho que esse problema deve ser reaberto.

Feito. Embora eu precise de algum tempo para dar uma olhada nisso, pois estou ocupado com outro trabalho. Qualquer ajuda apreciada :)

17 de maio de 2019
Relatei o problema aqui: https://bugs.chromium.org/p/chromium/issues/detail?id=964249

23 de maio de 2019
O problema do Chromium foi marcado como uma duplicata de https://bugs.chromium.org/p/chromium/issues/detail?id=961199 , que foi marcado como corrigido no mesmo dia.

13 de março de 2020
Eu me pergunto se isso ainda é um problema com as versões recentes do Chrome / Chromium e do Sentry JS SDK.

Não encontrei nenhum uso relevante de "use strict" no mestre, imagino que a implementação pode ter mudado um pouco desde que o problema foi relatado. Marcando isso como uma reprodução necessária por enquanto.

@rhcarvalho

Ainda vemos muitos erros provenientes do Chrome 74 Mobile.

Curiosamente, não há problema com bundle.min.js (de sentrycdn)
Começamos a ver esse problema quando mudamos para bundle.es6.min.js

Eu acho que o babel transpile de alguma forma elimina o uso de chamada de função com erros no Chrome 74

Nosso site completo visa apenas es6 (es2015), então esperamos usar o es6 build

image

@Fonger você pode fornecer um link para o evento afetado aqui ou diretamente para [email protected]? obrigado

@kamilogorek com certeza. acabei de enviar por email

Tínhamos revertido para usar bundle.min.js alguns minutos atrás.

Ei!

Desculpe por fazer um mais um sobre isso, mas parece que também estamos encontrando isso no codesandbox e também tem estado nas mãos:

103711776-6ad73e80-4fb8-11eb-86b7-e902874e30e3

O interessante é que parece acontecer apenas no Chrome em um Mac

Você pode ver o relatório de falha criado pelo usuário aqui: https://github.com/codesandbox/codesandbox-client/issues/5326

Deixe-me saber se você precisar de mais alguma coisa ou qualquer ajuda neste

Postagem cruzada para a referência: https://github.com/codesandbox/codesandbox-client/issues/5406#issuecomment -768339564

Esta página foi útil?
0 / 5 - 0 avaliações