Introduce features/base/logging

The functionality around logging including logging_config.js i.e.
loggingConfig and the other classes and/or functions that initialize
loggers for Jits Meet truly deserves a feature of its own. Start getting
in that direction on both Web and mobile by introducing
features/base/logging and bringing loggingConfig to mobile.
This commit is contained in:
Lyubo Marinov 2017-04-23 15:17:31 -05:00
parent 92e765ea21
commit 7836fd1990
12 changed files with 269 additions and 43 deletions

View File

@ -1,10 +1,13 @@
/* global config, interfaceConfig, loggingConfig, getConfigParamsFromUrl */ /* global config, getConfigParamsFromUrl, interfaceConfig, loggingConfig */
const logger = require("jitsi-meet-logger").getLogger(__filename); const logger = require("jitsi-meet-logger").getLogger(__filename);
var configUtils = require('./Util'); var configUtils = require('./Util');
var params = {}; var params = {};
if (typeof getConfigParamsFromUrl === 'function') {
params = getConfigParamsFromUrl(); params = getConfigParamsFromUrl();
}
var URLProcessor = { var URLProcessor = {
setConfigParametersFromUrl: function () { setConfigParametersFromUrl: function () {

View File

@ -41,6 +41,7 @@
"jssha": "1.5.0", "jssha": "1.5.0",
"jws": "3.1.4", "jws": "3.1.4",
"lib-jitsi-meet": "jitsi/lib-jitsi-meet", "lib-jitsi-meet": "jitsi/lib-jitsi-meet",
"lodash": "4.17.4",
"postis": "2.2.0", "postis": "2.2.0",
"react": "15.4.2", "react": "15.4.2",
"react-dom": "15.4.2", "react-dom": "15.4.2",

View File

@ -14,7 +14,6 @@ import {
} from '../unsupported-browser'; } from '../unsupported-browser';
import { WelcomePage } from '../welcome'; import { WelcomePage } from '../welcome';
import URLProcessor from '../../../modules/config/URLProcessor';
import KeyboardShortcut import KeyboardShortcut
from '../../../modules/keyboardshortcut/keyboardshortcut'; from '../../../modules/keyboardshortcut/keyboardshortcut';
import getTokenData from '../../../modules/tokendata/TokenData'; import getTokenData from '../../../modules/tokendata/TokenData';
@ -115,7 +114,6 @@ export function _getRouteToRender(stateOrGetState: Object | Function) {
* @returns {void} * @returns {void}
*/ */
export function init() { export function init() {
URLProcessor.setConfigParametersFromUrl();
_initLogging(); _initLogging();
APP.keyboardshortcut = KeyboardShortcut; APP.keyboardshortcut = KeyboardShortcut;
@ -129,40 +127,6 @@ export function init() {
APP.translation.init(); APP.translation.init();
} }
/**
* Adjusts the logging levels.
*
* @private
* @returns {void}
*/
function _configureLoggingLevels() {
// NOTE The library Logger is separated from the app loggers, so the levels
// have to be set in two places
// Set default logging level
const defaultLogLevel
= loggingConfig.defaultLogLevel || JitsiMeetJS.logLevels.TRACE;
Logger.setLogLevel(defaultLogLevel);
JitsiMeetJS.setLogLevel(defaultLogLevel);
// NOTE console was used on purpose here to go around the logging and always
// print the default logging level to the console
console.info(`Default logging level set to: ${defaultLogLevel}`);
// Set log level for each logger
if (loggingConfig) {
Object.keys(loggingConfig).forEach(loggerName => {
if (loggerName !== 'defaultLogLevel') {
const level = loggingConfig[loggerName];
Logger.setLogLevelById(level, loggerName);
JitsiMeetJS.setLogLevelById(level, loggerName);
}
});
}
}
/** /**
* Initializes logging in the app. * Initializes logging in the app.
* *
@ -170,9 +134,6 @@ function _configureLoggingLevels() {
* @returns {void} * @returns {void}
*/ */
function _initLogging() { function _initLogging() {
// Adjust logging level
_configureLoggingLevels();
// Create the LogCollector and register it as the global log transport. It // 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 // is done early to capture as much logs as possible. Captured logs will be
// cached, before the JitsiMeetLogStorage gets ready (statistics module is // cached, before the JitsiMeetLogStorage gets ready (statistics module is

View File

@ -47,8 +47,8 @@ export function initLib() {
throw new Error('Cannot init lib-jitsi-meet without config'); throw new Error('Cannot init lib-jitsi-meet without config');
} }
// XXX Temporarily until conference.js is moved to the React app we // FIXME Until the logic of conference.js is rewritten into the React
// shouldn't use JitsiMeetJS from the React app. // app we, JitsiMeetJS.init is to not be used for the React app.
if (typeof APP !== 'undefined') { if (typeof APP !== 'undefined') {
return Promise.resolve(); return Promise.resolve();
} }

View File

@ -1,5 +1,7 @@
import { loadScript } from '../../base/util'; import { loadScript } from '../../base/util';
import URLProcessor from '../../../../modules/config/URLProcessor';
import JitsiMeetJS from './_'; import JitsiMeetJS from './_';
declare var APP: Object; declare var APP: Object;
@ -38,6 +40,12 @@ export function loadConfig(host: string, path: string = '/config.js') {
// being used for the React Native app because the old/current Web app uses // being used for the React Native app because the old/current Web app uses
// config from the global scope. // config from the global scope.
if (typeof APP !== 'undefined') { if (typeof APP !== 'undefined') {
// FIXME The following call to setConfigParametersFromUrl is bad design
// but URLProcessor still deals with the global variables config,
// interfaceConfig, and loggingConfig and loadConfig. As the latter will
// surely change in the future, so will the former then.
URLProcessor.setConfigParametersFromUrl();
return Promise.resolve(window.config); return Promise.resolve(window.config);
} }

View File

@ -1,6 +1,7 @@
/* @flow */ /* @flow */
import { SET_CONFIG } from '../config'; import { SET_CONFIG } from '../config';
import { setLoggingConfig } from '../logging';
import { PARTICIPANT_LEFT } from '../participants'; import { PARTICIPANT_LEFT } from '../participants';
import { MiddlewareRegistry } from '../redux'; import { MiddlewareRegistry } from '../redux';
@ -106,6 +107,14 @@ function _setConfig({ dispatch, getState }, next, action) {
// from there). // from there).
next(action); next(action);
// FIXME Obviously, the following is bad design. However, I'm currently
// introducing the features base/config and base/logging and I'm trying
// to minimize the scope of the changes while I'm attempting to preserve
// compatibility with the existing partially React-ified Web source code
// and what was already executing on React Native. Additionally, I do
// not care to load logging_config.js on React Native.
dispatch(setLoggingConfig(window.loggingConfig));
dispatch(initLib()); dispatch(initLib());
}); });
} }

View File

@ -0,0 +1,12 @@
import { Symbol } from '../react';
/**
* The type of redux action which sets the configuration of the feature
* base/logging.
*
* {
* type: SET_LOGGING_CONFIG,
* config: Object
* }
*/
export const SET_LOGGING_CONFIG = Symbol('SET_LOGGING_CONFIG');

View File

@ -0,0 +1,20 @@
/* @flow */
import { SET_LOGGING_CONFIG } from './actionTypes';
/**
* Sets the configuration of the feature base/logging.
*
* @param {Object} config - The configuration to set on the features
* base/logging.
* @returns {{
* type: SET_LOGGING_CONFIG,
* config: Object
* }}
*/
export function setLoggingConfig(config: Object) {
return {
type: SET_LOGGING_CONFIG,
config
};
}

View File

@ -0,0 +1,5 @@
export * from './actions';
export * from './actionTypes';
import './middleware';
import './reducer';

View File

@ -0,0 +1,131 @@
/* @flow */
import Logger from 'jitsi-meet-logger';
import { APP_WILL_MOUNT } from '../../app';
import JitsiMeetJS, { LIB_WILL_INIT } from '../lib-jitsi-meet';
import { MiddlewareRegistry } from '../redux';
import { SET_LOGGING_CONFIG } from './actionTypes';
declare var APP: Object;
/**
* The Redux middleware of the feature base/logging.
*
* @param {Store} store - The Redux store.
* @returns {Function}
* @private
*/
MiddlewareRegistry.register(store => next => action => {
switch (action.type) {
case APP_WILL_MOUNT:
return _appWillMount(store, next, action);
case LIB_WILL_INIT:
return _libWillInit(store, next, action);
case SET_LOGGING_CONFIG:
return _setLoggingConfig(store, next, action);
}
return next(action);
});
/**
* Notifies the feature base/logging that the action {@link APP_WILL_MOUNT} is
* being dispatched within a specific Redux {@code store}.
*
* @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 APP_WILL_MOUNT} which is
* being dispatched in the specified {@code store}.
* @private
* @returns {Object} The new state that is the result of the reduction of the
* specified {@code action}.
*/
function _appWillMount({ getState }, next, action) {
const { config } = getState()['features/base/logging'];
_setLogLevels(Logger, config);
// FIXME Until the logic of conference.js is rewritten into the React
// app we, JitsiMeetJS.init is to not be used for the React app.
// Consequently, LIB_WILL_INIT will not be dispatched. In the meantime, do
// the following:
typeof APP === 'undefined' || _setLogLevels(JitsiMeetJS, config);
return next(action);
}
/**
* Notifies the feature base/logging that the action {@link LIB_WILL_INIT} is
* being dispatched within a specific Redux {@code store}.
*
* @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 LIB_WILL_INIT} which is
* being dispatched in the specified {@code store}.
* @private
* @returns {Object} The new state that is the result of the reduction of the
* specified {@code action}.
*/
function _libWillInit({ getState }, next, action) {
_setLogLevels(JitsiMeetJS, getState()['features/base/logging'].config);
return next(action);
}
/**
* Notifies the feature base/logging that the action {@link SET_LOGGING_CONFIG}
* is being dispatched within a specific Redux {@code store}.
*
* @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 SET_LOGGING_CONFIG} which is
* being dispatched in the specified {@code store}.
* @private
* @returns {Object} The new state that is the result of the reduction of the
* specified {@code action}.
*/
function _setLoggingConfig({ getState }, next, action) {
const oldValue = getState()['features/base/logging'].config;
const result = next(action);
const newValue = getState()['features/base/logging'].config;
if (oldValue !== newValue) {
_setLogLevels(Logger, newValue);
_setLogLevels(JitsiMeetJS, newValue);
}
return result;
}
/**
* Sets the log levels of {@link Logger} or {@link JitsiMeetJS} in accord with
* a specific configuration.
*
* @param {Object} logger - The object on which the log levels are to be set.
* @param {Object} config - The configuration specifying the log levels to be
* set on {@code Logger} or {@code JitsiMeetJS}.
* @private
* @returns {void}
*/
function _setLogLevels(logger, config) {
// XXX The loggers of the library lib-jitsi-meet and the application
// jitsi-meet are separate, so the log levels have to be set in both.
// First, set the default log level.
logger.setLogLevel(config.defaultLogLevel);
// Second, set the log level of each logger explictly overriden by config.
Object.keys(config).forEach(
id =>
id === 'defaultLogLevel' || logger.setLogLevelById(config[id], id));
}

View File

@ -0,0 +1,61 @@
import { equals, ReducerRegistry } from '../redux';
import { SET_LOGGING_CONFIG } from './actionTypes';
/**
* The initial state of the feature base/logging.
*
* @type {{
* config: Object
* }}
*/
const INITIAL_STATE = {
config: {
defaultLogLevel: 'trace',
// The following are too verbose in their logging with the
// {@link #defaultLogLevel}:
'modules/statistics/CallStats.js': 'info',
'modules/xmpp/strophe.util.js': 'log'
}
};
ReducerRegistry.register(
'features/base/logging',
(state = INITIAL_STATE, action) => {
switch (action.type) {
case SET_LOGGING_CONFIG:
return _setLoggingConfig(state, action);
default:
return state;
}
});
/**
* Reduces a specific Redux action SET_LOGGING_CONFIG of the feature
* base/logging.
*
* @param {Object} state - The Redux state of the feature base/logging.
* @param {Action} action - The Redux action SET_LOGGING_CONFIG to reduce.
* @private
* @returns {Object} The new state of the feature base/logging after the
* reduction of the specified action.
*/
function _setLoggingConfig(state, action) {
const config = {
// The config of INITIAL_STATE is the default configuration of the
// feature base/logging.
...INITIAL_STATE.config,
...action.config
};
if (equals(state.config, config)) {
return state;
}
return {
...state,
config
};
}

View File

@ -1,3 +1,5 @@
import _ from 'lodash';
/** /**
* Sets specific properties of a specific state to specific values and prevents * Sets specific properties of a specific state to specific values and prevents
* unnecessary state changes. * unnecessary state changes.
@ -21,6 +23,19 @@ export function assign(target, source) {
return t; return t;
} }
/**
* Determines whether {@code a} equals {@code b} according to deep comparison
* (which makes sense for Redux and its state definition).
*
* @param {*} a - The value to compare to {@code b}.
* @param {*} b - The value to compare to {@code a}.
* @returns {boolean} True if {@code a} equals {@code b} (according to deep
* comparison); false, otherwise.
*/
export function equals(a, b) {
return _.isEqual(a, b);
}
/** /**
* Sets a specific property of a specific state to a specific value. Prevents * Sets a specific property of a specific state to a specific value. Prevents
* unnecessary state changes (when the specified <tt>value</tt> is equal to the * unnecessary state changes (when the specified <tt>value</tt> is equal to the