Add RecurringError class for errors that should only be logged once per session
Summary: Some errors such as UI errors should be logged whenever they occur, but some, such as those that occur when a device keeps trying to connect but can't, should not be. This adds the class and replaces the top recurring errors with it. Reviewed By: danielbuechele Differential Revision: D8639448 fbshipit-source-id: f001aa1e90eae6d26a8dbfcd3175b51fc486eae9
This commit is contained in:
committed by
Facebook Github Bot
parent
0ddeb076bb
commit
de353a7ed0
@@ -13,6 +13,7 @@ import CertificateProvider from './utils/CertificateProvider';
|
|||||||
import {RSocketServer, ReactiveSocket} from 'rsocket-core';
|
import {RSocketServer, ReactiveSocket} from 'rsocket-core';
|
||||||
import RSocketTCPServer from 'rsocket-tcp-server';
|
import RSocketTCPServer from 'rsocket-tcp-server';
|
||||||
import Client from './Client.js';
|
import Client from './Client.js';
|
||||||
|
import {RecurringError} from './utils/errors';
|
||||||
|
|
||||||
const EventEmitter = (require('events'): any);
|
const EventEmitter = (require('events'): any);
|
||||||
const invariant = require('invariant');
|
const invariant = require('invariant');
|
||||||
@@ -261,10 +262,11 @@ class ConnectionTracker {
|
|||||||
this.connectionAttempts.set(key, entry);
|
this.connectionAttempts.set(key, entry);
|
||||||
if (entry.length >= this.connectionProblemThreshold) {
|
if (entry.length >= this.connectionProblemThreshold) {
|
||||||
console.error(
|
console.error(
|
||||||
|
new RecurringError(
|
||||||
`Connection loop detected with ${key}. Connected ${
|
`Connection loop detected with ${key}. Connected ${
|
||||||
entry.length
|
this.connectionProblemThreshold
|
||||||
} times in ${(time - entry[0]) / 1000}s.`,
|
} times within ${this.timeWindowMillis / 1000}s.`,
|
||||||
'ConnectionTracker',
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import LogManager from '../fb-stubs/Logger';
|
import LogManager from '../fb-stubs/Logger';
|
||||||
|
import {RecurringError} from './errors';
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const adb = require('adbkit-fb');
|
const adb = require('adbkit-fb');
|
||||||
import {
|
import {
|
||||||
@@ -82,7 +83,7 @@ export default class CertificateProvider {
|
|||||||
this.ensureOpenSSLIsAvailable();
|
this.ensureOpenSSLIsAvailable();
|
||||||
if (!appDirectory.match(allowedAppDirectoryRegex)) {
|
if (!appDirectory.match(allowedAppDirectoryRegex)) {
|
||||||
return Promise.reject(
|
return Promise.reject(
|
||||||
new Error(
|
new RecurringError(
|
||||||
`Invalid appDirectory recieved from ${os} device: ${appDirectory}`,
|
`Invalid appDirectory recieved from ${os} device: ${appDirectory}`,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -174,7 +175,7 @@ export default class CertificateProvider {
|
|||||||
fs.writeFileSync(destination + filename, contents);
|
fs.writeFileSync(destination + filename, contents);
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
return Promise.reject(new Error(`Unsupported device os: ${os}`));
|
return Promise.reject(new RecurringError(`Unsupported device os: ${os}`));
|
||||||
}
|
}
|
||||||
|
|
||||||
getTargetDeviceId(
|
getTargetDeviceId(
|
||||||
@@ -209,7 +210,9 @@ export default class CertificateProvider {
|
|||||||
return Promise.all(deviceMatchList).then(devices => {
|
return Promise.all(deviceMatchList).then(devices => {
|
||||||
const matchingIds = devices.filter(m => m.isMatch).map(m => m.id);
|
const matchingIds = devices.filter(m => m.isMatch).map(m => m.id);
|
||||||
if (matchingIds.length == 0) {
|
if (matchingIds.length == 0) {
|
||||||
throw new Error(`No matching device found for app: ${appName}`);
|
throw new RecurringError(
|
||||||
|
`No matching device found for app: ${appName}`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return matchingIds[0];
|
return matchingIds[0];
|
||||||
});
|
});
|
||||||
@@ -261,11 +264,13 @@ export default class CertificateProvider {
|
|||||||
command: string,
|
command: string,
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
if (!user.match(allowedAppNameRegex)) {
|
if (!user.match(allowedAppNameRegex)) {
|
||||||
return Promise.reject(new Error(`Disallowed run-as user: ${user}`));
|
return Promise.reject(
|
||||||
|
new RecurringError(`Disallowed run-as user: ${user}`),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (command.match(/[']/)) {
|
if (command.match(/[']/)) {
|
||||||
return Promise.reject(
|
return Promise.reject(
|
||||||
new Error(`Disallowed escaping command: ${command}`),
|
new RecurringError(`Disallowed escaping command: ${command}`),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return this.adb
|
return this.adb
|
||||||
@@ -274,14 +279,14 @@ export default class CertificateProvider {
|
|||||||
.then(buffer => buffer.toString())
|
.then(buffer => buffer.toString())
|
||||||
.then(output => {
|
.then(output => {
|
||||||
if (output.match(appNotDebuggableRegex)) {
|
if (output.match(appNotDebuggableRegex)) {
|
||||||
const e = new Error(
|
const e = new RecurringError(
|
||||||
`Android app ${user} is not debuggable. To use it with sonar, add android:debuggable="true" to the application section of AndroidManifest.xml`,
|
`Android app ${user} is not debuggable. To use it with sonar, add android:debuggable="true" to the application section of AndroidManifest.xml`,
|
||||||
);
|
);
|
||||||
this.server.emit('error', e);
|
this.server.emit('error', e);
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
if (output.toLowerCase().match(operationNotPermittedRegex)) {
|
if (output.toLowerCase().match(operationNotPermittedRegex)) {
|
||||||
const e = new Error(
|
const e = new RecurringError(
|
||||||
`Your android device (${deviceId}) does not support the adb shell run-as command. We're tracking this at https://github.com/facebook/Sonar/issues/92`,
|
`Your android device (${deviceId}) does not support the adb shell run-as command. We're tracking this at https://github.com/facebook/Sonar/issues/92`,
|
||||||
);
|
);
|
||||||
this.server.emit('error', e);
|
this.server.emit('error', e);
|
||||||
@@ -307,13 +312,13 @@ export default class CertificateProvider {
|
|||||||
.then(subject => {
|
.then(subject => {
|
||||||
const matches = subject.trim().match(x509SubjectCNRegex);
|
const matches = subject.trim().match(x509SubjectCNRegex);
|
||||||
if (!matches || matches.length < 2) {
|
if (!matches || matches.length < 2) {
|
||||||
throw new Error(`Cannot extract CN from ${subject}`);
|
throw new RecurringError(`Cannot extract CN from ${subject}`);
|
||||||
}
|
}
|
||||||
return matches[1];
|
return matches[1];
|
||||||
})
|
})
|
||||||
.then(appName => {
|
.then(appName => {
|
||||||
if (!appName.match(allowedAppNameRegex)) {
|
if (!appName.match(allowedAppNameRegex)) {
|
||||||
throw new Error(
|
throw new RecurringError(
|
||||||
`Disallowed app name in CSR: ${appName}. Only alphanumeric characters and '.' allowed.`,
|
`Disallowed app name in CSR: ${appName}. Only alphanumeric characters and '.' allowed.`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
14
src/utils/errors.js
Normal file
14
src/utils/errors.js
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2018-present Facebook.
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
* @format
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Class of errors that may keep repeating but should only be logged once.
|
||||||
|
export class RecurringError extends Error {
|
||||||
|
constructor(message: string) {
|
||||||
|
super(message);
|
||||||
|
this.name = 'RecurringError';
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user