Merge pull request #7864 from antobinary/extra-logs

Attempt to capture & log more info on client errors
This commit is contained in:
Chad Pilkey 2019-08-01 12:54:29 -04:00 committed by GitHub
commit 91e710fae7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 55 additions and 69 deletions

View File

@ -23,7 +23,12 @@ Meteor.startup(() => {
if (!stack.includes(message)) {
stack = `${message}\n${stack}`;
}
logger.error({ logCode: 'startup_error', stackTrace: stack }, message);
logger.error({
logCode: 'startup_error',
extraInfo: {
stackTrace: stack,
},
}, message);
});
// TODO make this a Promise

View File

@ -1,6 +1,6 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { log } from '/imports/ui/services/api';
import logger from '/imports/startup/client/logger';
const propTypes = {
low: PropTypes.number,
@ -38,7 +38,8 @@ class AudioStreamVolume extends Component {
}
componentDidUpdate(prevProps) {
if (prevProps.deviceId !== this.props.deviceId) {
const { deviceId: nextDeviceId } = this.props;
if (prevProps.deviceId !== nextDeviceId) {
this.closeAudioContext().then(() => {
this.setState({
slow: 0,
@ -102,7 +103,10 @@ class AudioStreamVolume extends Component {
}
handleError(error) {
log('error', JSON.stringify(error));
logger.error({
logCode: 'audiostreamvolume_handleError',
extraInfo: { error },
}, 'Encountered error while creating audio context');
}
render() {
@ -110,6 +114,8 @@ class AudioStreamVolume extends Component {
low, optimum, high, ...props
} = this.props;
const { slow } = this.state;
return (
<meter
{...props}
@ -118,7 +124,7 @@ class AudioStreamVolume extends Component {
low={low}
optimum={optimum}
high={high}
value={this.state.slow}
value={slow}
/>
);
}

View File

@ -1,6 +1,6 @@
import React, { Component } from 'react';
import { Session } from 'meteor/session';
import { log } from '/imports/ui/services/api';
import logger from '/imports/startup/client/logger';
import Auth from '/imports/ui/services/auth';
import LoadingScreen from '/imports/ui/components/loading-screen/component';
@ -43,7 +43,11 @@ class AuthenticatedHandler extends Component {
AuthenticatedHandler.addReconnectObservable();
const setReason = (reason) => {
log('error', reason);
logger.error({
logCode: 'authenticatedhandlercomponent_setreason',
extraInfo: { reason },
}, 'Encountered error while trying to authenticate');
AuthenticatedHandler.setError(reason.error);
callback();
};

View File

@ -49,6 +49,7 @@ class JoinHandler extends Component {
logger.error({
logCode: 'joinhandler_component_fetchToken_not_connected',
extraInfo: {
attemptForUserInfo: Auth.fullInfo,
numFetchTokenRetries: this.numFetchTokenRetries,
},
}, 'Meteor was not connected, retry in a few moments');

View File

@ -1,6 +1,6 @@
import Auth from '/imports/ui/services/auth';
import { check } from 'meteor/check';
import { notify } from '/imports/ui/services/notification';
import logger from '/imports/startup/client/logger';
/**
* Send the request to the server via Meteor.call and don't treat errors.
@ -25,37 +25,14 @@ export function makeCall(name, ...args) {
resolve(result);
});
} else {
reject(new Error('Meteor was not connected'));
reject(() => logger.warn({
logCode: 'servicesapiindex_makeCall',
extraInfo: {
attemptForUserInfo: Auth.fullInfo,
name,
...args,
},
}, 'Connection to Meteor was interrupted.'));
}
});
}
/**
* Send the request to the server via Meteor.call and treat the error to a default callback.
*
* @param {string} name
* @param {any} args
* @see https://docs.meteor.com/api/methods.html#Meteor-call
* @return {Promise}
*/
export function call(name, ...args) {
return makeCall(name, ...args).catch((e) => {
notify(`Ops! Error while executing ${name}`, 'error');
throw e;
});
}
export function log(type = 'error', message, ...args) {
const { credentials } = Auth;
const logContents = { ...args };
const topic = logContents[0] ? logContents[0].topic : null;
const messageOrStack = message.stack || message.message || JSON.stringify(message);
console.debug(`CLIENT LOG (${topic ? `${type.toUpperCase()}.${topic}` : type.toUpperCase()}): `, messageOrStack, ...args);
Meteor.call('logClient', type, messageOrStack, {
credentials,
...args,
});
}

View File

@ -1,10 +1,7 @@
import { log } from '/imports/ui/services/api';
const VISIBILITY_TIMEOUT = 5000;
export default class VisibilityEvent {
constructor () {
constructor() {
this._onVisible = null;
this._onHidden = null;
@ -15,7 +12,7 @@ export default class VisibilityEvent {
this._onHiddenTimeout = null;
}
onVisible (onVisibleCallback) {
onVisible(onVisibleCallback) {
this._onVisible = () => {
if (!this._isHidden()) {
onVisibleCallback();
@ -33,12 +30,11 @@ export default class VisibilityEvent {
}
removeEventListeners() {
let event = this._getVisibilityEvent();
const event = this._getVisibilityEvent();
document.removeEventListener(event, this._handleVisibilityChange, false);
}
_handleVisibilityChange () {
_handleVisibilityChange() {
if (!this._isHidden()) {
if (this._onVisible) {
if (this._onHiddenTimeout) {
@ -48,25 +44,23 @@ export default class VisibilityEvent {
this._onVisible();
}
}
} else {
if (this._onHidden) {
if (!this._onHiddenTimeout) {
this._onHiddenTimeout = setTimeout(this._onHidden.bind(this), VISIBILITY_TIMEOUT);
}
} else if (this._onHidden) {
if (!this._onHiddenTimeout) {
this._onHiddenTimeout = setTimeout(this._onHidden.bind(this), VISIBILITY_TIMEOUT);
}
}
}
_getHiddenProp () {
let prefixes = ['webkit', 'moz', 'ms', 'o'];
_getHiddenProp() {
const prefixes = ['webkit', 'moz', 'ms', 'o'];
// if 'hidden' is natively supported just return it
if ('hidden' in document) return 'hidden';
// otherwise loop over all the known prefixes unti we find one
for (var i = 0; i < prefixes.length; i++) {
if ((prefixes[i] + 'Hidden') in document) {
return prefixes[i] + 'Hidden';
for (let i = 0; i < prefixes.length; i++) {
if ((`${prefixes[i]}Hidden`) in document) {
return `${prefixes[i]}Hidden`;
}
}
@ -74,8 +68,8 @@ export default class VisibilityEvent {
return null;
}
_isHidden () {
var prop = this._getHiddenProp();
_isHidden() {
const prop = this._getHiddenProp();
if (!prop) {
return false;
@ -84,21 +78,20 @@ export default class VisibilityEvent {
}
_getVisibilityEvent() {
let hidden, visibilityChange;
if (typeof document.hidden !== "undefined") {
visibilityChange = "visibilitychange";
} else if (typeof document.msHidden !== "undefined") {
visibilityChange = "msvisibilitychange";
} else if (typeof document.webkitHidden !== "undefined") {
visibilityChange = "webkitvisibilitychange";
let visibilityChange;
if (typeof document.hidden !== 'undefined') {
visibilityChange = 'visibilitychange';
} else if (typeof document.msHidden !== 'undefined') {
visibilityChange = 'msvisibilitychange';
} else if (typeof document.webkitHidden !== 'undefined') {
visibilityChange = 'webkitvisibilitychange';
}
return visibilityChange;
}
_registerVisibilityEvent () {
let event = this._getVisibilityEvent();
_registerVisibilityEvent() {
const event = this._getVisibilityEvent();
document.addEventListener(event, this._handleVisibilityChange, false);
}
}