Skip to content

Commit

Permalink
Merge branch 'feat/sentry-integration'
Browse files Browse the repository at this point in the history
  • Loading branch information
toverux committed Jun 26, 2017
2 parents 8454af4 + 7c146c6 commit fe99d0a
Show file tree
Hide file tree
Showing 10 changed files with 107 additions and 16 deletions.
1 change: 1 addition & 0 deletions .env.defaults
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ CHUCK_ENV=development
CHUCK_LOGLEVEL=verbose
CHUCK_SERVERPORT=3001
CHUCK_MONGOURL=mongodb://localhost/chuck
CHUCK_RAVENDSN=
CHUCK_REDIS_HOST=localhost
CHUCK_REDIS_PORT=6379
CHUCK_REDIS_DB=0
Expand Down
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ Chuck notably features REST & Server-Sent APIs, a command-line interface, an adm
- :warning: **An _activated_ installation of Unity on the machine** :warning:
- If Unity is not installed in the standard path, configure the path via the [Configuration](#configuration)
- You must activate Unity if not already done, even with a free plan, read [Unity activation](https://github.com/mitmadness/AssetBundleCompiler#unity-activation) from AssetBundleCompiler
- An installation of **[IfcConvert (IfcOpenShell)](http://ifcopenshell.org/ifcconvert.html)** available as `IfcConvert` via the `PATH`, but only if you are converting IFC files.

Also, except logging them, chuck can optionally report fatal errors on [Sentry](https://sentry.io/welcome/). To enable this, [configure](#configuration) your Sentry DSN.

## Installation

Expand Down Expand Up @@ -147,6 +148,10 @@ interface IChuckConfig {
// Defaults to mongodb://localhost/chuck
mongoUrl: string;

// DSN for Sentry error reporting.
// Reporting is disabled if this is not set.
ravenDsn: string;

// Redis connection informations.
// Defaults to { host: 'localhost', port: 6379, db: 0 }
redis: { host: string; port: number; db: number };
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"@types/morgan": "^1.7.32",
"@types/node-fetch": "^1.6.7",
"@types/pify": "^0.0.28",
"@types/raven": "^1.2.2",
"@types/source-map-support": "^0.2.28",
"@types/uuid": "^2.0.29",
"@types/winston": "^2.3.1",
Expand Down Expand Up @@ -60,6 +61,7 @@
"node-fetch": "^1.6.3",
"pify": "^3.0.0",
"pug": "^2.0.0-rc.1",
"raven": "^2.1.0",
"source-map-support": "^0.4.15",
"toureiro": "^0.2.13",
"uuid": "^3.0.1",
Expand Down
9 changes: 7 additions & 2 deletions src/api/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import * as express from 'express';
import * as raven from 'raven';
import conversionsApi from './conversions_api';
import { errorHandler } from './middlewares';
import { fatalErrorsHandler, recoverableErrorsHandler } from './middlewares';

const router: express.Router = express.Router();

//=> API endpoint roots
router.use('/conversions', conversionsApi);

router.use(errorHandler());
//=> Install error handlers
router.use(recoverableErrorsHandler());
router.use(raven.errorHandler());
router.use(fatalErrorsHandler());

export default router;
21 changes: 17 additions & 4 deletions src/api/middlewares.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ import { wrapAsync } from '../express_utils';
import { safeErrorSerialize } from '../safe_error_serialize';
import { isKeyValid } from './api_keys_cache';

interface ISentryResponse extends Response {
sentry?: string;
}

export function hasValidApiKey(): Handler {
return wrapAsync(async (req: Request, res: Response, next: NextFunction): Promise<void> => {
const authHeader = req.header('Authorization');
Expand All @@ -22,7 +26,7 @@ export function hasValidApiKey(): Handler {
});
}

export function errorHandler(): ErrorRequestHandler {
export function recoverableErrorsHandler(): ErrorRequestHandler {
return (err: any, req: Request, res: Response, next: NextFunction): void => {
//=> Headers already sent, let Express handle the thing
if (res.headersSent) {
Expand All @@ -43,10 +47,19 @@ export function errorHandler(): ErrorRequestHandler {
});
}

//=> In all other cases, return a 500 error
res.status(500).json(safeErrorSerialize(err));
//=> We can't recognize this error, pass to the next error handler.
next(err);
};
}

//=> Log it because that's unexpected
export function fatalErrorsHandler(): ErrorRequestHandler {
return (err: any, req: Request, res: ISentryResponse, next: NextFunction): void => {
//=> We don't know what this error is, return a 500 error
res.status(500).json(safeErrorSerialize(err, res.sentry));

//=> Log it because that's, well, unexpected
logger.error(err);

next();
};
}
17 changes: 17 additions & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ import * as path from 'path';
export type EnvType = 'development'|'production';

export interface IChuckConfig {
/**
* The release number of chuck, as specified in the package.json.
* This will only have a real value in the npm distribution of chuck -- value is otherwise "0.0.0-development".
*/
release: string;

/**
* aka NODE_ENV. Configures the mode (`development` or `production`) in which the server is running.
* - development: permissive CORS rules are set on the API
Expand Down Expand Up @@ -35,6 +41,11 @@ export interface IChuckConfig {
*/
mongoUrl: string;

/**
* DSN for Sentry error reporting.
*/
ravenDsn: string;

/**
* Redis connection informations.
*
Expand Down Expand Up @@ -76,12 +87,18 @@ dotenvx.load({
defaults: path.resolve(`${__dirname}/../.env.defaults`)
});

//=> Determine release number
// tslint:disable-next-line:no-var-requires
const release = require('../package.json').version;

//=> Hydrate config with the environment variables
const config: IChuckConfig = {
release,
env: process.env.NODE_ENV || process.env.CHUCK_ENV,
logLevel: process.env.CHUCK_LOGLEVEL,
serverPort: parseInt(process.env.CHUCK_SERVERPORT, 10),
mongoUrl: process.env.CHUCK_MONGOURL,
ravenDsn: process.env.CHUCK_RAVENDSN,
redis: {
host: process.env.CHUCK_REDIS_HOST,
port: parseInt(process.env.CHUCK_REDIS_PORT, 10),
Expand Down
11 changes: 10 additions & 1 deletion src/converter/queue_event_handlers.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import * as raven from 'raven';
import config from '../config';
import logger from '../logger';
import { safeErrorSerialize } from '../safe_error_serialize';
import { IConversionJob, IProgressReportJob, updateConversion } from './job';
Expand Down Expand Up @@ -66,13 +68,20 @@ export async function onJobCompleted(job: IConversionJob, assetBundleUrl: string
}

export async function onJobFailed(job: IConversionJob, error: any): Promise<void> {
//=> Log & report on Sentry
logger.error(`convqueue: job #${job.jobId} has failed!`, error);

if (config.ravenDsn) {
raven.captureException(error);
}

//=> Report in job's progress log
const progressTask = job.progress(queueConversionEndedEvent(
'Conversion failed, an error occured!', null, error
));

// we don't update conversion.step to let the client know where the fail occured
//=> Update the conversion document infos about progress.
// We don't update conversion.step to let the client know where the fail occured.
const updateTask = updateConversion(job, {
$set: {
'conversion.isCompleted': true,
Expand Down
10 changes: 7 additions & 3 deletions src/entry/bootstrap.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
import * as raven from 'raven';
import * as sourceMapSupport from 'source-map-support';
import '../config';
import config from '../config';
import logger from '../logger';

sourceMapSupport.install();

config.ravenDsn && raven.config(config.ravenDsn, {
release: config.release,
environment: config.env
}).install();

process.on('unhandledRejection', (reason: any): void => {
logger.error('UNHANDLED REJECTION', reason);
process.exit(1);
});

process.on('uncaughtException', (err: any): void => {
logger.error('UNCAUGHT EXCEPTION', err);
process.exit(1);
});
8 changes: 7 additions & 1 deletion src/safe_error_serialize.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
export interface IPlainObjectError {
name: string;
message: string;
errorId?: string;
errors?: any[];
}

export function safeErrorSerialize(error: any): IPlainObjectError {
export function safeErrorSerialize(error: any, sentryErrorId?: string): IPlainObjectError {
const plainError: any = {};

//=> Error name
Expand All @@ -13,6 +14,11 @@ export function safeErrorSerialize(error: any): IPlainObjectError {
//=> Error message
plainError.message = error.message || 'Unknown error';

//=> Set error's ID if given
if (sentryErrorId) {
plainError.errorId = sentryErrorId;
}

//=> Serialize recursively sub-errors if any
if (error.errors) {
plainError.errors = error.errors.map(safeErrorSerialize);
Expand Down
37 changes: 33 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,12 @@
version "0.0.28"
resolved "https://registry.yarnpkg.com/@types/pify/-/pify-0.0.28.tgz#682b6c33a1d05748b86f029bdab6f62aa73ff506"

"@types/raven@^1.2.2":
version "1.2.2"
resolved "https://registry.yarnpkg.com/@types/raven/-/raven-1.2.2.tgz#afe52bd98187a3a3d28b8212e363143bd16f23bf"
dependencies:
"@types/node" "*"

"@types/redis@*":
version "0.12.36"
resolved "https://registry.yarnpkg.com/@types/redis/-/redis-0.12.36.tgz#61df652a269af425fe2e9ee95cdfa175577b4c3b"
Expand Down Expand Up @@ -1896,7 +1902,7 @@ json-stable-stringify@^1.0.1:
dependencies:
jsonify "~0.0.0"

json-stringify-safe@~5.0.1:
json-stringify-safe@5.0.1, json-stringify-safe@~5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"

Expand Down Expand Up @@ -2124,6 +2130,10 @@ lru-cache@^4.0.1:
pseudomap "^1.0.1"
yallist "^2.0.0"

lsmod@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/lsmod/-/lsmod-1.0.0.tgz#9a00f76dca36eb23fa05350afe1b585d4299e64b"

map-obj@^1.0.0, map-obj@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d"
Expand Down Expand Up @@ -2896,6 +2906,17 @@ range-parser@~1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e"

raven@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/raven/-/raven-2.1.0.tgz#1b624e56374d9c9d93c74448461a2a356ce37527"
dependencies:
cookie "0.3.1"
json-stringify-safe "5.0.1"
lsmod "1.0.0"
stack-trace "0.0.9"
timed-out "4.0.1"
uuid "3.0.0"

raw-body@~2.1.5:
version "2.1.7"
resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.1.7.tgz#adfeace2e4fb3098058014d08c072dcc59758774"
Expand Down Expand Up @@ -3402,9 +3423,9 @@ sshpk@^1.7.0:
jsbn "~0.1.0"
tweetnacl "~0.14.0"

stack-trace@0.0.x:
version "0.0.10"
resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0"
stack-trace@0.0.9, stack-trace@0.0.x:
version "0.0.9"
resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.9.tgz#a8f6eaeca90674c333e7c43953f275b451510695"

statuses@1, "statuses@>= 1.3.1 < 2", statuses@~1.3.1:
version "1.3.1"
Expand Down Expand Up @@ -3528,6 +3549,10 @@ through@2, through@~2.3, through@~2.3.1, through@~2.3.4:
version "2.3.8"
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"

timed-out@4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f"

timed-out@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-2.0.0.tgz#f38b0ae81d3747d628001f41dafc652ace671c0a"
Expand Down Expand Up @@ -3709,6 +3734,10 @@ utils-merge@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.0.tgz#0294fb922bb9375153541c4f7096231f287c8af8"

uuid@3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.0.tgz#6728fc0459c450d796a99c31837569bdf672d728"

uuid@^2.0.1:
version "2.0.3"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a"
Expand Down

0 comments on commit fe99d0a

Please sign in to comment.