feat(RN): enable log collector on mobile

Stores the Logger.LogCollector instance in base/logging state instead of
global APP variable and enables it on mobile.
This commit is contained in:
paweldomas 2018-09-05 15:23:57 -05:00 committed by Saúl Ibarra Corretgé
parent e729f0948c
commit 2305effa5c
7 changed files with 165 additions and 49 deletions

View File

@ -2234,34 +2234,6 @@ export default {
* @returns {void}
*/
_onConferenceJoined() {
if (APP.logCollector) {
// Start the LogCollector's periodic "store logs" task
APP.logCollector.start();
APP.logCollectorStarted = true;
// Make an attempt to flush in case a lot of logs have been
// cached, before the collector was started.
APP.logCollector.flush();
// This event listener will flush the logs, before
// the statistics module (CallStats) is stopped.
//
// NOTE The LogCollector is not stopped, because this event can
// be triggered multiple times during single conference
// (whenever statistics module is stopped). That includes
// the case when Jicofo terminates the single person left in the
// room. It will then restart the media session when someone
// eventually join the room which will start the stats again.
APP.conference.addConferenceListener(
JitsiConferenceEvents.BEFORE_STATISTICS_DISPOSED,
() => {
if (APP.logCollector) {
APP.logCollector.flush();
}
}
);
}
APP.UI.initConference();
APP.keyboardshortcut.init();

View File

@ -1,5 +1,7 @@
/**
* Implements in memory logs storage, used for testing/debugging.
*
* FIXME: move to base/logging
*/
export default class JitsiMeetInMemoryLogStorage {

View File

@ -1,27 +1,45 @@
/* global APP */
import { getCurrentConference } from '../../react/features/base/conference';
/**
* Implements logs storage through the CallStats.
*
* FIXME: move to base/logging
*/
export default class JitsiMeetLogStorage {
/**
* Creates new <tt>JitsiMeetLogStorage</tt>
* Creates new <tt>JitsiMeetLogStorage</tt>.
*
* @param {Function} getState - the Redux store's {@code getState} method.
*/
constructor() {
constructor(getState) {
/**
* Counts each log entry, increases on every batch log entry stored.
* @type {number}
*/
this.counter = 1;
/**
* The Redux store's {@code getState} method.
*
* @type {Function}
*/
this.getState = getState;
}
/**
* The JitsiMeetLogStorage is ready when the CallStats are started and
* before refactoring the code it was after the conference has been joined.
* A conference is considered joined when the 'conference' field is defined
* in the base/conference state.
*
* @return {boolean} <tt>true</tt> when this storage is ready or
* <tt>false</tt> otherwise.
*/
isReady() {
return Boolean(APP.logCollectorStarted && APP.conference);
const { conference } = this.getState()['features/base/conference'];
return Boolean(conference);
}
/**
@ -31,8 +49,9 @@ export default class JitsiMeetLogStorage {
* representing log lines or aggregated lines objects.
*/
storeLogs(logEntries) {
const conference = getCurrentConference(this.getState());
if (!APP.conference.isCallstatsEnabled()) {
if (!conference || !conference.isCallstatsEnabled()) {
// Discard the logs if CallStats is not enabled.
return;
}
@ -58,8 +77,9 @@ export default class JitsiMeetLogStorage {
// on the way that could be uninitialized if the storeLogs
// attempt would be made very early (which is unlikely)
try {
APP.conference._room.sendApplicationLog(logMessage);
conference.sendApplicationLog(logMessage);
} catch (error) {
// FIXME whole objects logged
// NOTE console is intentional here
console.error(
'Failed to store the logs: ', logMessage, error);

View File

@ -1,3 +1,14 @@
/**
* The type of redux action which stores the log collector that will be
* submitting the logs to CallStats.
*
* {
* type: SET_LOG_COLLECTOR,
* logCollector: Logger.LogCollector
* }
*/
export const SET_LOG_COLLECTOR = Symbol('SET_LOG_COLLECTOR');
/**
* The type of redux action which sets the configuration of the feature
* base/logging.

View File

@ -1,6 +1,24 @@
/* @flow */
import { SET_LOGGING_CONFIG } from './actionTypes';
import { SET_LOG_COLLECTOR, SET_LOGGING_CONFIG } from './actionTypes';
/**
* Stores a {@code Logger.LogCollector} instance which will be uploading logs
* to CallStats.
*
* @param {Logger.LogCollector} logCollector - The log collector instance to be
* stored in the Redux state of base/logging feature.
* @returns {{
* type,
* logCollector: Object
* }}
*/
export function setLogCollector(logCollector: ?Object) {
return {
type: SET_LOG_COLLECTOR,
logCollector
};
}
/**
* Sets the configuration of the feature base/logging.

View File

@ -3,7 +3,11 @@
import Logger from 'jitsi-meet-logger';
import { APP_WILL_MOUNT } from '../app';
import JitsiMeetJS, { LIB_WILL_INIT } from '../lib-jitsi-meet';
import { CONFERENCE_JOINED, getCurrentConference } from '../conference';
import JitsiMeetJS, {
LIB_WILL_INIT,
JitsiConferenceEvents
} from '../lib-jitsi-meet';
import { MiddlewareRegistry } from '../redux';
import JitsiMeetInMemoryLogStorage
@ -12,6 +16,7 @@ import JitsiMeetLogStorage from '../../../../modules/util/JitsiMeetLogStorage';
import { isTestModeEnabled } from '../testing';
import { setLogCollector } from './actions';
import { SET_LOGGING_CONFIG } from './actionTypes';
declare var APP: Object;
@ -28,6 +33,9 @@ MiddlewareRegistry.register(store => next => action => {
case APP_WILL_MOUNT:
return _appWillMount(store, next, action);
case CONFERENCE_JOINED:
return _conferenceJoined(store, next, action);
case LIB_WILL_INIT:
return _libWillInit(store, next, action);
@ -66,28 +74,83 @@ function _appWillMount({ getState }, next, action) {
return next(action);
}
/**
* Starts the log collector, after {@link CONFERENCE_JOINED} action is reduced.
*
* @param {Store} store - The Redux store in which the specified {@code action}
* is being dispatched.
* @param {Dispatch} next - The Redux {@code dispatch} function to dispatch the
* specified {@code action} to the specified {@code store}.
* @param {Action} action - The Redux action {@code CONFERENCE_JOINED} which is
* being dispatched in the specified {@code store}.
* @private
* @returns {*}
*/
function _conferenceJoined({ getState }, next, action) {
// Wait until the joined event is processed, so that the JitsiMeetLogStorage
// will be ready.
const result = next(action);
const { conference } = action;
const { logCollector } = getState()['features/base/logging'];
if (logCollector && conference === getCurrentConference(getState())) {
// Start the LogCollector's periodic "store logs" task
logCollector.start();
// Make an attempt to flush in case a lot of logs have been cached,
// before the collector was started.
logCollector.flush();
// This event listener will flush the logs, before the statistics module
// (CallStats) is stopped.
//
// NOTE The LogCollector is not stopped, because this event can be
// triggered multiple times during single conference (whenever
// statistics module is stopped). That includes the case when Jicofo
// terminates a single person conference (one person left in the room
// waiting for someone to join). It will then restart the media session
// when someone eventually joins the room which will start the stats
// again.
conference.on(
JitsiConferenceEvents.BEFORE_STATISTICS_DISPOSED,
() => logCollector.flush()
);
}
return result;
}
/**
* Initializes logging in the app.
*
* @param {Store} store - The Redux store in which context the logging is to be
* initialized.
* @param {Object} loggingConfig - The configuration with which logging is to be
* initialized.
* @param {boolean} isTestingEnabled - Is debug logging enabled.
* @private
* @returns {void}
*/
function _initLogging(loggingConfig, isTestingEnabled) {
function _initLogging({ dispatch, getState }, loggingConfig, isTestingEnabled) {
const { logCollector } = getState()['features/base/logging'];
// Create the LogCollector and register it as the global log transport. It
// is done early to capture as much logs as possible. Captured logs will be
// cached, before the JitsiMeetLogStorage gets ready (statistics module is
// initialized).
if (typeof APP === 'object'
&& !APP.logCollector
&& !loggingConfig.disableLogCollector) {
APP.logCollector = new Logger.LogCollector(new JitsiMeetLogStorage());
Logger.addGlobalTransport(APP.logCollector);
JitsiMeetJS.addGlobalLogTransport(APP.logCollector);
if (!logCollector && !loggingConfig.disableLogCollector) {
const _logCollector
= new Logger.LogCollector(new JitsiMeetLogStorage(getState));
if (isTestingEnabled) {
Logger.addGlobalTransport(_logCollector);
JitsiMeetJS.addGlobalLogTransport(_logCollector);
dispatch(setLogCollector(_logCollector));
// The JitsiMeetInMemoryLogStorage can not be accessed on mobile through
// the 'executeScript' method like it's done in torture tests for WEB.
if (isTestingEnabled && typeof APP === 'object') {
APP.debugLogs = new JitsiMeetInMemoryLogStorage();
const debugLogCollector = new Logger.LogCollector(
APP.debugLogs, { storeInterval: 1000 });
@ -96,6 +159,11 @@ function _initLogging(loggingConfig, isTestingEnabled) {
JitsiMeetJS.addGlobalLogTransport(debugLogCollector);
debugLogCollector.start();
}
} else if (logCollector && loggingConfig.disableLogCollector) {
Logger.removeGlobalTransport(logCollector);
JitsiMeetJS.removeGlobalLogTransport(logCollector);
logCollector.stop();
dispatch(setLogCollector(undefined));
}
}
@ -137,7 +205,7 @@ function _libWillInit({ getState }, next, action) {
* @returns {Object} The new state that is the result of the reduction of the
* specified {@code action}.
*/
function _setLoggingConfig({ getState }, next, action) {
function _setLoggingConfig({ dispatch, getState }, next, action) {
const result = next(action);
const newValue = getState()['features/base/logging'].config;
const isTestingEnabled = isTestModeEnabled(getState());
@ -151,7 +219,10 @@ function _setLoggingConfig({ getState }, next, action) {
_setLogLevels(Logger, newValue);
_setLogLevels(JitsiMeetJS, newValue);
_initLogging(newValue, isTestingEnabled);
_initLogging({
dispatch,
getState
}, newValue, isTestingEnabled);
return result;
}

View File

@ -1,8 +1,8 @@
// @flow
import { equals, ReducerRegistry } from '../redux';
import { equals, ReducerRegistry, set } from '../redux';
import { SET_LOGGING_CONFIG } from './actionTypes';
import { SET_LOG_COLLECTOR, SET_LOGGING_CONFIG } from './actionTypes';
/**
* The default/initial redux state of the feature base/logging.
@ -12,7 +12,12 @@ import { SET_LOGGING_CONFIG } from './actionTypes';
* }}
*/
const DEFAULT_STATE = {
config: require('../../../../logging_config.js')
config: require('../../../../logging_config.js'),
/**
* The log collector.
*/
logCollector: undefined
};
ReducerRegistry.register(
@ -21,6 +26,9 @@ ReducerRegistry.register(
switch (action.type) {
case SET_LOGGING_CONFIG:
return _setLoggingConfig(state, action);
case SET_LOG_COLLECTOR: {
return _setLogCollector(state, action);
}
default:
return state;
@ -54,3 +62,17 @@ function _setLoggingConfig(state, action) {
config
};
}
/**
* Reduces a specific Redux action SET_LOG_COLLECTOR of the feature
* base/logging.
*
* @param {Object} state - The Redux state of the feature base/logging.
* @param {Action} action - The Redux action SET_LOG_COLLECTOR to reduce.
* @private
* @returns {Object} The new state of the feature base/logging after the
* reduction of the specified action.
*/
function _setLogCollector(state, action) {
return set(state, 'logCollector', action.logCollector);
}