- Improve email notification cases for unexpected exceptions.

This commit is contained in:
Paulo Gustavo Veiga 2012-08-14 23:55:13 -03:00
parent 6d7c12ca60
commit 09ed4f68b7
9 changed files with 113 additions and 50 deletions

View File

@ -6,17 +6,17 @@
obj - object to inspect obj - object to inspect
*/ */
$defined = function(obj) { $defined = function (obj) {
return (obj != undefined); return (obj != undefined);
}; };
$assert = function(assert, message) { $assert = function (assert, message) {
if (!$defined(assert) || !assert) { if (!$defined(assert) || !assert) {
var stack; var stack;
try { try {
null.eval(); null.eval();
} catch(e) { } catch (e) {
stack = e; stack = e;
} }
console.log(message + "," + stack); console.log(message + "," + stack);
@ -25,7 +25,7 @@ $assert = function(assert, message) {
} }
}; };
Math.sign = function(value) { Math.sign = function (value) {
return (value >= 0) ? 1 : -1; return (value >= 0) ? 1 : -1;
}; };
@ -34,7 +34,7 @@ function stackTrace() {
var isCallstackPopulated = false; var isCallstackPopulated = false;
try { try {
null.eval(); null.eval();
} catch(e) { } catch (e) {
if (e.stack) { //Firefox and Chrome... if (e.stack) { //Firefox and Chrome...
result = e.stack; result = e.stack;
isCallstackPopulated = true; isCallstackPopulated = true;
@ -60,7 +60,7 @@ function stackTrace() {
/*! @source https://gist.github.com/1129031 */ /*! @source https://gist.github.com/1129031 */
/*global document, DOMParser*/ /*global document, DOMParser*/
(function(DOMParser) { (function (DOMParser) {
"use strict"; "use strict";
var DOMParser_proto = DOMParser.prototype , real_parseFromString = DOMParser_proto.parseFromString; var DOMParser_proto = DOMParser.prototype , real_parseFromString = DOMParser_proto.parseFromString;
@ -75,7 +75,7 @@ function stackTrace() {
} catch (ex) { } catch (ex) {
} }
DOMParser_proto.parseFromString = function(markup, type) { DOMParser_proto.parseFromString = function (markup, type) {
if (/^\s*text\/html\s*(?:;|$)/i.test(type)) { if (/^\s*text\/html\s*(?:;|$)/i.test(type)) {
var var
doc = document.implementation.createHTMLDocument("") doc = document.implementation.createHTMLDocument("")
@ -101,9 +101,9 @@ function stackTrace() {
}(DOMParser)); }(DOMParser));
// Support for Windows ... // Support for Windows ...
if(!window.console){ if (!window.console) {
console = { console = {
log: function(e){ log:function (e) {
} }
}; };

View File

@ -165,7 +165,7 @@ final public class NotificationService {
final String errorReporterEmail = mailer.getErrorReporterEmail(); final String errorReporterEmail = mailer.getErrorReporterEmail();
if (errorReporterEmail != null && !errorReporterEmail.isEmpty()) { if (errorReporterEmail != null && !errorReporterEmail.isEmpty()) {
mailer.sendEmail(mailer.getServerSenderEmail(), errorReporterEmail, "[WiseMapping] Editor error from " + user.getEmail(), model, mailer.sendEmail(mailer.getServerSenderEmail(), errorReporterEmail, "[WiseMapping] Editor error from " + user.getEmail(), model,
"editorErrorReport.vm"); "errorNotification.vm");
} }
} catch (Exception e) { } catch (Exception e) {
handleException(e); handleException(e);
@ -183,7 +183,24 @@ final public class NotificationService {
final String errorReporterEmail = mailer.getErrorReporterEmail(); final String errorReporterEmail = mailer.getErrorReporterEmail();
if (errorReporterEmail != null && !errorReporterEmail.isEmpty()) { if (errorReporterEmail != null && !errorReporterEmail.isEmpty()) {
mailer.sendEmail(mailer.getServerSenderEmail(), errorReporterEmail, "[WiseMapping] Export error from " + user.getEmail(), model, mailer.sendEmail(mailer.getServerSenderEmail(), errorReporterEmail, "[WiseMapping] Export error from " + user.getEmail(), model,
"editorErrorReport.vm"); "errorNotification.vm");
}
} catch (Exception e) {
handleException(e);
}
}
public void reportUnexpectedError(@NotNull Throwable exception, @Nullable User user, @NotNull String userAgent) {
try {
final Map<String, Object> model = new HashMap<String, Object>();
model.put("user", user);
model.put("errorMsg", stackTraceToString(exception));
model.put("userAgent", userAgent);
final String errorReporterEmail = mailer.getErrorReporterEmail();
if (errorReporterEmail != null && !errorReporterEmail.isEmpty()) {
mailer.sendEmail(mailer.getServerSenderEmail(), errorReporterEmail, "[WiseMapping] Unexpected error from " + (user != null ? user.getEmail() : "anonymous"), model,
"errorNotification.vm");
} }
} catch (Exception e) { } catch (Exception e) {
handleException(e); handleException(e);

View File

@ -0,0 +1,43 @@
package com.wisemapping.mail;
import com.wisemapping.model.User;
import com.wisemapping.security.Utils;
import org.apache.log4j.Logger;
import org.jetbrains.annotations.NotNull;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashSet;
import java.util.Set;
public class NotifyingExceptionResolver extends SimpleMappingExceptionResolver {
final private Logger logger = Logger.getLogger("com.wisemapping");
private Set<String> exclude = new HashSet<String>();
private NotificationService notificationService;
@Override
protected ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
if (!exclude.contains(ex.getClass().getName())) {
logger.error("An Exception has occurred in the application", ex);
sendNotification(ex, request);
}
return super.doResolveException(request, response, handler, ex);
}
private void sendNotification(@NotNull Exception ex, @NotNull HttpServletRequest request) {
final User user = Utils.getUser();
notificationService.reportUnexpectedError(ex, user, request.getHeader("User-Agent"));
}
public void setExclude(final Set<String> exclude) {
this.exclude = exclude;
}
public void setNotificationService(NotificationService notificationService) {
this.notificationService = notificationService;
}
}

View File

@ -18,7 +18,10 @@
package com.wisemapping.rest; package com.wisemapping.rest;
import com.wisemapping.mail.NotificationService;
import com.wisemapping.model.User;
import com.wisemapping.rest.model.RestErrors; import com.wisemapping.rest.model.RestErrors;
import com.wisemapping.security.Utils;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Qualifier;
@ -34,6 +37,9 @@ public class BaseController {
@Autowired @Autowired
private ResourceBundleMessageSource messageSource; private ResourceBundleMessageSource messageSource;
@Autowired
private NotificationService notificationService;
@ExceptionHandler(IllegalArgumentException.class) @ExceptionHandler(IllegalArgumentException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST) @ResponseStatus(HttpStatus.BAD_REQUEST)
@ResponseBody @ResponseBody
@ -46,14 +52,15 @@ public class BaseController {
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ResponseBody @ResponseBody
public String handleServerErrors(@NotNull Exception ex) { public String handleServerErrors(@NotNull Exception ex) {
ex.printStackTrace(); final User user = Utils.getUser();
notificationService.reportUnexpectedError(ex, user, "unknown browser");
return ex.getMessage(); return ex.getMessage();
} }
@ExceptionHandler(ValidationException.class) @ExceptionHandler(ValidationException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST) @ResponseStatus(HttpStatus.BAD_REQUEST)
public RestErrors handleValidationErrors(@NotNull ValidationException ex) { public RestErrors handleValidationErrors(@NotNull ValidationException ex) {
return new RestErrors(ex.getErrors(),messageSource); return new RestErrors(ex.getErrors(), messageSource);
} }

View File

@ -4,16 +4,23 @@
<li>User Name: ${user.fullName}</li> <li>User Name: ${user.fullName}</li>
<li>Email: ${user.email}</li> <li>Email: ${user.email}</li>
<li>User Agent: ${userAgent}</li> <li>User Agent: ${userAgent}</li>
<li>Mindmap Id: ${mapId}</li> #if($mapId)
<li>Mindmap Title: ${mapTitle}</li> <li>Mindmap Id: ${mapId}</li>
#end
#if($mapTitle)
<li>Mindmap Title: ${mapTitle}</li>
#end
</ul> </ul>
<pre style="border:1px dashed #a9a9a9"> <pre style="border:1px dashed #a9a9a9">
${errorMsg} ${errorMsg}
</pre> </pre>
#if($mapXML)
<pre style="border:1px dashed #a9a9a9"> <pre style="border:1px dashed #a9a9a9">
${mapXML} ${mapXML}
</pre> </pre>
#end
</body> </body>
</html> </html>

View File

@ -58,7 +58,7 @@ mail.serverSendEmail=root@localhost
mail.supportEmail=root@localhost mail.supportEmail=root@localhost
# Optional: Unexpected errors will be reported to this address. # Optional: Unexpected errors will be reported to this address.
mail.errorReporterEmail= mail.errorReporterEmail=support@wisemapping.com
################################################################################## ##################################################################################
# Users Registration Configuration # Users Registration Configuration

View File

@ -50,11 +50,25 @@
<definition name="unexpectedError" extends="errorTemplate"> <definition name="unexpectedError" extends="errorTemplate">
<put-attribute name="title" value="UNEXPECTED_ERROR"/> <put-attribute name="title" value="UNEXPECTED_ERROR"/>
<put-attribute name="details" value="UNEXPECTED_ERROR_DETAILS"/> <put-attribute name="details" value="UNEXPECTED_ERROR_DETAILS"/>
<put-attribute name="logError" value="true"/>
</definition> </definition>
<definition name="securityError" extends="errorTemplate"> <definition name="securityError" extends="errorTemplate">
<put-attribute name="title" value="NO_ENOUGH_PERMISSIONS"/> <put-attribute name="title" value="NO_ENOUGH_PERMISSIONS"/>
<put-attribute name="details" value="NO_ENOUGH_PERMISSIONS_DETAILS"/> <put-attribute name="details" value="NO_ENOUGH_PERMISSIONS_DETAILS"/>
<put-attribute name="logError" value="false"/>
</definition>
<definition name="forgotPasswordError" extends="errorTemplate">
<put-attribute name="title" value="INVALID_EMAIL_ERROR"/>
<put-attribute name="body" value="/jsp/userForgotPasswordError.jsp"/>
<put-attribute name="logError" value="false"/>
</definition>
<definition name="forgotPasswordSuccess" extends="errorTemplate">
<put-attribute name="title" value="FORGOT_PASSWORD"/>
<put-attribute name="body" value="/jsp/userForgotPasswordSuccess.jsp"/>
<put-attribute name="logError" value="false"/>
</definition> </definition>
<!-- Main Pages --> <!-- Main Pages -->
@ -68,16 +82,6 @@
<put-attribute name="body" value="/jsp/termsOfUse.jsp"/> <put-attribute name="body" value="/jsp/termsOfUse.jsp"/>
</definition> </definition>
<definition name="forgotPasswordError" extends="errorTemplate">
<put-attribute name="title" value="INVALID_EMAIL_ERROR"/>
<put-attribute name="body" value="/jsp/userForgotPasswordError.jsp"/>
</definition>
<definition name="forgotPasswordSuccess" extends="errorTemplate">
<put-attribute name="title" value="FORGOT_PASSWORD"/>
<put-attribute name="body" value="/jsp/userForgotPasswordSuccess.jsp"/>
</definition>
<definition name="forgotPassword" extends="pageTemplate"> <definition name="forgotPassword" extends="pageTemplate">
<put-attribute name="title" value="FORGOT_PASSWORD"/> <put-attribute name="title" value="FORGOT_PASSWORD"/>
<put-attribute name="body" value="/jsp/userForgotPassword.jsp"/> <put-attribute name="body" value="/jsp/userForgotPassword.jsp"/>

View File

@ -54,7 +54,7 @@
<bean id="exceptionHandlerResolver" <bean id="exceptionHandlerResolver"
class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> class="com.wisemapping.mail.NotifyingExceptionResolver">
<property name="defaultStatusCode" value="500"/> <property name="defaultStatusCode" value="500"/>
<property name="defaultErrorView" value="unexpectedError"/> <property name="defaultErrorView" value="unexpectedError"/>
<property name="exceptionMappings"> <property name="exceptionMappings">
@ -65,6 +65,14 @@
<prop key="java.lang.reflect.UndeclaredThrowableException">securityError</prop> <prop key="java.lang.reflect.UndeclaredThrowableException">securityError</prop>
</props> </props>
</property> </property>
<property name="exclude">
<set>
<value>java.lang.reflect.UndeclaredThrowableException</value>
<value>com.wisemapping.exceptions.GoogleChromeFrameRequiredException</value>
<value>com.wisemapping.exceptions.UnsupportedBrowserException</value>
</set>
</property>
<property name="notificationService" ref="notificationService"/>
</bean> </bean>
<bean id="viewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver"> <bean id="viewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">

View File

@ -1,14 +1,8 @@
<!DOCTYPE HTML> <!DOCTYPE HTML>
<%@ page import="org.apache.log4j.Logger" %>
<%@ page import="com.wisemapping.security.Utils" %>
<%@ page import="com.wisemapping.model.User" %>
<%@ page autoFlush="true" buffer="none" %> <%@ page autoFlush="true" buffer="none" %>
<%@ include file="/jsp/init.jsp" %> <%@ include file="/jsp/init.jsp" %>
<%!
final Logger logger = Logger.getLogger("com.wisemapping");
%>
<h2> <h2>
<spring:message code="${requestScope.title}"/> <spring:message code="${requestScope.title}"/>
</h2> </h2>
@ -16,21 +10,4 @@
<strong> <strong>
<spring:message code="${requestScope.details}"/> <spring:message code="${requestScope.details}"/>
</strong> </strong>
<!--
<%
final Throwable exception = (Throwable) request.getAttribute("exception");
if (exception != null) {
exception.printStackTrace(response.getWriter());
String usrMail = "anonymous";
final User user = Utils.getUser(false);
if (user != null) {
usrMail = user.getEmail();
}
logger.error("Unexpected error on user '" + usrMail + " ':", exception);
}
%>
-->