1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
7 * A class of server log entries.
12 /** @suppress {duplicate} */
13 var remoting = remoting || {};
19 remoting.ServerLogEntry = function() {
20 /** @type Object.<string, string> */ this.dict = {};
24 remoting.ServerLogEntry.KEY_EVENT_NAME_ = 'event-name';
26 remoting.ServerLogEntry.VALUE_EVENT_NAME_SESSION_STATE_ =
30 remoting.ServerLogEntry.KEY_SESSION_ID_ = 'session-id';
33 remoting.ServerLogEntry.KEY_ROLE_ = 'role';
35 remoting.ServerLogEntry.VALUE_ROLE_CLIENT_ = 'client';
38 remoting.ServerLogEntry.KEY_SESSION_STATE_ = 'session-state';
42 * @param {remoting.ClientSession.State} state
45 remoting.ServerLogEntry.getValueForSessionState = function(state) {
47 case remoting.ClientSession.State.UNKNOWN:
49 case remoting.ClientSession.State.CREATED:
51 case remoting.ClientSession.State.CONNECTING:
53 case remoting.ClientSession.State.INITIALIZING:
54 return 'initializing';
55 case remoting.ClientSession.State.CONNECTED:
57 case remoting.ClientSession.State.CLOSED:
59 case remoting.ClientSession.State.FAILED:
60 return 'connection-failed';
61 case remoting.ClientSession.State.CONNECTION_DROPPED:
62 return 'connection-dropped';
63 case remoting.ClientSession.State.CONNECTION_CANCELED:
64 return 'connection-canceled';
66 return 'undefined-' + state;
71 remoting.ServerLogEntry.KEY_CONNECTION_ERROR_ = 'connection-error';
75 * @param {remoting.Error} connectionError
78 remoting.ServerLogEntry.getValueForError =
79 function(connectionError) {
80 switch(connectionError) {
81 case remoting.Error.NONE:
83 case remoting.Error.INVALID_ACCESS_CODE:
84 return 'invalid-access-code';
85 case remoting.Error.MISSING_PLUGIN:
86 return 'missing_plugin';
87 case remoting.Error.AUTHENTICATION_FAILED:
88 return 'authentication-failed';
89 case remoting.Error.HOST_IS_OFFLINE:
90 return 'host-is-offline';
91 case remoting.Error.INCOMPATIBLE_PROTOCOL:
92 return 'incompatible-protocol';
93 case remoting.Error.BAD_PLUGIN_VERSION:
94 return 'bad-plugin-version';
95 case remoting.Error.NETWORK_FAILURE:
96 return 'network-failure';
97 case remoting.Error.HOST_OVERLOAD:
98 return 'host-overload';
99 case remoting.Error.P2P_FAILURE:
100 return 'p2p-failure';
101 case remoting.Error.UNEXPECTED:
104 return 'unknown-' + connectionError;
109 remoting.ServerLogEntry.KEY_SESSION_DURATION_ = 'session-duration';
112 remoting.ServerLogEntry.VALUE_EVENT_NAME_CONNECTION_STATISTICS_ =
113 "connection-statistics";
115 remoting.ServerLogEntry.KEY_VIDEO_BANDWIDTH_ = "video-bandwidth";
117 remoting.ServerLogEntry.KEY_CAPTURE_LATENCY_ = "capture-latency";
119 remoting.ServerLogEntry.KEY_ENCODE_LATENCY_ = "encode-latency";
121 remoting.ServerLogEntry.KEY_DECODE_LATENCY_ = "decode-latency";
123 remoting.ServerLogEntry.KEY_RENDER_LATENCY_ = "render-latency";
125 remoting.ServerLogEntry.KEY_ROUNDTRIP_LATENCY_ = "roundtrip-latency";
128 remoting.ServerLogEntry.KEY_OS_NAME_ = 'os-name';
130 remoting.ServerLogEntry.VALUE_OS_NAME_WINDOWS_ = 'Windows';
132 remoting.ServerLogEntry.VALUE_OS_NAME_LINUX_ = 'Linux';
134 remoting.ServerLogEntry.VALUE_OS_NAME_MAC_ = 'Mac';
136 remoting.ServerLogEntry.VALUE_OS_NAME_CHROMEOS_ = 'ChromeOS';
139 remoting.ServerLogEntry.KEY_OS_VERSION_ = 'os-version';
142 remoting.ServerLogEntry.KEY_CPU_ = 'cpu';
145 remoting.ServerLogEntry.KEY_BROWSER_VERSION_ = 'browser-version';
148 remoting.ServerLogEntry.KEY_WEBAPP_VERSION_ = 'webapp-version';
151 remoting.ServerLogEntry.VALUE_EVENT_NAME_SESSION_ID_OLD_ = 'session-id-old';
154 remoting.ServerLogEntry.VALUE_EVENT_NAME_SESSION_ID_NEW_ = 'session-id-new';
157 remoting.ServerLogEntry.KEY_MODE_ = 'mode';
159 remoting.ServerLogEntry.VALUE_MODE_IT2ME_ = 'it2me';
161 remoting.ServerLogEntry.VALUE_MODE_ME2ME_ = 'me2me';
163 remoting.ServerLogEntry.VALUE_MODE_UNKNOWN_ = 'unknown';
166 * Sets one field in this log entry.
169 * @param {string} key
170 * @param {string} value
172 remoting.ServerLogEntry.prototype.set = function(key, value) {
173 this.dict[key] = value;
177 * Converts this object into an XML stanza.
181 remoting.ServerLogEntry.prototype.toStanza = function() {
182 var stanza = '<gr:entry ';
183 for (var key in this.dict) {
184 stanza += escape(key) + '="' + escape(this.dict[key]) + '" ';
191 * Prints this object on the debug log.
193 * @param {number} indentLevel the indentation level
195 remoting.ServerLogEntry.prototype.toDebugLog = function(indentLevel) {
196 /** @type Array.<string> */ var fields = [];
197 for (var key in this.dict) {
198 fields.push(key + ': ' + this.dict[key]);
200 console.log(Array(indentLevel+1).join(" ") + fields.join(', '));
204 * Makes a log entry for a change of client session state.
206 * @param {remoting.ClientSession.State} state
207 * @param {remoting.Error} connectionError
208 * @param {remoting.ClientSession.Mode} mode
209 * @return {remoting.ServerLogEntry}
211 remoting.ServerLogEntry.makeClientSessionStateChange = function(state,
212 connectionError, mode) {
213 var entry = new remoting.ServerLogEntry();
214 entry.set(remoting.ServerLogEntry.KEY_ROLE_,
215 remoting.ServerLogEntry.VALUE_ROLE_CLIENT_);
216 entry.set(remoting.ServerLogEntry.KEY_EVENT_NAME_,
217 remoting.ServerLogEntry.VALUE_EVENT_NAME_SESSION_STATE_);
218 entry.set(remoting.ServerLogEntry.KEY_SESSION_STATE_,
219 remoting.ServerLogEntry.getValueForSessionState(state));
220 if (connectionError != remoting.Error.NONE) {
221 entry.set(remoting.ServerLogEntry.KEY_CONNECTION_ERROR_,
222 remoting.ServerLogEntry.getValueForError(connectionError));
224 entry.addModeField(mode);
229 * Adds a session duration to a log entry.
231 * @param {number} sessionDuration
233 remoting.ServerLogEntry.prototype.addSessionDurationField = function(
235 this.set(remoting.ServerLogEntry.KEY_SESSION_DURATION_,
236 sessionDuration.toString());
240 * Makes a log entry for a set of connection statistics.
241 * Returns null if all the statistics were zero.
243 * @param {remoting.StatsAccumulator} statsAccumulator
244 * @param {remoting.ClientSession.Mode} mode
245 * @return {?remoting.ServerLogEntry}
247 remoting.ServerLogEntry.makeStats = function(statsAccumulator, mode) {
248 var entry = new remoting.ServerLogEntry();
249 entry.set(remoting.ServerLogEntry.KEY_ROLE_,
250 remoting.ServerLogEntry.VALUE_ROLE_CLIENT_);
251 entry.set(remoting.ServerLogEntry.KEY_EVENT_NAME_,
252 remoting.ServerLogEntry.VALUE_EVENT_NAME_CONNECTION_STATISTICS_);
253 entry.addModeField(mode);
255 nonZero |= entry.addStatsField(
256 remoting.ServerLogEntry.KEY_VIDEO_BANDWIDTH_,
257 remoting.ClientSession.STATS_KEY_VIDEO_BANDWIDTH, statsAccumulator);
258 nonZero |= entry.addStatsField(
259 remoting.ServerLogEntry.KEY_CAPTURE_LATENCY_,
260 remoting.ClientSession.STATS_KEY_CAPTURE_LATENCY, statsAccumulator);
261 nonZero |= entry.addStatsField(
262 remoting.ServerLogEntry.KEY_ENCODE_LATENCY_,
263 remoting.ClientSession.STATS_KEY_ENCODE_LATENCY, statsAccumulator);
264 nonZero |= entry.addStatsField(
265 remoting.ServerLogEntry.KEY_DECODE_LATENCY_,
266 remoting.ClientSession.STATS_KEY_DECODE_LATENCY, statsAccumulator);
267 nonZero |= entry.addStatsField(
268 remoting.ServerLogEntry.KEY_RENDER_LATENCY_,
269 remoting.ClientSession.STATS_KEY_RENDER_LATENCY, statsAccumulator);
270 nonZero |= entry.addStatsField(
271 remoting.ServerLogEntry.KEY_ROUNDTRIP_LATENCY_,
272 remoting.ClientSession.STATS_KEY_ROUNDTRIP_LATENCY, statsAccumulator);
280 * Adds one connection statistic to a log entry.
283 * @param {string} entryKey
284 * @param {string} statsKey
285 * @param {remoting.StatsAccumulator} statsAccumulator
286 * @return {boolean} whether the statistic is non-zero
288 remoting.ServerLogEntry.prototype.addStatsField = function(
289 entryKey, statsKey, statsAccumulator) {
290 var val = statsAccumulator.calcMean(statsKey);
291 this.set(entryKey, val.toFixed(2));
296 * Makes a log entry for a "this session ID is old" event.
298 * @param {string} sessionId
299 * @param {remoting.ClientSession.Mode} mode
300 * @return {remoting.ServerLogEntry}
302 remoting.ServerLogEntry.makeSessionIdOld = function(sessionId, mode) {
303 var entry = new remoting.ServerLogEntry();
304 entry.set(remoting.ServerLogEntry.KEY_ROLE_,
305 remoting.ServerLogEntry.VALUE_ROLE_CLIENT_);
306 entry.set(remoting.ServerLogEntry.KEY_EVENT_NAME_,
307 remoting.ServerLogEntry.VALUE_EVENT_NAME_SESSION_ID_OLD_);
308 entry.addSessionIdField(sessionId);
309 entry.addModeField(mode);
314 * Makes a log entry for a "this session ID is new" event.
316 * @param {string} sessionId
317 * @param {remoting.ClientSession.Mode} mode
318 * @return {remoting.ServerLogEntry}
320 remoting.ServerLogEntry.makeSessionIdNew = function(sessionId, mode) {
321 var entry = new remoting.ServerLogEntry();
322 entry.set(remoting.ServerLogEntry.KEY_ROLE_,
323 remoting.ServerLogEntry.VALUE_ROLE_CLIENT_);
324 entry.set(remoting.ServerLogEntry.KEY_EVENT_NAME_,
325 remoting.ServerLogEntry.VALUE_EVENT_NAME_SESSION_ID_NEW_);
326 entry.addSessionIdField(sessionId);
327 entry.addModeField(mode);
332 * Adds a session ID field to this log entry.
334 * @param {string} sessionId
336 remoting.ServerLogEntry.prototype.addSessionIdField = function(sessionId) {
337 this.set(remoting.ServerLogEntry.KEY_SESSION_ID_, sessionId);
341 * Adds fields describing the host to this log entry.
343 remoting.ServerLogEntry.prototype.addHostFields = function() {
344 var host = remoting.ServerLogEntry.getHostData();
346 if (host.os_name.length > 0) {
347 this.set(remoting.ServerLogEntry.KEY_OS_NAME_, host.os_name);
349 if (host.os_version.length > 0) {
350 this.set(remoting.ServerLogEntry.KEY_OS_VERSION_, host.os_version);
352 if (host.cpu.length > 0) {
353 this.set(remoting.ServerLogEntry.KEY_CPU_, host.cpu);
359 * Extracts host data from the userAgent string.
362 * @return {{os_name:string, os_version:string, cpu:string} | null}
364 remoting.ServerLogEntry.getHostData = function() {
365 return remoting.ServerLogEntry.extractHostDataFrom(navigator.userAgent);
369 * Extracts host data from the given userAgent string.
373 * @return {{os_name:string, os_version:string, cpu:string} | null}
375 remoting.ServerLogEntry.extractHostDataFrom = function(s) {
376 // Sample userAgent strings:
377 // 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.2 ' +
378 // '(KHTML, like Gecko) Chrome/15.0.874.106 Safari/535.2'
379 // 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.8 ' +
380 // '(KHTML, like Gecko) Chrome/17.0.933.0 Safari/535.8'
381 // 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/535.1 ' +
382 // '(KHTML, like Gecko) Chrome/14.0.835.202 Safari/535.1'
383 // 'Mozilla/5.0 (X11; CrOS i686 14.811.154) AppleWebKit/535.1 ' +
384 // '(KHTML, like Gecko) Chrome/14.0.835.204 Safari/535.1'
385 var match = new RegExp('Windows NT ([0-9\\.]*)').exec(s);
386 if (match && (match.length >= 2)) {
388 'os_name': remoting.ServerLogEntry.VALUE_OS_NAME_WINDOWS_,
389 'os_version': match[1],
393 match = new RegExp('Linux ([a-zA-Z0-9_]*)').exec(s);
394 if (match && (match.length >= 2)) {
396 'os_name': remoting.ServerLogEntry.VALUE_OS_NAME_LINUX_,
401 match = new RegExp('([a-zA-Z]*) Mac OS X ([0-9_]*)').exec(s);
402 if (match && (match.length >= 3)) {
404 'os_name': remoting.ServerLogEntry.VALUE_OS_NAME_MAC_,
405 'os_version': match[2].replace(/_/g, '.'),
409 match = new RegExp('CrOS ([a-zA-Z0-9]*) ([0-9.]*)').exec(s);
410 if (match && (match.length >= 3)) {
412 'os_name': remoting.ServerLogEntry.VALUE_OS_NAME_CHROMEOS_,
413 'os_version': match[2],
421 * Adds a field specifying the browser version to this log entry.
423 remoting.ServerLogEntry.prototype.addChromeVersionField = function() {
424 var version = remoting.ServerLogEntry.getChromeVersion();
425 if (version != null) {
426 this.set(remoting.ServerLogEntry.KEY_BROWSER_VERSION_, version);
431 * Extracts the Chrome version from the userAgent string.
434 * @return {string | null}
436 remoting.ServerLogEntry.getChromeVersion = function() {
437 return remoting.ServerLogEntry.extractChromeVersionFrom(navigator.userAgent);
441 * Extracts the Chrome version from the given userAgent string.
445 * @return {string | null}
447 remoting.ServerLogEntry.extractChromeVersionFrom = function(s) {
448 var match = new RegExp('Chrome/([0-9.]*)').exec(s);
449 if (match && (match.length >= 2)) {
456 * Adds a field specifying the webapp version to this log entry.
458 remoting.ServerLogEntry.prototype.addWebappVersionField = function() {
459 var manifest = chrome.runtime.getManifest();
460 if (manifest && manifest.version) {
461 this.set(remoting.ServerLogEntry.KEY_WEBAPP_VERSION_, manifest.version);
466 * Adds a field specifying the mode to this log entry.
468 * @param {remoting.ClientSession.Mode} mode
470 remoting.ServerLogEntry.prototype.addModeField = function(mode) {
471 this.set(remoting.ServerLogEntry.KEY_MODE_,
472 remoting.ServerLogEntry.getModeField(mode));
476 * Gets the value of the mode field to be put in a log entry.
479 * @param {remoting.ClientSession.Mode} mode
482 remoting.ServerLogEntry.getModeField = function(mode) {
484 case remoting.ClientSession.Mode.IT2ME:
485 return remoting.ServerLogEntry.VALUE_MODE_IT2ME_;
486 case remoting.ClientSession.Mode.ME2ME:
487 return remoting.ServerLogEntry.VALUE_MODE_ME2ME_;
489 return remoting.ServerLogEntry.VALUE_MODE_UNKNOWN_;