Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best Practices for GWT services exceptions logging

I decided to add logging system to my gwt service layer. First of all I wanted to log all exceptions that are thrown from that layer. I had an object similar to Spring's ServletDispatcher, which calls other services. I thought I could add logging there, but I realized that GWT services wraps checked exceptions in ServletResponse and unchecked into UnexpectedException.

Can anybody share his experience with that problem? What is the best way to log checked and unchecked exceptions for all GWT Services.


I found solution which suggests to extend RemoteServiceServlet and override default exceptions flow. But I find this solution too time-consuming. Does anybode know any easier variant?

like image 655
Zalivaka Avatar asked Nov 16 '10 10:11

Zalivaka


3 Answers

On the server side, we have a subclass of RemoteServiceServlet that we use for all service implementations. You mention that it seems time-consuming, but here's what the code looks like. You do it once and you're done.

@Override
protected void doUnexpectedFailure(Throwable t) {
    t.printStackTrace(System.err);
    super.doUnexpectedFailure(t);
}

Note: We don't actually send it to System.err and you probably shouldn't either, but you get the idea.

On the client side, we use a subclass of AsyncCallback called AsyncSuccessCallback. It handles the onFailure case uniformly for most of our RPC calls. Most of our callback code can deal with the onSuccess case knowing that onFailure is handled. It also provides a single place to change this implementation later.

public abstract class AsyncSuccessCallback<T> implements AsyncCallback<T> {

    public void onFailure(Throwable t) {
        handleException(t);
    }

    protected void handleException(Throwable t) {
         Window.alert(t.getMessage());
    }

}

Note: We don't actually use Window.alert, but again, you get the idea. What we do in this case is display a GWT DialogBox that displays a form that does a POST to a different server that accepts error reports. The form allows the user to type a description of what they were doing when the error occurred.

On the client side, if you want to get the stack trace, you need to write a little extra code:

// for lineEnding, use "<br>" for HTML, "\n" for text
public static final String getStackTrace(Throwable t, String lineEnding) {
    Object[] stackTrace = t.getStackTrace();
    if (stackTrace != null) {
        StringBuilder output = new StringBuilder();
        for (Object line : stackTrace) {
            output.append(line);
            output.append(lineEnding);
        }
        return output.toString();
    } else {
        return "[stack unavailable]";
    }
}
like image 78
andykellr Avatar answered Sep 21 '22 05:09

andykellr


Which exceptions do you want to log? Client side or server side? We have a big enterprise application with gwt. We use the MVP pattern on the client and all the request to the server are done using a generic RPCservice class. For example saveUserService = new remoteService();

on the server side we process the SaveUserRequest and prepare SaveUserResponse using the command pattern. All exceptions are treated there, apart from the ClientWarningException that are left to propagate till the client where we display a nice message to the user.

This is maybe a bit verbose, but it scaled well on a big app with about 100k loc.

like image 36
Uberto Avatar answered Sep 24 '22 05:09

Uberto


Use gwt-dispatch. Logging can be embedded in the standard dispatch service, as shown in the following sample, which I lifted from the gwt-dispatch Getting Started page.

public class SimpleDispatchServlet extends RemoteServiceServlet 
       implements StandardDispatchService {

    private Dispatch dispatch;

    public SimpleDispatchServlet() {
        InstanceActionHandlerRegistry registry = 
          new DefaultActionHandlerRegistry();
        registry.addHandler(new IncrementCounterHandler());
        dispatch = new SimpleDispatch(registry);
    }

    public Result execute(Action<?> action) throws DispatchException {
        try {
            return dispatch.execute(action);
        } catch (RuntimeException e) {
            log("Exception while executing " + action.getClass().getName() 
                + ": " + e.getMessage(), e );
            throw e;
        }
    }
}
like image 26
David Avatar answered Sep 23 '22 05:09

David