Skip to content

Instantly share code, notes, and snippets.

@nodkz
Created February 7, 2017 08:09
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nodkz/d7caf219dcb6e65b94900a9f549bf9d0 to your computer and use it in GitHub Desktop.
Save nodkz/d7caf219dcb6e65b94900a9f549bf9d0 to your computer and use it in GitHub Desktop.
Sentry/raven manual config
import path from 'path';
import express from 'express';
import { merge } from 'lodash';
import graphqlHTTP from 'express-graphql';
import PrettyError from 'pretty-error';
import expressHttpProxy from 'express-http-proxy';
import bodyParser from 'body-parser';
import raven from 'raven';
import morgan from 'morgan';
import { PORT, PUBLIC_URL } from 'config';
import GraphQLSchema from 'schema';
import serverRenderHtml from './serverRenderHtml';
import getAuthRouter from 'app/auth/server';
import * as myJWT from 'app/auth/_jwt';
const pe = new PrettyError();
pe.skipNodeFiles();
pe.skipPackage('express', 'graphql');
raven.config(!__DEV__ && 'https://111:222@sentry.io/127680', {
release: __REVISION__,
tags: { git_commit: __GIT_COMMIT__ },
environment: process.env.NODE_ENV,
captureUnhandledRejections: true,
}).install();
const server = express();
server.use((req, res, next) => {
req.ravenPipe = [];
req.ravenAddContext = (context) => {
req.ravenPipe.push(context);
};
req.ravenGetContext = () => {
const context = {
user: {
id: req.cabinetId,
username: req.userEmail,
email: req.userEmail,
},
tags: {
...(req.headers['x-referrer-url'] && {
referrer: req.headers['x-referrer-url']
}),
...(req.admin && {
adminId: req.admin.id,
adminEmail: req.admin.email,
})
}
};
return merge(context, ...req.ravenPipe, raven.parsers.parseRequest(req));
};
next();
});
server.use(morgan(__DEV__ ? 'dev' : 'combined'));
server.get('/aws-health-check', (req, res) => {
res.send('Healthy!');
});
const graphQLMiddleware = graphqlHTTP(req => ({
schema: GraphQLSchema,
graphiql: true,
formatError: (error) => {
req.ravenAddContext({
extra: {
source: error.source && error.source.body,
positions: error.positions,
path: error.path,
},
});
if (error.path || error.name !== 'GraphQLError') {
req.ravenAddContext({ tags: { graphql: 'exec_error' } });
raven.captureException(error, req.ravenGetContext());
console.error(pe.render(error));
} else {
req.ravenAddContext({ tags: { graphql: 'wrong_query' } });
raven.captureMessage(`GraphQLWrongQuery: ${error.message}`, req.ravenGetContext());
console.error(pe.render(error.message));
}
return {
message: error.message,
stack: process.env.NODE_ENV === 'development' ? error.stack.split('\n') : null,
};
}
}));
server.use('/graphql',
myJWT.validateRequest,
graphQLMiddleware
);
server.get('/*', async (req, res, next) => {
serverRenderHtml(req, res, next);
});
// Error handling
server.use((err, req, res, next) => {
const status = err.status || err.statusCode || err.status_code || 500;
if (status < 500) return next(err);
res.sentry = raven.captureException(err, req.ravenGetContext());
return next(err);
});
server.use((err, req, res, next) => { // eslint-disable-line no-unused-vars
console.log(pe.render(err)); // eslint-disable-line no-console
res.status(err.status || 500);
res.setHeader('Content-Type', 'text/plain');
res.send(__DEV__ ? err.stack : 'Oops, internal server error');
});
server.listen(PORT, () => {
console.log(`The server is running at http://localhost:${PORT}/`);
});
@nodkz
Copy link
Author

nodkz commented Feb 7, 2017

In the req.ravenPipe I put all contexts. And only when error occurs call fat ravenGetContext() function. So it is a quite performant solution.

@nodkz
Copy link
Author

nodkz commented Feb 7, 2017

And got such errors attached to user request on server error:

screen shot 2017-02-07 at 14 11 57

screen shot 2017-02-07 at 14 12 14

@kaareal
Copy link

kaareal commented Feb 28, 2017

only problem i can find here, formatError is triggered multiple times.
e.g. for each edges, which can end up being quite a bit.
I am thinking about adding in a requestId which should allow me to group them together, a tiny bit ? but not 100% sure how sentry handles multiple errors per request. Perhaps the best solution is just to trigger a sentry new event per error?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment