mirror of
https://github.com/vale981/Vulcan
synced 2025-03-05 09:31:43 -05:00
vulcan-errors package
This commit is contained in:
parent
47bd12eb80
commit
983c9ed08a
10 changed files with 422 additions and 0 deletions
1
packages/vulcan-errors/README.md
Normal file
1
packages/vulcan-errors/README.md
Normal file
|
@ -0,0 +1 @@
|
|||
Vulcan error tracking package.
|
1
packages/vulcan-errors/lib/client/main.js
Normal file
1
packages/vulcan-errors/lib/client/main.js
Normal file
|
@ -0,0 +1 @@
|
|||
export * from '../modules/index.js';
|
45
packages/vulcan-errors/lib/components/ErrorCatcher.jsx
Normal file
45
packages/vulcan-errors/lib/components/ErrorCatcher.jsx
Normal file
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
|
||||
ErrorCatcher
|
||||
|
||||
Usage:
|
||||
|
||||
<Components.ErrorCatcher>
|
||||
<YourComponentTree />
|
||||
</Components.ErrorCatcher>
|
||||
|
||||
*/
|
||||
|
||||
import { Components, registerComponent, withCurrentUser } from 'meteor/vulcan:core';
|
||||
import React, { Component } from 'react';
|
||||
import { Errors } from '../modules/errors.js';
|
||||
|
||||
class ErrorCatcher extends Component {
|
||||
state = {
|
||||
error: null,
|
||||
};
|
||||
|
||||
componentDidCatch = (error, errorInfo) => {
|
||||
const { currentUser } = this.props;
|
||||
this.setState({ error });
|
||||
Errors.log({
|
||||
message: error.message,
|
||||
error,
|
||||
details: errorInfo,
|
||||
currentUser,
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { error } = this.state;
|
||||
return error ? (
|
||||
<div className="error-catcher">
|
||||
<Components.Flash message={{ id: 'errors.generic_report', properties: { errorMessage: error.message } }} />
|
||||
</div>
|
||||
) : (
|
||||
this.props.children
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
registerComponent('ErrorCatcher', ErrorCatcher, withCurrentUser);
|
59
packages/vulcan-errors/lib/components/ErrorsUserMonitor.jsx
Normal file
59
packages/vulcan-errors/lib/components/ErrorsUserMonitor.jsx
Normal file
|
@ -0,0 +1,59 @@
|
|||
import React, { PureComponent } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Components, registerComponent, withCurrentUser } from 'meteor/vulcan:core';
|
||||
import classNames from 'classnames';
|
||||
import { Errors } from 'meteor/vulcan:errors';
|
||||
|
||||
class ErrorsUserMonitor extends PureComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.checkCurrentUser();
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
this.checkCurrentUser();
|
||||
}
|
||||
|
||||
checkCurrentUser(prevProps, prevState, snapshot) {
|
||||
const currentUser = this.props.currentUser;
|
||||
|
||||
const currentUserId = currentUser && currentUser._id;
|
||||
const errorsUserId = Errors.currentUser && Errors.currentUser._id;
|
||||
|
||||
if (currentUserId !== errorsUserId) {
|
||||
const currentUserEmail = currentUser && currentUser.email;
|
||||
const errorsUserEmail = Errors.currentUser && Errors.currentUser.email;
|
||||
|
||||
console.log(`User changed from ${errorsUserEmail} (${errorsUserId}) to ${currentUserEmail} (${currentUserId})`);
|
||||
|
||||
Errors.setCurrentUser(currentUser);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { className, currentUser } = this.props;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classNames(
|
||||
'errors-user-monitor',
|
||||
(currentUser && currentUser._id) || 'no-user',
|
||||
currentUser && currentUser.email,
|
||||
className
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ErrorsUserMonitor.propTypes = {
|
||||
className: PropTypes.string,
|
||||
currentUser: PropTypes.object,
|
||||
};
|
||||
|
||||
ErrorsUserMonitor.displayName = 'ErrorsUserMonitor';
|
||||
|
||||
registerComponent('ErrorsUserMonitor', ErrorsUserMonitor, withCurrentUser);
|
197
packages/vulcan-errors/lib/modules/errors.js
Normal file
197
packages/vulcan-errors/lib/modules/errors.js
Normal file
|
@ -0,0 +1,197 @@
|
|||
import Users from 'meteor/vulcan:users';
|
||||
import { getSetting } from 'meteor/vulcan:core';
|
||||
import get from 'lodash/get';
|
||||
import isEqual from 'lodash/isEqual';
|
||||
import { formatMessage } from 'meteor/vulcan:i18n';
|
||||
import _isEmpty from 'lodash/isEmpty';
|
||||
import { inspect } from 'util';
|
||||
|
||||
export const initFunctions = [];
|
||||
export const logFunctions = [];
|
||||
export const userFunctions = [];
|
||||
export const scrubFields = new Set();
|
||||
|
||||
export const userFields = {
|
||||
id: '_id',
|
||||
email: 'email',
|
||||
username: 'profile.username',
|
||||
isAdmin: 'isAdmin',
|
||||
};
|
||||
|
||||
export const addInitFunction = fn => {
|
||||
initFunctions.push(fn);
|
||||
// execute init function as soon as possible
|
||||
fn();
|
||||
};
|
||||
|
||||
export const addLogFunction = fn => {
|
||||
logFunctions.push(fn);
|
||||
};
|
||||
|
||||
export const addUserFunction = fn => {
|
||||
userFunctions.push(fn);
|
||||
};
|
||||
|
||||
export const addUserFields = fields => {
|
||||
Object.assign(userFields, fields);
|
||||
};
|
||||
|
||||
export const addScrubFields = fields => {
|
||||
fields = Array.isArray(fields) ? fields : [fields];
|
||||
for (const field of fields) {
|
||||
scrubFields.add(field);
|
||||
}
|
||||
};
|
||||
|
||||
// export const getUserPayload = function(userOrUserId) {
|
||||
// try {
|
||||
// const user = Users.getUser(userOrUserId);
|
||||
// if (!user) return null;
|
||||
|
||||
// const userPayload = {};
|
||||
|
||||
// for (const field in userFields) {
|
||||
// const path = userFields[field];
|
||||
// userPayload[field] = get(user, path);
|
||||
// }
|
||||
|
||||
// return userPayload;
|
||||
// } catch (error) {
|
||||
// return null;
|
||||
// }
|
||||
// };
|
||||
|
||||
// export const getServerHost = function() {
|
||||
// return process.env.GALAXY_CONTAINER_ID
|
||||
// ? process.env.GALAXY_CONTAINER_ID.split('-')[1]
|
||||
// : getSetting('public.environment');
|
||||
// };
|
||||
|
||||
// export const processApolloErrors = function(err) {
|
||||
// if (!err) return;
|
||||
|
||||
// const apolloErrors =
|
||||
// err.original && err.original.data && err.original.data.errors
|
||||
// ? formatApolloError(err.original, formatMessage, '\n', ' ApolloError: ')
|
||||
// : err.data && err.data.errors
|
||||
// ? formatApolloError(err, formatMessage, '\n', ' ApolloError: ')
|
||||
// : '';
|
||||
|
||||
// err.message = err.message + '\n' + apolloErrors;
|
||||
// };
|
||||
|
||||
// export const formatApolloError = (err, formatMessage, separator = ', ', prefix = '') => {
|
||||
// let formatted = '';
|
||||
|
||||
// const formatProperties = properties => {
|
||||
// return _isEmpty(properties) ? '' : ' ' + inspect(properties);
|
||||
// };
|
||||
|
||||
// const addError = error => {
|
||||
// let message = '';
|
||||
|
||||
// if (error.id) {
|
||||
// try {
|
||||
// message = formatMessage({ id: error.id }, error.properties);
|
||||
// } catch (err) {
|
||||
// message = error.id + formatProperties(error.properties);
|
||||
// }
|
||||
// } else if (error.message) {
|
||||
// message = error.message + formatProperties(error.properties);
|
||||
// }
|
||||
|
||||
// formatted += formatted ? separator : '';
|
||||
// formatted += prefix + message;
|
||||
// };
|
||||
|
||||
// const graphQLErrors = err.data && err.data.errors ? [err] : err.graphQLErrors;
|
||||
|
||||
// if (graphQLErrors) {
|
||||
// for (let graphQLError of graphQLErrors) {
|
||||
// if (graphQLError.data && graphQLError.data.errors) {
|
||||
// for (let innerError of graphQLError.data.errors) {
|
||||
// if (innerError.data) {
|
||||
// addError(innerError.data);
|
||||
// } else {
|
||||
// addError(innerError);
|
||||
// }
|
||||
// }
|
||||
// } else if (graphQLError.data) {
|
||||
// addError(graphQLError.data);
|
||||
// } else {
|
||||
// addError(graphQLError);
|
||||
// }
|
||||
// }
|
||||
// } else {
|
||||
// let message = err.message;
|
||||
// const graphqlPrefixIsPresent = message.match(/GraphQL error: (.*)/);
|
||||
// addError({ message: graphqlPrefixIsPresent ? graphqlPrefixIsPresent[1] : message });
|
||||
// }
|
||||
|
||||
// return formatted;
|
||||
// };
|
||||
|
||||
export const Errors = {
|
||||
currentUser: null,
|
||||
|
||||
setCurrentUser: function(user) {
|
||||
// avoid setting current user multiple times
|
||||
if (isEqual(this.currentUser, user)) return;
|
||||
|
||||
for (const fn of userFunctions) {
|
||||
try {
|
||||
fn(user);
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(`// ${fn.name} with ${user && user.email}`);
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
this.currentUser = user;
|
||||
},
|
||||
|
||||
/*rethrow: function (message, err, details, level = 'error') {
|
||||
err = new RethrownError(message, err, { stack: true, remove: 1 });
|
||||
Errors.log({ err, details, level });
|
||||
},*/
|
||||
|
||||
log: function(params) {
|
||||
const { message, err, level = 'error' } = params;
|
||||
// processApolloErrors(err);
|
||||
|
||||
for (const fn of logFunctions) {
|
||||
try {
|
||||
fn(params);
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(`// ${fn.name} ${level} error for '${(err && err.message) || message}'`);
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/*
|
||||
|
||||
Shortcuts
|
||||
|
||||
*/
|
||||
debug: params => Errors.log({ level: 'debug', ...params }),
|
||||
|
||||
info: params => Errors.log({ level: 'info', ...params }),
|
||||
|
||||
warning: params => Errors.log({ level: 'warning', ...params }),
|
||||
|
||||
error: params => Errors.log({ level: 'error', ...params }),
|
||||
|
||||
critical: params => Errors.log({ level: 'info', ...params }),
|
||||
|
||||
// getMethodDetails: function(method) {
|
||||
// return {
|
||||
// userId: method.userId,
|
||||
// headers: method.connection && method.connection.httpHeaders,
|
||||
// };
|
||||
// },
|
||||
};
|
50
packages/vulcan-errors/lib/modules/extended-NOTUSED.js
Normal file
50
packages/vulcan-errors/lib/modules/extended-NOTUSED.js
Normal file
|
@ -0,0 +1,50 @@
|
|||
// This is experimental and not actually used by vulcan:errors
|
||||
|
||||
// ### ExtendedError
|
||||
// From https://github.com/deployable/deployable-errors
|
||||
|
||||
// Custom errors can extend this
|
||||
|
||||
export default class ExtendedError extends Error {
|
||||
constructor(message, options = {}) {
|
||||
// Make it an error
|
||||
super(message);
|
||||
|
||||
// Standard Error things
|
||||
this.name = this.constructor.name;
|
||||
this.message = message;
|
||||
|
||||
// Get a stack trace where we can
|
||||
/* istanbul ignore else */
|
||||
if (typeof Error.captureStackTrace === 'function') {
|
||||
Error.captureStackTrace(this, this.constructor);
|
||||
} else {
|
||||
this.stack = new Error(message).stack;
|
||||
}
|
||||
|
||||
// A standard place to store a more human readable error message
|
||||
if (options.simple) this.simple = options.simple;
|
||||
}
|
||||
|
||||
// Support `.statusCode` for express
|
||||
get statusCode() {
|
||||
return this.status;
|
||||
}
|
||||
|
||||
set statusCode(val) {
|
||||
this.status = val;
|
||||
}
|
||||
|
||||
// Fix Errors `.toJSON` for our errors
|
||||
toJSON() {
|
||||
let o = {};
|
||||
Object.getOwnPropertyNames(this).forEach(key => (o[key] = this[key]), this);
|
||||
return o;
|
||||
}
|
||||
|
||||
toResponse() {
|
||||
let o = this.toJSON();
|
||||
if (process && process.env && process.env.NODE_ENV !== 'development') delete o.stack;
|
||||
return o;
|
||||
}
|
||||
}
|
3
packages/vulcan-errors/lib/modules/index.js
Normal file
3
packages/vulcan-errors/lib/modules/index.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
import '../components/ErrorsUserMonitor';
|
||||
import '../components/ErrorCatcher';
|
||||
export * from './errors';
|
45
packages/vulcan-errors/lib/modules/rethrown-NOTUSED.js
Normal file
45
packages/vulcan-errors/lib/modules/rethrown-NOTUSED.js
Normal file
|
@ -0,0 +1,45 @@
|
|||
import ExtendedError from './extended';
|
||||
|
||||
// This is experimental and not actually used by vulcan:errors
|
||||
|
||||
/**
|
||||
* Rethrow an error that you caught in your code, adding an additional message,
|
||||
* and preserving the stack trace
|
||||
*
|
||||
* Based on https://github.com/deployable/deployable-errors
|
||||
* See https://stackoverflow.com/questions/42754270/re-throwing-exception-in-nodejs-and-not-losing-stack-trace
|
||||
*
|
||||
* @example
|
||||
* try {
|
||||
* ... some code
|
||||
* } catch (error) {
|
||||
* new RethrownError('new error message', error, { stack: true });
|
||||
* }
|
||||
*/
|
||||
export default class RethrownError extends ExtendedError {
|
||||
/**
|
||||
* @param {string} message - An error message
|
||||
* @param {Error} error - An Error caught in a catch block
|
||||
* @param {Object} [options] - The employee who is responsible for the project.
|
||||
* @param {boolean|number} [options.stack] - Enable, disable or set the number of lines of stack output
|
||||
* @param {number} [options.remove] - The number of lines to remove from the beginning of the stack trace
|
||||
*/
|
||||
constructor(message, error, options = {}) {
|
||||
super(message);
|
||||
if (!error) throw new Error(`new ${this.name} requires a message and error`);
|
||||
|
||||
let message_lines = (this.message.match(/\n/g) || []).length + 1;
|
||||
let stack_array = this.stack.split('\n');
|
||||
|
||||
if (options.remove) {
|
||||
stack_array.splice(message_lines, options.remove);
|
||||
}
|
||||
|
||||
if (options.stack !== true) {
|
||||
stack_array = stack_array.slice(0, message_lines + (options.stack || 0));
|
||||
}
|
||||
|
||||
//this.original = error;
|
||||
this.stack = stack_array.join('\n') + '\n' + error.stack;
|
||||
}
|
||||
}
|
1
packages/vulcan-errors/lib/server/main.js
Normal file
1
packages/vulcan-errors/lib/server/main.js
Normal file
|
@ -0,0 +1 @@
|
|||
export * from '../modules/index.js';
|
20
packages/vulcan-errors/package.js
Normal file
20
packages/vulcan-errors/package.js
Normal file
|
@ -0,0 +1,20 @@
|
|||
Package.describe({
|
||||
name: "vulcan:errors",
|
||||
summary: "Vulcan error tracking package",
|
||||
version: '1.12.8',
|
||||
git: "https://github.com/VulcanJS/Vulcan.git"
|
||||
});
|
||||
|
||||
Package.onUse(function(api) {
|
||||
|
||||
api.versionsFrom('1.6.1');
|
||||
|
||||
api.use([
|
||||
'ecmascript',
|
||||
'vulcan:core',
|
||||
]);
|
||||
|
||||
api.mainModule("lib/server/main.js", "server");
|
||||
api.mainModule('lib/client/main.js', 'client');
|
||||
|
||||
});
|
Loading…
Add table
Reference in a new issue