mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/VisualEditor
synced 2024-11-30 00:55:00 +00:00
21f526bffe
In Schema:Edit, all action timing durations (ready, loaded, saveAttempt etc.) are defined as "time since the editor was initialised", which is internally stored as the timestamp for the "init" action. The 'init' action itself does not have a timing duratation, but the Edit schema has a special case for it, definining it as "time since the page was loaded". In actually, it isn't actually implemented as "time since the page loaded", and I suspect that as such, this value is probably not used by EventLogging consumers of the Edit schema. Or, it might be used, but doesn't represent what the consumers think it does. Presently, it uses the init time now() - mediaWikiLoadStart, which basically means the time between the random point at which MediaWiki core JavaScript finished executing which is quite variable in practice due to the race between <script async> and browssing parsing/rendering of HTML. That is by design, and is also why mediaWikiLoadStart is undocumented and internal, and actually in the process of being removed. After many iterations on this patch to try and approximate an alternative to this undocumented variable, I came up with an alternative approach with DLynch at the Hackathon, which is to simply not record this one timing value, but preserve the behaviour of all the other timing values exactly as-is. That is, keep the behaviour of storing `now()` as "init" when the editor activates, and keep the behaviour of substracting "init" from all other action times, but only don't report "init" itself to EventLogging (given its value would be 0, which isn't useful). Bug: T160315 Change-Id: I778234efe40dde8ff30333339335be1c3910a4e0
156 lines
4.5 KiB
JavaScript
156 lines
4.5 KiB
JavaScript
/*!
|
|
* VisualEditor MediaWiki event subscriber.
|
|
*
|
|
* Subscribes to ve.track() events and routes them to mw.track().
|
|
*
|
|
* @copyright 2011-2018 VisualEditor Team and others; see AUTHORS.txt
|
|
* @license The MIT License (MIT); see LICENSE.txt
|
|
*/
|
|
|
|
( function () {
|
|
var timing, editingSessionId;
|
|
|
|
if ( mw.loader.getState( 'schema.Edit' ) === null ) {
|
|
// Only route any events into the Edit schema if the module is actually available.
|
|
// It won't be if EventLogging is installed but WikimediaEvents is not.
|
|
return;
|
|
}
|
|
|
|
timing = {};
|
|
editingSessionId = mw.user.generateRandomSessionId();
|
|
|
|
function computeDuration( action, event, timeStamp ) {
|
|
if ( event.timing !== undefined ) {
|
|
return event.timing;
|
|
}
|
|
|
|
switch ( action ) {
|
|
case 'ready':
|
|
return timeStamp - timing.init;
|
|
case 'loaded':
|
|
return timeStamp - timing.init;
|
|
case 'saveIntent':
|
|
return timeStamp - timing.ready;
|
|
case 'saveAttempt':
|
|
return timeStamp - timing.saveIntent;
|
|
case 'saveSuccess':
|
|
case 'saveFailure':
|
|
// HERE BE DRAGONS: the caller must compute these themselves
|
|
// for sensible results. Deliberately sabotage any attempts to
|
|
// use the default by returning -1
|
|
mw.log.warn( 've.init.mw.trackSubscriber: Do not rely on default timing value for saveSuccess/saveFailure' );
|
|
return -1;
|
|
case 'abort':
|
|
switch ( event.type ) {
|
|
case 'preinit':
|
|
return timeStamp - timing.init;
|
|
case 'nochange':
|
|
case 'switchwith':
|
|
case 'switchwithout':
|
|
case 'switchnochange':
|
|
case 'abandon':
|
|
return timeStamp - timing.ready;
|
|
case 'abandonMidsave':
|
|
return timeStamp - timing.saveAttempt;
|
|
}
|
|
}
|
|
mw.log.warn( 've.init.mw.trackSubscriber: Unrecognized action', action );
|
|
return -1;
|
|
}
|
|
|
|
ve.trackSubscribe( 'mwedit.', function ( topic, data, timeStamp ) {
|
|
var action = topic.split( '.' )[ 1 ],
|
|
event;
|
|
|
|
timeStamp = timeStamp || this.timeStamp; // I8e82acc12 back-compat
|
|
|
|
if ( action === 'init' ) {
|
|
// Regenerate editingSessionId
|
|
editingSessionId = mw.user.generateRandomSessionId();
|
|
} else if (
|
|
action === 'abort' &&
|
|
( data.type === 'unknown' || data.type === 'unknown-edited' )
|
|
) {
|
|
if (
|
|
timing.saveAttempt &&
|
|
timing.saveSuccess === undefined &&
|
|
timing.saveFailure === undefined
|
|
) {
|
|
data.type = 'abandonMidsave';
|
|
} else if (
|
|
timing.init &&
|
|
timing.ready === undefined
|
|
) {
|
|
data.type = 'preinit';
|
|
} else if ( data.type === 'unknown' ) {
|
|
data.type = 'nochange';
|
|
} else {
|
|
data.type = 'abandon';
|
|
}
|
|
}
|
|
|
|
// Convert mode=source/visual to editor name
|
|
if ( data && data.mode ) {
|
|
data.editor = data.mode === 'source' ? 'wikitext-2017' : 'visualeditor';
|
|
delete data.mode;
|
|
}
|
|
|
|
event = $.extend( {
|
|
version: 1,
|
|
action: action,
|
|
editor: 'visualeditor',
|
|
platform: ve.init && ve.init.target && ve.init.target.constructor.static.platformType || 'other',
|
|
integration: ve.init && ve.init.target && ve.init.target.constructor.static.integrationType || 'page',
|
|
'page.id': mw.config.get( 'wgArticleId' ),
|
|
'page.title': mw.config.get( 'wgPageName' ),
|
|
'page.ns': mw.config.get( 'wgNamespaceNumber' ),
|
|
'page.revid': mw.config.get( 'wgRevisionId' ),
|
|
editingSessionId: editingSessionId,
|
|
'user.id': mw.user.getId(),
|
|
'user.editCount': mw.config.get( 'wgUserEditCount', 0 ),
|
|
'mediawiki.version': mw.config.get( 'wgVersion' )
|
|
}, data );
|
|
|
|
if ( mw.user.isAnon() ) {
|
|
event[ 'user.class' ] = 'IP';
|
|
}
|
|
|
|
event[ 'action.' + action + '.type' ] = event.type;
|
|
event[ 'action.' + action + '.mechanism' ] = event.mechanism;
|
|
if ( action !== 'init' ) {
|
|
event[ 'action.' + action + '.timing' ] = Math.round( computeDuration( action, event, timeStamp ) );
|
|
}
|
|
event[ 'action.' + action + '.message' ] = event.message;
|
|
|
|
// Remove renamed properties
|
|
delete event.type;
|
|
delete event.mechanism;
|
|
delete event.timing;
|
|
delete event.message;
|
|
|
|
if ( action === 'abort' ) {
|
|
timing = {};
|
|
} else {
|
|
timing[ action ] = timeStamp;
|
|
}
|
|
|
|
// Sample at 6.25%
|
|
if ( event.editingSessionId && event.editingSessionId[ 0 ] === '0' ) {
|
|
mw.track( 'event.Edit', event );
|
|
}
|
|
|
|
} );
|
|
|
|
ve.trackSubscribe( 'mwtiming.', function ( topic, data ) {
|
|
// Add type for save errors; not in the topic for stupid historical reasons
|
|
if ( topic === 'mwtiming.performance.user.saveError' ) {
|
|
topic = topic + '.' + data.type;
|
|
}
|
|
|
|
// Map mwtiming.foo --> timing.ve.foo.mobile
|
|
topic = topic.replace( /^mwtiming/, 'timing.ve.' + data.targetName );
|
|
mw.track( topic, data.duration );
|
|
} );
|
|
|
|
}() );
|