Comments (6)
Got it, that makes sense.
Also, if the errorHandler middleware needs to be added after the routes, the documentation on the bugsnag website needs to be updated, as it doesn't reflect that: https://docs.bugsnag.com/platforms/nodejs/express/.
from bugsnag-node.
Hey @ajsharp. Can you provide an example of a route that is erroring in the small code snippet you provided please?
e.g. I tried this example and it worked as expected (creates a request tab in the dashboard)…
import express from 'express';
import bugsnag from 'bugsnag';
const app = express();
bugsnag.register('API_KEY', {autoNotify: true});
app.use(bugsnag.requestHandler);
// routes must go _after_ request handler
app.get('/', (req, res) => {
throw new Error('bad route')
});
// and _before_ error handler
app.use(bugsnag.errorHandler);
app.listen(3000);
from bugsnag-node.
Ok, so if I define a normal endpoint, it works as expected, and I get a request tab in the web UI. However, if it's an async
endpoint, I get no request tab:
Source:
app.get('/test', async (req, res) => {
throw new Error('test error');
});
Generated Javascript:
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
const express_1 = __importDefault(require("express"));
const bugsnag_1 = __importDefault(require("bugsnag"));
const app = express_1.default();
bugsnag_1.default.register('API_KEY', { autoNotify: true });
app.use(bugsnag_1.default.requestHandler);
app.get('/test', (req, res) => __awaiter(this, void 0, void 0, function* () {
throw new Error('test error');
}));
app.use(bugsnag_1.errorHandler);
app.listen(3000, () => {
console.log('running server on', PORT);
});
from bugsnag-node.
Hey @ajsharp. This happens because express routes are not "async/promise-aware". I'll try to explain…
When you create an async function () {}
, what it actually does it create a Promise
(as you can see from your generated code).
When express runs this route function which returns a Promise
, it doesn't do anything with either then eventual return value (from .then()
) or the error value (from .catch()
).
This means the error gets thrown outside of the context of the route, which is why you don't get any request metadata.
This post by Dom @ Readme goes into more detail about this if you want to understand more. But if you just want the solution, here is the example from the post applied to our small test case:
import express from 'express';
import bugsnag from 'bugsnag';
const app = express();
bugsnag.register('API_KEY', {autoNotify: true});
app.use(bugsnag.requestHandler);
// routes must go _after_ request handler
app.get('/', asyncWrap(async (req, res) => {
throw new Error('test error');
}));
function asyncWrap(fn) {
return (req, res, next) => {
fn(req, res, next).catch(next);
};
};
// and _before_ error handler
app.use(bugsnag.errorHandler);
app.listen(3000);
Basically what this does is catch any error in the route function and passes it on to the express error handler with .catch(next)
.
I hope this helps!
Cheers
from bugsnag-node.
@bengourley Awesome, thanks for wading through this, I'm very appreciative of this fix.
I'd love to see this become part of the busgnag express middleware. In my mind, this should be built in to bugsnag, because async
is a language feature, and as a user of the bugsnag library, I expect that would just handle async gracefully.
from bugsnag-node.
You're very welcome.
I would love to get this into bugsnag too but there isn't a lot we can do… if either of the following changes, things can work "out-of-the-box":
- Express routes/middleware support async functions/Promises. There is actually an open PR on the routing module that express uses internally, so this may land in the near future.
- Domains are updated to work with Promises. We use domains (although deprecated, they didn't replace it with anything yet!) to track the execution context across asynchronous calls, but this only works with callbacks, not Promises. This is highly unlikely to be fixed since the module is deprecated :(
In the future we will probably end up using the new async hooks module to track async execution contexts, but that is a little way off just now!
from bugsnag-node.
Related Issues (20)
- Can't disable logs HOT 3
- Duplicate Error Messages in Logs HOT 1
- Cannot find module backo HOT 2
- Missing functionality or documentation for app type feature HOT 1
- No way to filter authorization header HOT 1
- Middleware crashes with serverless-http HOT 2
- Interface ConfigurationOptions is missing newer Bugsnag options HOT 4
- Source map support HOT 2
- Bugsnag: Error: uv_signal_start EINVAL HOT 9
- not able to minify using create-react-app webpack configuration HOT 7
- bugsnag-node depends on "unlicensed" code HOT 2
- Please upgrade `request` dependency to ^2.87.0 HOT 2
- Dependency Bloat HOT 2
- Cannot read property 'startSession' of undefined on test environment HOT 2
- Sessions tracking against `production`, not configured releaseStage HOT 3
- Delivering exception to http://undefined:80undefined HOT 3
- How to add bugsnag middleware to apollo-server-lambda HOT 1
- Sending Strings to bugsnag.notify('String') are ignored HOT 2
- Bugsnag: Encountered an uncaught error, terminating. All uncaught errors force process.exit(), bad. HOT 11
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from bugsnag-node.