¿Cómo obtener el seguimiento de la pila de errores en el script de contenido de la extensión de Chrome?

Hay un Extensión de Google Chrome con content script que maneja los errores JS ocurridos en todas las páginas de pestañas. Pero el problema es que ninguno de los métodos habituales para obtener el seguimiento de la pila de errores no funciona.

Por ejemplo, hay un código en content script de la extensión de Chrome:

window.addEventListener('error', function(event) {
    console.log(event.error.stack); // event.error will be null
}, false);

Si llamo a este código dentro de la página web, entonces event.error contendrá Error objeto con stack propiedad.

El mismo problema al intentar obtener el seguimiento de la pila usando:

console.log((new Error()).stack));

¿Alguien sabe algún problema de trabajo para obtener el seguimiento de la pila de errores en el interior? content script de la extensión de Chrome?

El seguimiento de la pila de errores debe recibirse como string or Array, significa no solo como una salida en la consola JS llamando console.trace().

Como reproducirse:

  1. Descargar https://mega.co.nz/#!ENw00YAC!92gBZEoLCO9jPsWyKht4dbjYyo0Zk-PU5YAj0h88-3Q
  2. Deshacer jzen.zip Para algo /jsen carpeta
  3. Abierta chrome://extensions en su Google Chrome, habilite Developer mode http://i.imgur.com/5x5D6NP.png
  4. Presione Load unpacked extension botón y seleccione la ruta a /jsen carpeta
  5. Abierta /jsen/content.js archivar y agregar console.log('JSEN', e.error.stack); dentro window.addEventListener('error', function(e) {
  6. Ve a http://xpart.ru/_share/js.htm y vea el resultado en la consola JS (Ctrl + Shift + J)
  7. Intenta editar /jsen/content.js para obtener el seguimiento de error correcto
  8. Para reinicializar el código fuente de la extensión de Chrome, haga clic en http://i.imgur.com/SjFgkHA.png

preguntado el 02 de diciembre de 13 a las 08:12

Debe mencionar que desea el seguimiento de la pila como una cadena, no es suficiente que se muestre en la consola. La pregunta es un poco engañosa. -

@Tibos Gracias por el comentario. He actualizado la pregunta. -

2 Respuestas

Como mencionas, el error propiedad del objeto de evento es null al capturar el evento en el contexto de Content Script, pero tiene la información requerida cuando se captura en el contexto de la página web. Entonces, la solución es capturar el evento en el contexto de la página web y usar la mensajería para enviarlo al script de contenido.

// This code will be injected to run in webpage context
function codeToInject() {
    window.addEventListener('error', function(e) {
        var error = {
            stack: e.error.stack
            // Add here any other properties you need, like e.filename, etc...
        };
        document.dispatchEvent(new CustomEvent('ReportError', {detail:error}));
    });
}

document.addEventListener('ReportError', function(e) {
    console.log('CONTENT SCRIPT', e.detail.stack);
});

//Inject code
var script = document.createElement('script');
script.textContent = '(' + codeToInject + '())';
(document.head||document.documentElement).appendChild(script);
script.parentNode.removeChild(script);

Las técnicas utilizadas se describen en:

contestado el 23 de mayo de 17 a las 12:05

+1 Me ganaste por 6 minutos con una respuesta probablemente más sólida. Impresionante cómo Rob ya ha publicado excelentes respuestas detalladas sobre cualquier Futuro Preguntas relacionadas con Chrome-Extension :) - gkalpak

¿Esta respuesta sigue siendo válida en Chrome? Después de probar ambas soluciones a la T, el objeto event.error sigue siendo nulo. - jsutton

@jsutton sí, lo acabo de probar en 42.0.2311.152 m y funciona. - rsanchez

Tengo un problema un poco específico: esta implementación funciona para mí con un archivo html local con mi script en el medio <script> etiquetas, aunque cuando separo mi js en un archivo local separado y uso <script src="script.js">, ya no puedo escuchar los errores y, en cambio, obtengo esto en mi consola: Uncaught TypeError: Cannot read property 'stack' of null. Pero, cuando subo mis archivos html y js a mi servidor web a través de ftp, la implementación funciona en línea en mi sitio web. ¿Alguna idea de por qué no puedo leer la pila localmente? - Hacker de Noam

en realidad, parece que una vez en mi servidor, los contenidos de mi secuencia de comandos externa se agregan a la carga de la página web, mientras que localmente no se agregan. es decir, el javascript no se procesa en el html cuando se desarrolla localmente - Hacker de Noam

El problema

El principal problema es Aislamiento de contexto JS, es decir, el hecho de que "Los scripts de contenido se ejecutan en un entorno especial llamado mundo aislado". Esto es algo bueno, por supuesto, porque evita conflictos y mejora la seguridad, pero sigue siendo un problema si desea detectar errores.

Cada mundo aislado ve su propia versión del objeto (ventana). La asignación al objeto afecta a su copia independiente del objeto...

... ninguno puede leer el controlador de eventos del otro. Los controladores de eventos se llaman en el orden en que fueron asignados.


Una solución

Una posible solución (también conocida como pirateo) consta de los siguientes pasos:

  1. Inyecte algo de código en la propia página web (e intente que sea lo más discreto posible para evitar conflictos).
  2. En ese código, registre un detector de eventos para errores y almacene los datos de error en un nodo DOM. datos.
  3. Finalmente, desde el script de contenido, use un MutaciónObservador para observar los cambios en los atributos de este nodo DOM.
  4. Una vez que un cambio en el especificado datos-<...> se detecta el atributo, tome su nuevo valor y ahí tiene su información de error directamente en su script de contenido :)

El código fuente

A continuación se muestra el código fuente de una extensión de muestra que hace exactamente eso.

manifiesto.json:

{
    "manifest_version": 2,

    "name":    "Test Extension",
    "version": "0.0",

    "content_scripts": [{
        "matches":    ["*://*/*"],
        "js":         ["content.js"],
        "run_at":     "document_start",
        "all_frames": true
    }],
}

contenido.js:

/* This <script> element will function as an "error-proxy" 
 * for the content-script */
var errorProxy = document.createElement('script');
errorProxy.id = 'myErrorProxyScriptID';
errorProxy.dataset.lastError = '';

/* Make the content as non-obtrusive as possible */
errorProxy.textContent = [
    '',
    '(function() {',
    '    var script = document.querySelector("script#' + errorProxy.id + '");',
    '    window.addEventListener("error", function(evt) {',
    '        script.dataset.lastError = evt.error.stack;',
    '    }, true);',
    '})();',
    ''].join('\n');

/* Add the <script> element to the DOM */
document.documentElement.appendChild(errorProxy);

/* Create an observer for `errorProxy`'s attributes
 * (the `data-last-error` attribute is of interest) */
var errorObserver = new MutationObserver(function(mutations) {
    mutations.forEach(function(mutation) {
        if ((mutation.type === 'attributes')
                && (mutation.attributeName === 'data-last-error')) {
            console.log('Content script detected new error:\n',
                        errorProxy.dataset.lastError);
        }
    });
});
errorObserver.observe(errorProxy, { attributes: true });

Respondido el 08 de diciembre de 13 a las 15:12

gracias por una solución de trabajo más con una descripción tan detallada. ¡Parece que eres realmente un buen experto! :) - barbusín

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.