An Eventlogging adventure

Posted by The bugalore on Thursday, September 14, 2017

TOC

What the heck is eventlogging?

Eventlogging is a MediaWiki extension which lets us log events such as how users interact with a certain feature (client-side logging) or capturing the state of a system (user, permissions etc.) when a certain event happens (server-side logging). There are 3 different parts to eventlogging an event. The schema, the code and the log data. I won’t be going into the details of that because there’s a detailed guide for it.


Now we’ve got that out of the way, let’s take a look at the problem at hand.

My team is implementing the ACTRIAL experiment which will prevent non-autoconfirmed users from creating articles on English Wikipedia. The task was simple: Log which links were clicked from the landing page and how many times.

The schema was easy. The code involved loading a JS file on the landing page and tracking link clicks via eventlogging. The JS code was really simple too:

( function ( $, mw ) {

	function trackData( interactionType, link, sampling ) {
		mw.loader.using( 'schema.ArticleCreationWorkflow' ).then( function () {
			mw.eventLog.logEvent( 'ArticleCreationWorkflow', {
				interactionType: interactionType,
				link: link,
				sampling: sampling || 1
			}
		} );
	}

	$( 'html' ).on( 'click', '#bodyContent a', function ( event ) {
		var link = $( this ).attr( 'href' );
		trackData( 'click', link );
	} );

} ( jQuery, mediaWiki ) );

While this is the most common way of lazy loading eventlogging schemas, there’s a better and shorter way of doing it. Instead of -

mw.loader.using( 'schema.ArticleCreationWorkflow' ).then( function () {
	mw.eventLog.logEvent( 'ArticleCreationWorkflow', {
		interactionType: interactionType,
		link: link,
		sampling: sampling || 1
	}
} );

we can use -

mw.track( 'event.ArticleCreationWorkflow', {
	interactionType: interactionType,
	link: link,
	sampling: sampling || 1
} );

This is a log-and-forget way to use eventlogging while only using core interfaces. This code won’t produce an error if Eventlogging isn’t loaded. This lets us have our extension not to be dependent on Eventlogging.1

But remember, we need to load our schema in extension.json. Before mw.track, it was a simple matter of registering the script module -

"ResourceModules": {
	"ext.acw.eventlogging": {
		"scripts": [ "acw.eventlogging.js" ]
	}
},

But now in addition to that, you need to register your schema with the EventLoggingRegisterSchemas hook. So something like -

public static function onEventLoggingRegisterSchemas( array &$schemas ) {
	global $wgArticleCreationEventLoggingSchemas;
	foreach ( $wgArticleCreationEventLoggingSchemas as $schema => $property ) {
		if ( $property['enabled'] ) {
			$schemas[$schema] = $property['revision'];
		}
	}
}

With all of that in place, the only remaining thing is to hook up our code with the BeforePageDisplay MediaWiki hook, in order to inject our JS to the display before the page is rendered.

This is rather easy to do -

public static function onBeforePageDisplay( OutputPage $out ) {
	$config = MediaWikiServices::getInstance()
		->getConfigFactory()
		->makeConfig( 'ArticleCreationWorkflow' );
	$workflow = new Workflow( $config );
	if ( $out->getPageTitle() == $workflow->getLandingPageTitle() ) {
		$out->addModules( 'ext.acw.eventlogging' );
	}
}

Lastly, don’t forget to tell MediaWiki wabout your hooks in extension.json:

// BeforePageDisplay hook
"BeforePageDisplay": "ArticleCreationWorkflow\\Hooks::onBeforePageDisplay",

// EventLoggingRegisterSchemas hook
"EventLoggingRegisterSchemas": "ArticleCreationWorkflow\\Hooks::onEventLoggingRegisterSchemas"

Lastly, some actual patches for you to look at and admire: 1, 2, 3


  1. This information brought to you and me by Krinkle. ↩︎