Extension:EventLogging/Programming


 * ''See ../Data model (singular) for notes in storage in Redis

How it works
When code logs an event, it must reference a schema. Here's some actual working JavaScript: In this case the schema is "OpenTask". This should exactly match a Schema: page on Meta, and the name should use InitialCaps.


 * 1) The schema is a JSON structure that specifies the fields in the event &mdash; their names, their types (integer, string, boolean, etc.), whether required or not, allowed values, ... The technical term for this is "schema".
 * 2) PHP code in core or an extension explicitly depends on a particular data model.
 * 3) the MediaWiki ResourceLoader gets the data model from its page in meta-wiki's Schema: namespace (e.g. http://meta.wikimedia.org/wiki/Schema:OpenTask) caches it, and makes it available to client JavaScript such as the call to   above.

How to make a data model
Then:
 * Meet a researcher and determine what you're going to log, name the fields to log, reusing well-known field names.
 * Create a JSON structure representing this data model in the Schema: namespace on meta.
 * Sample: m:Schema:OpenTask
 * Tip: http://jsonlint.com/ will check and reformat your JSON.
 * Use the schema's talk page (sample) to link to experiments using this, discuss details, etc.
 * Always document what code in what circumstances logs the event
 * Developers write code to log events that match the data model.
 * The data model tells analysts what information is in the logs.

Versioning
If code tries to log an event that doesn't match the data model that EventLogging retrieved, EventLogging will log the event anyway but flag it as invalid. EventLogging always logs the revision of the schema page it used. Thus there are several ways to handle versioning. When you change the meaning or format of a field or add new fields, you could: You can note changes in the experimental conditions that don't affect the data model ("we replaced Benefits with a picture of Jimmy Wales") in your data model's own version field.
 * Update the existing data model's page
 * if the change is forward-compatible production code and code in development should work
 * if it isn't there will be some churn until the data model and code are back in sync
 * Create a new data model ("OpenTask2") and have new code refer to the new name.
 * Before going into production have code refer to a particular revision of the model's page, e.g. ([| Schema:OpenTask rev=4701932]).

It's OK to have different kinds of events (often called actions) sharing one data model, simply make the fields applicable to one event optional. That way all the events go into one table and it's easier to query and do multi-dimensional analysis.

Built-in data fields
The client-side mw.eventLog.logEvent function always logs some fields of its own in addition to the object you pass to it:
 * _db
 * string, the wiki database ("enwiki", etc.)


 * _id
 * string, the data model of the event (in this example, "OpenTask")


 * _rv
 * integer, the revision ID of the schema article provided to client-side code


 * _ok
 * boolean, false if the event failed to validate against its data model

Additions coming soon:
 * _token
 * string, random anonymous token per user (more precisely, per browser)

The server-side logging that handles the event stream also logs other fields, such as: palladium.eqiad.wmnet 327042 2012-12-11T20:53:20 208.80.154.133 (log server?, ??, server timestamp in UTC, IP?)

A schema should describe a server-side event or a client-side event, but not both at the same time, since server-side events and client-side events are annotated with a different set of metadata.

Standard data fields
Future Maybe these should be consistently generated by the event logging code, and have an underscore prefix, so clients could just say "please log,  , and  ".


 * anon
 * boolean; true if user has not logged-in (opposite of "authenticated"). In JavaScript, call mw.user.isAnon


 * article
 * string; the title of the page the user is editing. In JavaScript, request the config value wgTitle.
 * note this doesn't work for Special pages and other namespaces.

If user has logged in (anon is false), then we often log:
 * editCount
 * integer how many edits a logged-in user has made. In JavaScript, request the config value wgEditCount.


 * userId
 * integer the user ID of a logged in user. Privacy note: information about the activities of logged-in users is already available in Special:RecentChanges, Special:UserContributions, etc.

Common data fields
There are no standard values for these, but different data models use the same field name for their own values.


 * action
 * string; identifying different actions the data model logs, such as 'impression', 'click', 'submit', 'accept' (a task), 'create'


 * bucket
 * enum strings; this records which alternative is presented to a user. For example, Account Creation User Experience randomly shows users either 'control_3' (original form) or 'acux_3' (fancy validating form).


 * campaign
 * string; value of incoming query parameter identifying the source of an action. For example the Article Feedback Tool's "create an account" call to action links to the account creation with  in the query string.


 * error
 * ??, optional; records if the user experienced an error attempting an action (filling in a form, saving an edit, etc.) and what it was.


 * token
 * a unique random persistent token per browser, stored in the (badly misnamed) mediaWiki.user.id cookie. In JavaScript, calling mw.user.id will generate this. Note: this will probably become a built-in data field named _token
 * Perhaps use an additional session token when logging data in a single browser session


 * version
 * integer; a number representing changes to the conditions (not the data model), e.g. bump it when deploying code that presents a different experience.

Available data models
Also see m:Category:Data models. Not all of these have been converted to Schema: pages on meta,


 * openTask
 * in m:Schema:openTask


 * AccountCreation
 * in m:Schema:AccountCreation, includes client-side assign/impression/submit events and a server-side account_create event, both logged by Extension:E3Experiments. Current ACUX experiment still uses ClickTracking for client-side events, alas.


 * edit
 * server-side event logged by EventLogging itself whenever a user creates or edits an article (on PageContentSaveComplete hook), with fields:
 * articleId, api (boolean), title, namespace, created (boolean), summary, timestamp, minor (boolean), loggedIn, userId, editCount, registered (integer timestamp)


 * mobile
 * see Event_logging/Mobile


 * onboarding
 * may reuse openTask

JSON schema validation
Each data model JSON file on meta-wiki is a JSON schema. This is an evolving standard to specify the format of JSON structures, in our case the logged event.
 * the JSON schema draft].
 * As of December 2012 EventLogging only validates that the schemas on meta are valid JSON.
 * When code attempts to log an event, EventLogging only pays attention to a subset of JSON schema features; as of November 2012 this includes:
 * type: boolean, integer, number, string, timestamp
 * required: true/false
 * enum values

Error handling
If code attempts to log with an invalid format, EventLogging detects it's invalid and flags it, but logs it anyway.

Programming
Tips Debugging
 * The E3Experiments extension has working PHP setup code to declare and require the "openTasks" data model resource in, and sample JavaScript calls to eventLogging in.
 * your data model resource should depends on ext.eventLogging
 * require your data model wherever you need to log events
 * See for API documentation.
 * In JavaScript code, use mw.eventLog.setDefaults to set common values for fields to log that don't change, such as version, the user's name, etc.
 * Client-side event logging works by requesting a beacon image event.gif with the log info in its query string. To see the log events you can
 * watch for this request in your browser's network console,
 * look for it in your web server's access logs,
 * or run the toy web server scripts/DevServer.php in the EventLogging extension which pretty-prints the query string
 * In your browser's JavaScript console, enter mw.eventLog.dataModels to see if requiring a data model worked.