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.
9 * Any changes to the values here need to be coordinated with the host and
10 * server/log proto code.
11 * See remoting/signaling/server_log_entry.{cc|h}
16 /** @suppress {duplicate} */
17 var remoting = remoting || {};
23 remoting.ServerLogEntry = function() {
24 /** @type Object.<string, string> */ this.dict = {};
28 remoting.ServerLogEntry.KEY_EVENT_NAME_ = 'event-name';
30 remoting.ServerLogEntry.VALUE_EVENT_NAME_SESSION_STATE_ = 'session-state';
32 remoting.ServerLogEntry.VALUE_EVENT_NAME_SIGNAL_STRATEGY_PROGRESS_ =
33 'signal-strategy-progress';
35 remoting.ServerLogEntry.KEY_SESSION_ID_ = 'session-id';
37 remoting.ServerLogEntry.KEY_ROLE_ = 'role';
39 remoting.ServerLogEntry.VALUE_ROLE_CLIENT_ = 'client';
41 remoting.ServerLogEntry.KEY_SESSION_STATE_ = 'session-state';
43 remoting.ServerLogEntry.KEY_CONNECTION_TYPE_ = 'connection-type';
45 remoting.ServerLogEntry.KEY_SIGNAL_STRATEGY_TYPE_ = 'signal-strategy-type';
47 remoting.ServerLogEntry.KEY_SIGNAL_STRATEGY_PROGRESS_ =
48 'signal-strategy-progress';
50 remoting.ServerLogEntry.KEY_SIGNAL_STRATEGY_ELAPSED_TIME_ =
51 'signal-strategy-elapsed-time';
55 * @param {remoting.ClientSession.State} state
58 remoting.ServerLogEntry.getValueForSessionState_ = function(state) {
60 case remoting.ClientSession.State.UNKNOWN:
62 case remoting.ClientSession.State.CREATED:
64 case remoting.ClientSession.State.CONNECTING:
66 case remoting.ClientSession.State.INITIALIZING:
67 return 'initializing';
68 case remoting.ClientSession.State.CONNECTED:
70 case remoting.ClientSession.State.CLOSED:
72 case remoting.ClientSession.State.FAILED:
73 return 'connection-failed';
74 case remoting.ClientSession.State.CONNECTION_DROPPED:
75 return 'connection-dropped';
76 case remoting.ClientSession.State.CONNECTION_CANCELED:
77 return 'connection-canceled';
79 return 'undefined-' + state;
84 remoting.ServerLogEntry.KEY_CONNECTION_ERROR_ = 'connection-error';
88 * @param {remoting.Error} connectionError
91 remoting.ServerLogEntry.getValueForError_ = function(connectionError) {
92 // Directory service should be updated if a new string is added here as
93 // otherwise the error code will be ignored (i.e. recorded as 0 instead).
94 switch(connectionError) {
95 case remoting.Error.NONE:
97 case remoting.Error.INVALID_ACCESS_CODE:
98 return 'invalid-access-code';
99 case remoting.Error.MISSING_PLUGIN:
100 return 'missing_plugin';
101 case remoting.Error.AUTHENTICATION_FAILED:
102 return 'authentication-failed';
103 case remoting.Error.HOST_IS_OFFLINE:
104 return 'host-is-offline';
105 case remoting.Error.INCOMPATIBLE_PROTOCOL:
106 return 'incompatible-protocol';
107 case remoting.Error.BAD_PLUGIN_VERSION:
108 return 'bad-plugin-version';
109 case remoting.Error.NETWORK_FAILURE:
110 return 'network-failure';
111 case remoting.Error.HOST_OVERLOAD:
112 return 'host-overload';
113 case remoting.Error.P2P_FAILURE:
114 return 'p2p-failure';
115 case remoting.Error.UNEXPECTED:
118 return 'unknown-' + connectionError;
123 remoting.ServerLogEntry.KEY_SESSION_DURATION_ = 'session-duration';
126 remoting.ServerLogEntry.VALUE_EVENT_NAME_CONNECTION_STATISTICS_ =
127 "connection-statistics";
129 remoting.ServerLogEntry.KEY_VIDEO_BANDWIDTH_ = "video-bandwidth";
131 remoting.ServerLogEntry.KEY_CAPTURE_LATENCY_ = "capture-latency";
133 remoting.ServerLogEntry.KEY_ENCODE_LATENCY_ = "encode-latency";
135 remoting.ServerLogEntry.KEY_DECODE_LATENCY_ = "decode-latency";
137 remoting.ServerLogEntry.KEY_RENDER_LATENCY_ = "render-latency";
139 remoting.ServerLogEntry.KEY_ROUNDTRIP_LATENCY_ = "roundtrip-latency";
142 remoting.ServerLogEntry.KEY_OS_NAME_ = 'os-name';
144 remoting.ServerLogEntry.VALUE_OS_NAME_WINDOWS_ = 'Windows';
146 remoting.ServerLogEntry.VALUE_OS_NAME_LINUX_ = 'Linux';
148 remoting.ServerLogEntry.VALUE_OS_NAME_MAC_ = 'Mac';
150 remoting.ServerLogEntry.VALUE_OS_NAME_CHROMEOS_ = 'ChromeOS';
153 remoting.ServerLogEntry.KEY_OS_VERSION_ = 'os-version';
156 remoting.ServerLogEntry.KEY_CPU_ = 'cpu';
159 remoting.ServerLogEntry.KEY_BROWSER_VERSION_ = 'browser-version';
162 remoting.ServerLogEntry.KEY_WEBAPP_VERSION_ = 'webapp-version';
165 remoting.ServerLogEntry.VALUE_EVENT_NAME_SESSION_ID_OLD_ = 'session-id-old';
168 remoting.ServerLogEntry.VALUE_EVENT_NAME_SESSION_ID_NEW_ = 'session-id-new';
171 remoting.ServerLogEntry.KEY_MODE_ = 'mode';
173 remoting.ServerLogEntry.VALUE_MODE_IT2ME_ = 'it2me';
175 remoting.ServerLogEntry.VALUE_MODE_ME2ME_ = 'me2me';
177 remoting.ServerLogEntry.VALUE_MODE_APP_REMOTING_ = 'lgapp';
179 remoting.ServerLogEntry.VALUE_MODE_UNKNOWN_ = 'unknown';
182 * Sets one field in this log entry.
185 * @param {string} key
186 * @param {string} value
188 remoting.ServerLogEntry.prototype.set_ = function(key, value) {
189 this.dict[key] = value;
193 * Converts this object into an XML stanza.
197 remoting.ServerLogEntry.prototype.toStanza = function() {
198 var stanza = '<gr:entry ';
199 for (var key in this.dict) {
200 stanza += escape(key) + '="' + escape(this.dict[key]) + '" ';
207 * Prints this object on the debug log.
209 * @param {number} indentLevel the indentation level
211 remoting.ServerLogEntry.prototype.toDebugLog = function(indentLevel) {
212 /** @type Array.<string> */ var fields = [];
213 for (var key in this.dict) {
214 fields.push(key + ': ' + this.dict[key]);
216 console.log(Array(indentLevel+1).join(" ") + fields.join(', '));
220 * Makes a log entry for a change of client session state.
222 * @param {remoting.ClientSession.State} state
223 * @param {remoting.Error} connectionError
224 * @param {remoting.ClientSession.Mode} mode
225 * @return {remoting.ServerLogEntry}
227 remoting.ServerLogEntry.makeClientSessionStateChange = function(state,
228 connectionError, mode) {
229 var entry = new remoting.ServerLogEntry();
230 entry.set_(remoting.ServerLogEntry.KEY_ROLE_,
231 remoting.ServerLogEntry.VALUE_ROLE_CLIENT_);
232 entry.set_(remoting.ServerLogEntry.KEY_EVENT_NAME_,
233 remoting.ServerLogEntry.VALUE_EVENT_NAME_SESSION_STATE_);
234 entry.set_(remoting.ServerLogEntry.KEY_SESSION_STATE_,
235 remoting.ServerLogEntry.getValueForSessionState_(state));
236 if (connectionError != remoting.Error.NONE) {
237 entry.set_(remoting.ServerLogEntry.KEY_CONNECTION_ERROR_,
238 remoting.ServerLogEntry.getValueForError_(connectionError));
240 entry.addModeField(mode);
245 * Adds a session duration to a log entry.
247 * @param {number} sessionDuration
249 remoting.ServerLogEntry.prototype.addSessionDurationField = function(
251 this.set_(remoting.ServerLogEntry.KEY_SESSION_DURATION_,
252 sessionDuration.toString());
256 * Makes a log entry for a set of connection statistics.
257 * Returns null if all the statistics were zero.
259 * @param {remoting.StatsAccumulator} statsAccumulator
260 * @param {string} connectionType
261 * @param {remoting.ClientSession.Mode} mode
262 * @return {?remoting.ServerLogEntry}
264 remoting.ServerLogEntry.makeStats = function(statsAccumulator,
267 var entry = new remoting.ServerLogEntry();
268 entry.set_(remoting.ServerLogEntry.KEY_ROLE_,
269 remoting.ServerLogEntry.VALUE_ROLE_CLIENT_);
270 entry.set_(remoting.ServerLogEntry.KEY_EVENT_NAME_,
271 remoting.ServerLogEntry.VALUE_EVENT_NAME_CONNECTION_STATISTICS_);
272 if (connectionType) {
273 entry.set_(remoting.ServerLogEntry.KEY_CONNECTION_TYPE_,
276 entry.addModeField(mode);
278 nonZero |= entry.addStatsField_(
279 remoting.ServerLogEntry.KEY_VIDEO_BANDWIDTH_,
280 remoting.ClientSession.STATS_KEY_VIDEO_BANDWIDTH, statsAccumulator);
281 nonZero |= entry.addStatsField_(
282 remoting.ServerLogEntry.KEY_CAPTURE_LATENCY_,
283 remoting.ClientSession.STATS_KEY_CAPTURE_LATENCY, statsAccumulator);
284 nonZero |= entry.addStatsField_(
285 remoting.ServerLogEntry.KEY_ENCODE_LATENCY_,
286 remoting.ClientSession.STATS_KEY_ENCODE_LATENCY, statsAccumulator);
287 nonZero |= entry.addStatsField_(
288 remoting.ServerLogEntry.KEY_DECODE_LATENCY_,
289 remoting.ClientSession.STATS_KEY_DECODE_LATENCY, statsAccumulator);
290 nonZero |= entry.addStatsField_(
291 remoting.ServerLogEntry.KEY_RENDER_LATENCY_,
292 remoting.ClientSession.STATS_KEY_RENDER_LATENCY, statsAccumulator);
293 nonZero |= entry.addStatsField_(
294 remoting.ServerLogEntry.KEY_ROUNDTRIP_LATENCY_,
295 remoting.ClientSession.STATS_KEY_ROUNDTRIP_LATENCY, statsAccumulator);
303 * Adds one connection statistic to a log entry.
306 * @param {string} entryKey
307 * @param {string} statsKey
308 * @param {remoting.StatsAccumulator} statsAccumulator
309 * @return {boolean} whether the statistic is non-zero
311 remoting.ServerLogEntry.prototype.addStatsField_ = function(
312 entryKey, statsKey, statsAccumulator) {
313 var val = statsAccumulator.calcMean(statsKey);
314 this.set_(entryKey, val.toFixed(2));
319 * Makes a log entry for a "this session ID is old" event.
321 * @param {string} sessionId
322 * @param {remoting.ClientSession.Mode} mode
323 * @return {remoting.ServerLogEntry}
325 remoting.ServerLogEntry.makeSessionIdOld = function(sessionId, mode) {
326 var entry = new remoting.ServerLogEntry();
327 entry.set_(remoting.ServerLogEntry.KEY_ROLE_,
328 remoting.ServerLogEntry.VALUE_ROLE_CLIENT_);
329 entry.set_(remoting.ServerLogEntry.KEY_EVENT_NAME_,
330 remoting.ServerLogEntry.VALUE_EVENT_NAME_SESSION_ID_OLD_);
331 entry.addSessionIdField(sessionId);
332 entry.addModeField(mode);
337 * Makes a log entry for a "this session ID is new" event.
339 * @param {string} sessionId
340 * @param {remoting.ClientSession.Mode} mode
341 * @return {remoting.ServerLogEntry}
343 remoting.ServerLogEntry.makeSessionIdNew = function(sessionId, mode) {
344 var entry = new remoting.ServerLogEntry();
345 entry.set_(remoting.ServerLogEntry.KEY_ROLE_,
346 remoting.ServerLogEntry.VALUE_ROLE_CLIENT_);
347 entry.set_(remoting.ServerLogEntry.KEY_EVENT_NAME_,
348 remoting.ServerLogEntry.VALUE_EVENT_NAME_SESSION_ID_NEW_);
349 entry.addSessionIdField(sessionId);
350 entry.addModeField(mode);
355 * Makes a log entry for a "signal strategy fallback" event.
357 * @param {string} sessionId
358 * @param {remoting.SignalStrategy.Type} strategyType
359 * @param {remoting.FallbackSignalStrategy.Progress} progress
360 * @param {number} elapsedTimeInMs
361 * @return {remoting.ServerLogEntry}
363 remoting.ServerLogEntry.makeSignalStrategyProgress =
364 function(sessionId, strategyType, progress, elapsedTimeInMs) {
365 var entry = new remoting.ServerLogEntry();
366 entry.set_(remoting.ServerLogEntry.KEY_ROLE_,
367 remoting.ServerLogEntry.VALUE_ROLE_CLIENT_);
369 remoting.ServerLogEntry.KEY_EVENT_NAME_,
370 remoting.ServerLogEntry.VALUE_EVENT_NAME_SIGNAL_STRATEGY_PROGRESS_);
371 entry.addSessionIdField(sessionId);
372 entry.set_(remoting.ServerLogEntry.KEY_SIGNAL_STRATEGY_TYPE_, strategyType);
373 entry.set_(remoting.ServerLogEntry.KEY_SIGNAL_STRATEGY_PROGRESS_, progress);
374 entry.set_(remoting.ServerLogEntry.KEY_SIGNAL_STRATEGY_ELAPSED_TIME_,
375 String(elapsedTimeInMs));
381 * Adds a session ID field to this log entry.
383 * @param {string} sessionId
385 remoting.ServerLogEntry.prototype.addSessionIdField = function(sessionId) {
386 this.set_(remoting.ServerLogEntry.KEY_SESSION_ID_, sessionId);
390 * Adds fields describing the host to this log entry.
392 remoting.ServerLogEntry.prototype.addHostFields = function() {
393 var host = remoting.ServerLogEntry.getHostData_();
395 if (host.os_name.length > 0) {
396 this.set_(remoting.ServerLogEntry.KEY_OS_NAME_, host.os_name);
398 if (host.os_version.length > 0) {
399 this.set_(remoting.ServerLogEntry.KEY_OS_VERSION_, host.os_version);
401 if (host.cpu.length > 0) {
402 this.set_(remoting.ServerLogEntry.KEY_CPU_, host.cpu);
408 * Extracts host data from the userAgent string.
411 * @return {{os_name:string, os_version:string, cpu:string} | null}
413 remoting.ServerLogEntry.getHostData_ = function() {
414 return remoting.ServerLogEntry.extractHostDataFrom_(navigator.userAgent);
418 * Extracts host data from the given userAgent string.
422 * @return {{os_name:string, os_version:string, cpu:string} | null}
424 remoting.ServerLogEntry.extractHostDataFrom_ = function(s) {
425 // Sample userAgent strings:
426 // 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.2 ' +
427 // '(KHTML, like Gecko) Chrome/15.0.874.106 Safari/535.2'
428 // 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.8 ' +
429 // '(KHTML, like Gecko) Chrome/17.0.933.0 Safari/535.8'
430 // 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/535.1 ' +
431 // '(KHTML, like Gecko) Chrome/14.0.835.202 Safari/535.1'
432 // 'Mozilla/5.0 (X11; CrOS i686 14.811.154) AppleWebKit/535.1 ' +
433 // '(KHTML, like Gecko) Chrome/14.0.835.204 Safari/535.1'
434 var match = new RegExp('Windows NT ([0-9\\.]*)').exec(s);
435 if (match && (match.length >= 2)) {
437 'os_name': remoting.ServerLogEntry.VALUE_OS_NAME_WINDOWS_,
438 'os_version': match[1],
442 match = new RegExp('Linux ([a-zA-Z0-9_]*)').exec(s);
443 if (match && (match.length >= 2)) {
445 'os_name': remoting.ServerLogEntry.VALUE_OS_NAME_LINUX_,
450 match = new RegExp('([a-zA-Z]*) Mac OS X ([0-9_]*)').exec(s);
451 if (match && (match.length >= 3)) {
453 'os_name': remoting.ServerLogEntry.VALUE_OS_NAME_MAC_,
454 'os_version': match[2].replace(/_/g, '.'),
458 match = new RegExp('CrOS ([a-zA-Z0-9]*) ([0-9.]*)').exec(s);
459 if (match && (match.length >= 3)) {
461 'os_name': remoting.ServerLogEntry.VALUE_OS_NAME_CHROMEOS_,
462 'os_version': match[2],
470 * Adds a field specifying the browser version to this log entry.
472 remoting.ServerLogEntry.prototype.addChromeVersionField = function() {
473 var version = remoting.getChromeVersion();
474 if (version != null) {
475 this.set_(remoting.ServerLogEntry.KEY_BROWSER_VERSION_, version);
480 * Adds a field specifying the webapp version to this log entry.
482 remoting.ServerLogEntry.prototype.addWebappVersionField = function() {
483 var manifest = chrome.runtime.getManifest();
484 if (manifest && manifest.version) {
485 this.set_(remoting.ServerLogEntry.KEY_WEBAPP_VERSION_, manifest.version);
490 * Adds a field specifying the mode to this log entry.
492 * @param {remoting.ClientSession.Mode} mode
494 remoting.ServerLogEntry.prototype.addModeField = function(mode) {
495 this.set_(remoting.ServerLogEntry.KEY_MODE_,
496 remoting.ServerLogEntry.getModeField_(mode));
500 * Gets the value of the mode field to be put in a log entry.
503 * @param {remoting.ClientSession.Mode} mode
506 remoting.ServerLogEntry.getModeField_ = function(mode) {
508 case remoting.ClientSession.Mode.IT2ME:
509 return remoting.ServerLogEntry.VALUE_MODE_IT2ME_;
510 case remoting.ClientSession.Mode.ME2ME:
511 return remoting.ServerLogEntry.VALUE_MODE_ME2ME_;
512 case remoting.ClientSession.Mode.APP_REMOTING:
513 return remoting.ServerLogEntry.VALUE_MODE_APP_REMOTING_;
515 return remoting.ServerLogEntry.VALUE_MODE_UNKNOWN_;