trackCallbacks = $.Callbacks( 'memory' ),
trackQueue = [];
- /**
- * Log a message to window.console, if possible.
- *
- * Useful to force logging of some errors that are otherwise hard to detect (i.e., this logs
- * also in production mode). Gets console references in each invocation instead of caching the
- * reference, so that debugging tools loaded later are supported (e.g. Firebug Lite in IE).
- *
- * @private
- * @method log_
- * @param {string} msg Text for the log entry.
- * @param {Error} [e]
- */
- function log( msg, e ) {
- var console = window.console;
- if ( console && console.log ) {
- console.log( msg );
- // If we have an exception object, log it to the error channel to trigger a
- // proper stacktraces in browsers that support it. No fallback as we have no browsers
- // that don't support error(), but do support log().
- if ( e && console.error ) {
- console.error( String( e ), e );
- }
- }
- }
-
/**
* Create an object that can be read from or written to from methods that allow
* interaction both with single and multiple properties at once.
* error is not module-related or the module cannot be easily identified due to
* batched handling.
* @param {string} source Source of the error. Possible values:
+ *
* - style: stylesheet error (only affects old IE where a special style loading method
* is used)
* - load-callback: exception thrown by user callback
* - module-execute: exception thrown by module code
+ * - store-eval: could not evaluate module code cached in localStorage
+ * - store-localstorage-init: localStorage or JSON parse error in mw.loader.store.init
+ * - store-localstorage-json: JSON conversion error in mw.loader.store.set
+ * - store-localstorage-update: localStorage or JSON conversion error in mw.loader.store.update
+ */
+
+ /**
+ * Fired via mw.track on resource loading error conditions.
+ *
+ * @event resourceloader_assert
+ * @param {string} source Source of the error. Possible values:
+ *
+ * - bug-T59567: failed to cache script due to an Opera function -> string conversion
+ * bug; see <https://phabricator.wikimedia.org/T59567> for details
*/
/**
try {
styleEl.styleSheet.cssText += cssText;
} catch ( e ) {
- log( 'Stylesheet error', e );
mw.track( 'resourceloader.exception', { exception: e, source: 'stylesheet' } );
}
} else {
} catch ( e ) {
// A user-defined callback raised an exception.
// Swallow it to protect our state machine!
- log( 'Exception thrown by user callback', e );
- mw.track( 'resourceloader.exception',
- { exception: e, module: module, source: 'load-callback' } );
+ mw.track( 'resourceloader.exception', { exception: e, module: module, source: 'load-callback' } );
}
}
}
} catch ( e ) {
// This needs to NOT use mw.log because these errors are common in production mode
// and not in debug mode, such as when a symbol that should be global isn't exported
- log( 'Exception thrown by ' + module, e );
registry[module].state = 'error';
mw.track( 'resourceloader.exception', { exception: e, module: module, source: 'module-execute' } );
handlePending( module );
// repopulate these modules to the cache.
// This means that at most one module will be useless (the one that had
// the error) instead of all of them.
- log( 'Error while evaluating data from mw.loader.store', err );
+ mw.track( 'resourceloader.exception', { exception: err, source: 'store-eval' } );
origBatch = $.grep( origBatch, function ( module ) {
return registry[module].state === 'loading';
} );
return;
}
} catch ( e ) {
- log( 'Storage error', e );
+ mw.track( 'resourceloader.exception', { exception: e, source: 'store-localstorage-init' } );
}
if ( raw === undefined ) {
JSON.stringify( descriptor.messages ),
JSON.stringify( descriptor.templates )
];
- // Attempted workaround for a possible Opera bug (bug 57567).
+ // Attempted workaround for a possible Opera bug (bug T59567).
// This regex should never match under sane conditions.
if ( /^\s*\(/.test( args[1] ) ) {
args[1] = 'function' + args[1];
- log( 'Detected malformed function stringification (bug 57567)' );
+ mw.track( 'resourceloader.assert', { source: 'bug-T59567' } );
}
} catch ( e ) {
- log( 'Storage error', e );
+ mw.track( 'resourceloader.exception', { exception: e, source: 'store-localstorage-json' } );
return;
}
data = JSON.stringify( mw.loader.store );
localStorage.setItem( key, data );
} catch ( e ) {
- log( 'Storage error', e );
+ mw.track( 'resourceloader.exception', { exception: e, source: 'store-localstorage-update' } );
}
}
// @deprecated since 1.23 Use $ or jQuery instead
mw.log.deprecate( window, '$j', $, 'Use $ or jQuery instead.' );
+ /**
+ * Log a message to window.console, if possible.
+ *
+ * Useful to force logging of some errors that are otherwise hard to detect (i.e., this logs
+ * also in production mode). Gets console references in each invocation instead of caching the
+ * reference, so that debugging tools loaded later are supported (e.g. Firebug Lite in IE).
+ *
+ * @private
+ * @method log_
+ * @param {string} topic Stream name passed by mw.track
+ * @param {Object} data Data passed by mw.track
+ * @param {Error} [data.exception]
+ * @param {string} data.source Error source
+ * @param {string} [data.module] Name of module which caused the error
+ */
+ function log( topic, data ) {
+ var msg,
+ e = data.exception,
+ source = data.source,
+ module = data.module,
+ console = window.console;
+
+ if ( console && console.log ) {
+ msg = ( e ? 'Exception' : 'Error' ) + ' in ' + source;
+ if ( module ) {
+ msg += ' in module ' + module;
+ }
+ msg += ( e ? ':' : '.' );
+ console.log( msg );
+
+ // If we have an exception object, log it to the error channel to trigger a
+ // proper stacktraces in browsers that support it. No fallback as we have no browsers
+ // that don't support error(), but do support log().
+ if ( e && console.error ) {
+ console.error( String( e ), e );
+ }
+ }
+ }
+
+ // subscribe to error streams
+ mw.trackSubscribe( 'resourceloader.exception', log );
+ mw.trackSubscribe( 'resourceloader.assert', log );
+
// Attach to window and globally alias
window.mw = window.mediaWiki = mw;
}( jQuery ) );