Gilles has uploaded a new change for review. https://gerrit.wikimedia.org/r/174933
Change subject: [WIP] Track the most recent upload time for performance events ...................................................................... [WIP] Track the most recent upload time for performance events Change-Id: I673f9487deea15dc148452a3a4d6b91563a2c417 Mingle: https://wikimedia.mingle.thoughtworks.com/projects/multimedia/cards/975 --- M MultimediaViewer.php M resources/mmv/logging/mmv.logging.PerformanceLogger.js M resources/mmv/mmv.js M resources/mmv/mmv.lightboximage.js M resources/mmv/model/mmv.model.Image.js M resources/mmv/provider/mmv.provider.Image.js 6 files changed, 56 insertions(+), 41 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/MultimediaViewer refs/changes/33/174933/1 diff --git a/MultimediaViewer.php b/MultimediaViewer.php index 7a47510..dae2dad 100644 --- a/MultimediaViewer.php +++ b/MultimediaViewer.php @@ -1052,7 +1052,7 @@ $wgHooks['EventLoggingRegisterSchemas'][] = function( array &$schemas ) { $schemas += array( 'MediaViewer' => 10536413, - 'MultimediaViewerNetworkPerformance' => 7917896, + 'MultimediaViewerNetworkPerformance' => 10596581, 'MultimediaViewerDuration' => 10427980, 'MultimediaViewerAttribution' => 9758179, 'MultimediaViewerDimensions' => 10014238, diff --git a/resources/mmv/logging/mmv.logging.PerformanceLogger.js b/resources/mmv/logging/mmv.logging.PerformanceLogger.js index bfde462..d665996 100644 --- a/resources/mmv/logging/mmv.logging.PerformanceLogger.js +++ b/resources/mmv/logging/mmv.logging.PerformanceLogger.js @@ -62,9 +62,10 @@ * cached by the browser, as it will consume unnecessary bandwidth for the user. * @param {string} type the type of request to be measured * @param {string} url URL to be measured + * @param {jQuery.Promise.<string>} uploadDateTimePromise A promise which resolves to the image upload timestamp. * @returns {jQuery.Promise} A promise that resolves when the contents of the URL have been fetched */ - PL.record = function ( type, url ) { + PL.record = function ( type, url, uploadDateTimePromise ) { var deferred = $.Deferred(), request, perf = this, @@ -89,7 +90,7 @@ if ( request.readyState === 4 ) { deferred.notify( request.response, 100 ); deferred.resolve( request.response ); - perf.recordEntryDelayed( type, total, url, request ); + perf.recordEntryDelayed( type, total, url, request, uploadDateTimePromise ); } }; @@ -111,9 +112,11 @@ * @param {number} total the total load time tracked with a basic technique * @param {string} url URL of that was measured * @param {XMLHttpRequest} request HTTP request that just completed + * @param {jQuery.Promise.<string>} uploadDateTimePromise A promise which resolves to the image upload timestamp. */ - PL.recordEntry = function ( type, total, url, request ) { + PL.recordEntry = function ( type, total, url, request, uploadDateTimePromise ) { var matches, + logger = this, stats = { type: type, contentHost: window.location.host, isHttps: window.location.protocol === 'https:', @@ -165,7 +168,17 @@ } } - this.log( stats ); + if ( uploadDateTimePromise ) { // Only defined for images + uploadDateTimePromise.done( function ( uploadDateTime ) { + stats.uploadTimestamp = uploadDateTime; + logger.log( stats ); + } ) + .fail( function() { + logger.log( stats ); + } ); + } else { + this.log( stats ); + } }; /** @@ -305,14 +318,15 @@ * @param {number} total the total load time tracked with a basic technique * @param {string} url URL of that was measured * @param {XMLHttpRequest} request HTTP request that just completed + * @param {jQuery.Promise.<string>} uploadDateTimePromise A promise which resolves to the image upload timestamp. */ - PL.recordEntryDelayed = function ( type, total, url, request ) { + PL.recordEntryDelayed = function ( type, total, url, request, uploadDateTimePromise ) { var perf = this; // The timeout is necessary because if there's an entry in window.performance, // it hasn't been added yet at this point setTimeout( function() { - perf.recordEntry( type, total, url, request ); + perf.recordEntry( type, total, url, request, uploadDateTimePromise ); }, 0 ); }; @@ -402,6 +416,15 @@ return new XMLHttpRequest(); }; + /** + * @override + * @inheritdoc + */ + PL.log = function ( data ) { + mw.log( 'mw.mmv.logging.PerformanceLogger', data ); + return mw.mmv.logging.Logger.prototype.log.call( this, data ); + } + new PerformanceLogger().init(); mw.mmv.logging.PerformanceLogger = PerformanceLogger; diff --git a/resources/mmv/mmv.js b/resources/mmv/mmv.js index 99ebb92..74afe4f 100644 --- a/resources/mmv/mmv.js +++ b/resources/mmv/mmv.js @@ -306,15 +306,8 @@ return; } - uploadTimestamp = imageInfo.uploadDateTime.toString(); - // Convert to "timestamp" format commonly used in EventLogging - uploadTimestamp = uploadTimestamp.replace( /[:\s]/g, '' ); - // Anonymise the timestamp to avoid making the file identifiable - // We only need to know the day - uploadTimestamp = uploadTimestamp.substr( 0, uploadTimestamp.length - 6 ) + '000000'; - mw.mmv.durationLogger.record( 'click-to-first-image', { - uploadTimestamp: uploadTimestamp + uploadTimestamp: imageInfo.uploadDateTime } ); } ); } @@ -324,6 +317,8 @@ } ); metadataPromise.done( function ( imageInfo, repoInfo, userInfo ) { + image.uploadDateTimePromise.resolve( imageInfo.uploadDateTime ); + if ( viewer.currentIndex !== image.index ) { return; } @@ -337,6 +332,8 @@ // File reuse steals a bunch of information from the DOM, so do it last viewer.ui.setFileReuseData( imageInfo, repoInfo, image.caption ); } ).fail( function ( error ) { + image.uploadDateTimePromise.reject(); + if ( viewer.currentIndex !== image.index ) { return; } @@ -729,7 +726,8 @@ width, image.src, image.originalWidth, - image.originalHeight + image.originalHeight, + image.uploadDateTimePromise ); }; @@ -740,11 +738,12 @@ * @param {string} [sampleUrl] a thumbnail URL for the same file (but with different size) (might be missing) * @param {number} [originalWidth] the width of the original, full-sized file (might be missing) * @param {number} [originalHeight] the height of the original, full-sized file (might be missing) + * @param {jQuery.Promise.<string>} uploadDateTimePromise Promise that resolves to the image's upload timestamp when the metadata is loaded * @returns {jQuery.Promise.<mw.mmv.model.Thumbnail, HTMLImageElement>} A promise resolving to * a thumbnail model and an <img> element. It might or might not have progress events which * return a single number. */ - MMVP.fetchThumbnail = function ( fileTitle, width, sampleUrl, originalWidth, originalHeight ) { + MMVP.fetchThumbnail = function ( fileTitle, width, sampleUrl, originalWidth, originalHeight, uploadDateTimePromise ) { var viewer = this, guessing = false, thumbnailPromise, @@ -771,7 +770,7 @@ } imagePromise = thumbnailPromise.then( function ( thumbnail ) { - return viewer.imageProvider.get( thumbnail.url ); + return viewer.imageProvider.get( thumbnail.url, uploadDateTimePromise ); } ); if ( guessing ) { @@ -780,7 +779,7 @@ // because thumbnailInfoProvider.get is already called above when guessedThumbnailInfoProvider.get fails. imagePromise = imagePromise.then( null, function () { return viewer.thumbnailInfoProvider.get( fileTitle, width ).then( function ( thumbnail ) { - return viewer.imageProvider.get( thumbnail.url ); + return viewer.imageProvider.get( thumbnail.url, uploadDateTimePromise ); } ); } ); } diff --git a/resources/mmv/mmv.lightboximage.js b/resources/mmv/mmv.lightboximage.js index 0916720..918f886 100644 --- a/resources/mmv/mmv.lightboximage.js +++ b/resources/mmv/mmv.lightboximage.js @@ -52,25 +52,10 @@ /** @property {number|undefined} originalHeight Height of the full-sized file (read from HTML data attribute, might be missing) */ this.originalHeight = undefined; + + /** @property {jQuery.Promise.<string>} uploadDateTimePromise Promise that resolves to the image's upload timestamp */ + this.uploadDateTimePromise = $.Deferred(); } - - var LIP = LightboxImage.prototype; - - /** - * The URL of the image (in the size we intend use to display the it in the lightbox) - * @type {String} - * @protected - */ - LIP.src = null; - - /** - * The URL of a placeholder while the image loads. Typically a smaller version of the image, which is already - * loaded in the browser. - * @type {String} - * @return {jQuery.Promise.<mw.mmv.LightboxImage, HTMLImageElement>} - * @protected - */ - LIP.initialSrc = null; mw.mmv.LightboxImage = LightboxImage; }( mediaWiki, jQuery ) ); diff --git a/resources/mmv/model/mmv.model.Image.js b/resources/mmv/model/mmv.model.Image.js index 8781aa5..18c9780 100644 --- a/resources/mmv/model/mmv.model.Image.js +++ b/resources/mmv/model/mmv.model.Image.js @@ -146,7 +146,13 @@ if ( extmeta ) { creationDateTime = this.parseExtmeta( extmeta.DateTimeOriginal, 'plaintext' ); - uploadDateTime = this.parseExtmeta( extmeta.DateTime, 'plaintext' ); + uploadDateTime = this.parseExtmeta( extmeta.DateTime, 'plaintext' ).toString(); + // Convert to "timestamp" format commonly used in EventLogging + uploadDateTime = uploadDateTime.replace( /[:\s]/g, '' ); + // Anonymise the timestamp to avoid making the file identifiable + // We only need to know the day + uploadDateTime = uploadDateTime.substr( 0, uploadDateTime.length - 6 ) + '000000'; + name = this.parseExtmeta( extmeta.ObjectName, 'plaintext' ); description = this.parseExtmeta( extmeta.ImageDescription, 'string' ); @@ -172,6 +178,7 @@ name = title.getNameText(); } + imageData = new Image( title, name, diff --git a/resources/mmv/provider/mmv.provider.Image.js b/resources/mmv/provider/mmv.provider.Image.js index 2eccd43..4816654 100644 --- a/resources/mmv/provider/mmv.provider.Image.js +++ b/resources/mmv/provider/mmv.provider.Image.js @@ -44,11 +44,12 @@ * Loads an image and returns it. Includes performance metrics via mw.mmv.logging.PerformanceLogger. * When the browser supports it, the image is loaded as an AJAX request. * @param {string} url + * @param {jQuery.Promise.<string>} uploadDateTimePromise A promise which resolves to the image upload timestamp. * @return {jQuery.Promise.<HTMLImageElement>} A promise which resolves to the image object. * When loaded via AJAX, it has progress events, which return an array with the content loaded * so far and with the progress as a floating-point number between 0 and 100. */ - Image.prototype.get = function ( url ) { + Image.prototype.get = function ( url, uploadDateTimePromise ) { var provider = this, cacheKey = url, extraParam = {}, @@ -65,12 +66,12 @@ if ( !this.cache[cacheKey] ) { if ( this.imagePreloadingSupported() ) { rawGet = $.proxy( provider.rawGet, provider, url, true ); - this.cache[cacheKey] = this.performance.record( 'image', url ).then( rawGet, rawGet ); + this.cache[cacheKey] = this.performance.record( 'image', url, uploadDateTimePromise ).then( rawGet, rawGet ); } else { start = $.now(); this.cache[cacheKey] = this.rawGet( url ); this.cache[cacheKey].always( function () { - provider.performance.recordEntry( 'image', $.now() - start, url ); + provider.performance.recordEntry( 'image', $.now() - start, url, undefined, uploadDateTimePromise ); } ); } this.cache[cacheKey].fail( function ( error ) { -- To view, visit https://gerrit.wikimedia.org/r/174933 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I673f9487deea15dc148452a3a4d6b91563a2c417 Gerrit-PatchSet: 1 Gerrit-Project: mediawiki/extensions/MultimediaViewer Gerrit-Branch: master Gerrit-Owner: Gilles <gdu...@wikimedia.org> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits