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 * Module for sending log entries to the server.
12 /** @suppress {duplicate} */
13 var remoting = remoting || {};
18 remoting.LogToServer = function() {
19 /** @type Array.<string> */
20 this.pendingEntries = [];
21 /** @type {remoting.StatsAccumulator} */
22 this.statsAccumulator = new remoting.StatsAccumulator();
26 this.sessionIdGenerationTime = 0;
28 this.sessionStartTime = 0;
31 // Constants used for generating a session ID.
33 remoting.LogToServer.SESSION_ID_ALPHABET_ =
34 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
36 remoting.LogToServer.SESSION_ID_LEN_ = 20;
38 // The maximum age of a session ID, in milliseconds.
39 remoting.LogToServer.MAX_SESSION_ID_AGE = 24 * 60 * 60 * 1000;
41 // The time over which to accumulate connection statistics before logging them
42 // to the server, in milliseconds.
43 remoting.LogToServer.CONNECTION_STATS_ACCUMULATE_TIME = 60 * 1000;
46 * Logs a client session state change.
48 * @param {remoting.ClientSession.State} state
49 * @param {remoting.Error} connectionError
50 * @param {remoting.ClientSession.Mode} mode
52 remoting.LogToServer.prototype.logClientSessionStateChange =
53 function(state, connectionError, mode) {
54 this.maybeExpireSessionId(mode);
55 // Maybe set the session ID and start time.
56 if (remoting.LogToServer.isStartOfSession(state)) {
57 if (this.sessionId == '') {
60 if (this.sessionStartTime == 0) {
61 this.sessionStartTime = new Date().getTime();
64 // Log the session state change.
65 var entry = remoting.ServerLogEntry.makeClientSessionStateChange(
66 state, connectionError, mode);
67 entry.addHostFields();
68 entry.addChromeVersionField();
69 entry.addWebappVersionField();
70 entry.addSessionIdField(this.sessionId);
71 // Maybe clear the session start time, and log the session duration.
72 if (remoting.LogToServer.shouldAddDuration(state) &&
73 (this.sessionStartTime != 0)) {
74 entry.addSessionDurationField(
75 (new Date().getTime() - this.sessionStartTime) / 1000.0);
76 if (remoting.LogToServer.isEndOfSession(state)) {
77 this.sessionStartTime = 0;
81 // Don't accumulate connection statistics across state changes.
82 this.logAccumulatedStatistics(mode);
83 this.statsAccumulator.empty();
84 // Maybe clear the session ID.
85 if (remoting.LogToServer.isEndOfSession(state)) {
86 this.clearSessionId();
91 * Whether a session state is one of the states that occurs at the start of
95 * @param {remoting.ClientSession.State} state
98 remoting.LogToServer.isStartOfSession = function(state) {
99 return ((state == remoting.ClientSession.State.CONNECTING) ||
100 (state == remoting.ClientSession.State.INITIALIZING) ||
101 (state == remoting.ClientSession.State.CONNECTED));
105 * Whether a session state is one of the states that occurs at the end of
109 * @param {remoting.ClientSession.State} state
112 remoting.LogToServer.isEndOfSession = function(state) {
113 return ((state == remoting.ClientSession.State.CLOSED) ||
114 (state == remoting.ClientSession.State.FAILED) ||
115 (state == remoting.ClientSession.State.CONNECTION_DROPPED) ||
116 (state == remoting.ClientSession.State.CONNECTION_CANCELED));
120 * Whether the duration should be added to the log entry for this state.
123 * @param {remoting.ClientSession.State} state
126 remoting.LogToServer.shouldAddDuration = function(state) {
127 // Duration is added to log entries at the end of the session, as well as at
128 // some intermediate states where it is relevant (e.g. to determine how long
129 // it took for a session to become CONNECTED).
130 return (remoting.LogToServer.isEndOfSession(state) ||
131 (state == remoting.ClientSession.State.CONNECTED));
135 * Logs connection statistics.
136 * @param {Object.<string, number>} stats the connection statistics
137 * @param {remoting.ClientSession.Mode} mode
139 remoting.LogToServer.prototype.logStatistics = function(stats, mode) {
140 this.maybeExpireSessionId(mode);
141 // Store the statistics.
142 this.statsAccumulator.add(stats);
143 // Send statistics to the server if they've been accumulating for at least
145 if (this.statsAccumulator.getTimeSinceFirstValue() >=
146 remoting.LogToServer.CONNECTION_STATS_ACCUMULATE_TIME) {
147 this.logAccumulatedStatistics(mode);
152 * Moves connection statistics from the accumulator to the log server.
154 * If all the statistics are zero, then the accumulator is still emptied,
155 * but the statistics are not sent to the log server.
158 * @param {remoting.ClientSession.Mode} mode
160 remoting.LogToServer.prototype.logAccumulatedStatistics = function(mode) {
161 var entry = remoting.ServerLogEntry.makeStats(this.statsAccumulator, mode);
163 entry.addHostFields();
164 entry.addChromeVersionField();
165 entry.addWebappVersionField();
166 entry.addSessionIdField(this.sessionId);
169 this.statsAccumulator.empty();
173 * Sends a log entry to the server.
176 * @param {remoting.ServerLogEntry} entry
178 remoting.LogToServer.prototype.log = function(entry) {
179 // Send the stanza to the debug log.
180 console.log('Enqueueing log entry:');
182 // Store a stanza for the entry.
183 this.pendingEntries.push(entry.toStanza());
184 // Send all pending entries to the server.
185 console.log('Sending ' + this.pendingEntries.length + ' log ' +
186 ((this.pendingEntries.length == 1) ? 'entry' : 'entries') +
188 var stanza = '<cli:iq to="' +
189 remoting.settings.DIRECTORY_BOT_JID + '" type="set" ' +
190 'xmlns:cli="jabber:client"><gr:log xmlns:gr="google:remoting">';
191 while (this.pendingEntries.length > 0) {
192 stanza += /** @type string */ this.pendingEntries.shift();
194 stanza += '</gr:log></cli:iq>';
195 remoting.wcsSandbox.sendIq(stanza);
199 * Sets the session ID to a random string.
203 remoting.LogToServer.prototype.setSessionId = function() {
204 this.sessionId = remoting.LogToServer.generateSessionId();
205 this.sessionIdGenerationTime = new Date().getTime();
209 * Clears the session ID.
213 remoting.LogToServer.prototype.clearSessionId = function() {
215 this.sessionIdGenerationTime = 0;
219 * Sets a new session ID, if the current session ID has reached its maximum age.
221 * This method also logs the old and new session IDs to the server, in separate
225 * @param {remoting.ClientSession.Mode} mode
227 remoting.LogToServer.prototype.maybeExpireSessionId = function(mode) {
228 if ((this.sessionId != '') &&
229 (new Date().getTime() - this.sessionIdGenerationTime >=
230 remoting.LogToServer.MAX_SESSION_ID_AGE)) {
231 // Log the old session ID.
232 var entry = remoting.ServerLogEntry.makeSessionIdOld(this.sessionId, mode);
234 // Generate a new session ID.
236 // Log the new session ID.
237 entry = remoting.ServerLogEntry.makeSessionIdNew(this.sessionId, mode);
243 * Generates a string that can be used as a session ID.
246 * @return {string} a session ID
248 remoting.LogToServer.generateSessionId = function() {
250 for (var i = 0; i < remoting.LogToServer.SESSION_ID_LEN_; i++) {
252 Math.random() * remoting.LogToServer.SESSION_ID_ALPHABET_.length;
254 remoting.LogToServer.SESSION_ID_ALPHABET_.slice(index, index + 1));
256 return idArray.join('');