summaryrefslogtreecommitdiff
path: root/www/wiki/extensions/MultimediaViewer/resources/mmv/logging/mmv.logging.Logger.js
blob: 10bad51bc2c44bc9eee2505d78bc46fc3e33d9fa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
/*
 * This file is part of the MediaWiki extension MultimediaViewer.
 *
 * MultimediaViewer is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * MultimediaViewer is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with MultimediaViewer.  If not, see <http://www.gnu.org/licenses/>.
 */

( function ( mw, $ ) {
	var L;

	/**
	 * Abstract class providing common code for EventLogging loggers
	 *
	 * @class mw.mmv.logging.Logger
	 * @abstract
	 */
	function Logger() {
		this.Geo = undefined;
		this.eventLog = undefined;
	}

	L = Logger.prototype;

	/**
	 * Sampling factor key-value map.
	 *
	 * Makes the logger sample log events instead of recording each one if > 0. Disables logging if === 0.
	 * @property {number}
	 */
	L.samplingFactor = 0;

	/**
	 * EventLogging schema
	 * @property {string}
	 */
	L.schema = '';

	/**
	 * Sets the Geo object providing country information about the visitor
	 *
	 * @param {Object} Geo object containing country GeoIP information about the user
	 */
	L.setGeo = function ( Geo ) {
		this.Geo = Geo;
	};

	/**
	 * Sets the eventLog object providing a facility to record events
	 *
	 * @param {mw.eventLog} eventLog EventLogging instance
	 */
	L.setEventLog = function ( eventLog ) {
		this.eventLog = eventLog;
	};

	/**
	 * Loads the dependencies that allow us to log events
	 *
	 * @return {jQuery.Promise}
	 */
	L.loadDependencies = function () {
		var self = this,
			waitForEventLog = $.Deferred();

		// Waits for dom readiness because we don't want to have these dependencies loaded in the head
		$( function () {
			// window.Geo is currently defined in components that are loaded independently, there is no cheap
			// way to load just that information. Either we piggy-back on something that already loaded it
			// or we just don't have it
			if ( window.Geo ) {
				self.setGeo( window.Geo );
			}

			try {
				mw.loader.using( [ 'ext.eventLogging', 'schema.' + self.schema ], function () {
					self.setEventLog( mw.eventLog );
					waitForEventLog.resolve();
				} );
			} catch ( e ) {
				waitForEventLog.reject();
			}
		} );

		return waitForEventLog;
	};

	/**
	 * Returns whether or not we should measure this request
	 *
	 * @return {boolean} True if this request needs to be sampled
	 */
	L.isInSample = function () {
		if ( !$.isNumeric( this.samplingFactor ) || this.samplingFactor < 1 ) {
			return false;
		}

		return Math.floor( Math.random() * this.samplingFactor ) === 0;
	};

	/**
	 * Returns whether logging this event is enabled. This is intended for console logging, which
	 * (in debug mode) should be done even if the request is not being sampled, as long as logging
	 * is enabled for some sample.
	 *
	 * @return {boolean} True if this logging is enabled
	 */
	L.isEnabled = function () {
		return $.isNumeric( this.samplingFactor ) && this.samplingFactor >= 1;
	};

	/**
	 * True if the schema has a country field. Broken out in a separate function so it's easy to mock.
	 *
	 * @return {boolean}
	 */
	L.schemaSupportsCountry = function () {
		return this.eventLog && this.eventLog.schemas && // don't die if eventLog is a mock
			this.schema in this.eventLog.schemas && // don't die if schema is not loaded
			'country' in this.eventLog.schemas[ this.schema ].schema.properties;
	};

	/**
	 * Logs EventLogging data while including Geo data if any
	 *
	 * @param {Object} data
	 * @return {jQuery.Promise}
	 */
	L.log = function ( data ) {
		var self = this;

		if ( self.isInSample() ) {
			return this.loadDependencies().then( function () {
				// Add Geo information if there's any
				if (
					self.Geo && self.Geo.country !== undefined &&
					self.schemaSupportsCountry()
				) {
					data.country = self.Geo.country;
				}

				self.eventLog.logEvent( self.schema, data );
			} );
		} else {
			return $.Deferred().resolve();
		}
	};

	mw.mmv.logging = {};
	mw.mmv.logging.Logger = Logger;
}( mediaWiki, jQuery ) );