New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add global error/exception handler #174
Comments
related to aurelia/router#2 |
Errors are going through the logger. To route them elsewhere, you can attach a custom log appender. |
@EisenbergEffect I think using a custom log appender is fine. However, it does not report all errors (see examples below). I think that all Aurelia components have to make sure they send errors to the logger if the logger is the way to handle errors. What do you think? Example 1I have a view that does that:
and when
A workaround for this one is to handle it via Example 2I have a view that does this:
If the promise is rejected, the custom logger is not called. I see in the console:
I don't know if a workaround exists for this case. It seems like |
Update to my previous post. Another variation of case 2 is with a failed XHR Request, I was able to implement a workaround using https://github.com/slorber/ajax-interceptor which looks like this.
I still have not found a workaround for Promises. Until I get Aurelia's team's point of view on the issue, I keep the two workarounds inside my custom log appender. The full code is this:
which is wired-up this way:
I have another component that subscribes to the |
@sylvain-hamel Great workaround setup. I've also successfully implemented your workaround. I currently have an existing application in angular, and during the bootstrap of Aurelia, I'm loading a main.js with a configure function. Is there a way to get at the event aggregator when Aurelia starts and subscribe to the event there? How would I load a viewless module, say a simple log implementation, for the uncaught exceptions? |
Get EventAggregator from the container:
|
I figured out how to handle unhanded promise rejections:
The full code is now:
According to the core-js doc, you also need this in
|
Is there a way to just let the error bubble up so code I have in the head of index.html page catches it: eg
That's a trivial example. In reality, I have a custom logger in there that deals with posting back to the server. I know I could probably pull all of that code into a custom appender - like solution above - but I don't really want to have to do that. A simple way to turn off aurelia logging altogether would be good, or at least let errors bubble up and not be swallowed.
Stops on debugger line OK - but the new thrown error does not get caught by the page. Is there an easy way around that? |
@stevies no it's not possible because unhandled ajax errors and unhandled promise rejections don't end up in I created this issue because I think all Aurelia applications should benefit from a simple and reliable global error handling mechanism and I hope the Aurelia team integrates this into the framework. |
We could add something like this through our pal abstraction. @sylvain-hamel Would you be willing to put together a prototype? |
@EisenbergEffect would you be ok with adding a dependency on |
No 3rd party dependencies please. Those constantly cause us issues. Also, the AjaxInterceptor isn't going to work with Fetch I imagine, which is our preferred mechanism for HTTP. |
You are right. I feel like the core team is in a better position to find the proper implementation and all the right hooks. My current handler does not work if the error occurs too early and does not cover all error types yet. I think it's important that the global error handling mechanism kicks in as early as possible because errors during initial load are common. Our current app (that we converting to Aurelia) can even handle script loading errors (using I can keep sharing code as I find ways to handle things but I think you guys should write the final code. |
Please keep the ideas coming :) |
1 similar comment
Please keep the ideas coming :) |
My usage of the AjaxInterceptor breaks in typescript, so I manually created a definitions file for anyone who is interested until the official support without the 3rd party becomes available: ./typings/ajax-interceptor.d.ts
|
Another example of an uncaught error in the latest release.
The error is captured and discarded. Nothing in the console or dev tools. Nothing to the Aurelia log either. |
@sensedeep I just put an error in the |
The difference may be I'm using async functions with the Babel runtime. The full code is:
I've singled stepped through the code and if I uncomment the "throw", the Babel runtime gobbles the event as it unwinds the async promises. When it returns to evaluate in aurelia-binding, the exception is gone. I can do a try/catch in login(), but I'd like to have a global capture of such exceptions as well. Any ideas? Is there a recommended pattern for exceptions with async functions? |
Ok, this is a specific problem with the fact that the method is an async method. |
There are some discussions in whatwg here. Seems like the common thing for vendors would be to call |
Right. Doesn't Bluebird handle this automatically? Perhaps the best solution would be to just use that? |
Yeah there are a couple of different approaches for bluebird depending on if it's in node or browser but there seems to be events for this. Haven't used that myself though. |
Async functions are really, REALLY elegant. I'm not using bluebird and running in the browser ... chrome only at this point. To handle this, I think the framework would have to test if a rejected promise is returned. That is what an async function that throws will do. Ideally, you want the Aurelia logging to capture it at the actual function invoked and not at the bubble up point. Much better for debugging. |
Closing this as its mostly specific to how the end user is handling promises and ajax. |
@sylvain-hamel, thanks for sharing Your solution. I have a suggestion for imprvemenHanding errors from Promises used by router (Promises returned by ViewHooks: canActivate, activate, canDeactivate, deactivate) isn't covered by Your solution - I solved it as follows: constructor(eventAggregator: EventAggregator) {
eventAggregator.subscribe("router:navigation:error", (data: RouterNavigationErrorEventData, eventName: string) => {
const error: Error = data.result.output; // what was rejected - technically it could be smth other than Error, but that would be reported by bluebird as bad practice anyway
// do smth with the error
});
} where RouterNavigationErrorEventData is alias for type RouterNavigationErrorEventData = {
instruction: NavigationInstruction;
result: PipelineResult;
} |
@atsu85 Thanks for your contribution! I'll add this to my project. |
With all due respect, I do not understand why this issue was closed. |
What is a correct way to global error handling? I have made my own custom logger from: https://stackoverflow.com/questions/37791068/send-aurelia-error-logs-to-server-and-notify-the-user But when I throw exception in any part of application, in example: My custom logger don't catch it. |
@zchpit see |
@antonmos I have problem with adding: Cannot find module 'ajax-interceptor'. I'm using Visual Studio 2015 Update3. What I'm doing wrong? Or what I need to do, to load that file manualy (in example copy-paste https://github.com/slorber/ajax-interceptor/blob/master/index.js into my solution and load it directly). |
Another question: |
We have our own set of polyfills that are the minimal required set. If you prefer core-js, you can install that instead. It isn't required. |
@EisenbergEffect I don't have any preferences. I want to have one global custom error handler, that will log all my unexpected errors into my server. At this moment, I don't have it. import 'fetch';//IE Polyfill @Inject(HttpClient,EventAggregator)
} |
@EisenbergEffect Am I understanding it correctly, that to add global logging for async event handlers, I need to use a Promise library? Note - I'm using Typescript compiling to es6 - I don't know if my situation/solution applies in all cases. I need global error logging and the only way I have found that allows me to capture errors in async is to override the generated var __awaiter = (thisArg, _arguments, P, generator) => {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) {
// Add loggin here
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());
});
};
export class MyViewModel {
async buttonClicked() {
await doStuff();
throw new Error('Oh noes!!!');
}
} If there is a way to do this automatically for all view models, I would be interested to know about it, but it's still not great to replace generated code that could change with future versions of typescript. |
Check this SO article out and see if it helps: https://stackoverflow.com/questions/28001722/how-to-catch-uncaught-exception-in-promise |
@EisenbergEffect It does not. While |
This might be something you want to bring up with the TypeScript team, particularly if it's related to the code they are generating. |
Aurelia should route any uncaught exception or any unhandled rejected promise coming from expressions or from methods called by the framework itself (attached, activate, constructor (DI)) to a global exception handling service in order to let application developers to log the errors.
This would be equivalent to Angular’s
$exceptionHandler
service.This serves two purposes:
alert
whenever there is an uncaught exception. No need to constantly monitor the console window.The text was updated successfully, but these errors were encountered: