3

Till May this year, I was using GWT 2.5.1 and simple DevMode and was able to send obfuscated exceptions with stack traces to server and deobfuscate them there using symbol maps as per this brilliant article. This helped me a lot.

Since June I successfully switched to GWT 2.6.1 and SuperDevMode which provides quite decent experience comparing to simple DevMode and is simpler to use.

However, I noticed that my stack traces are not deobfuscated correctly on the server no more. I keep getting obfuscated stack traces even after deobfuscation.

Following is the related contents of *.gwt.xml file:

<module rename-to="somemodule">

    <!-- inherits, stylesheet, entry-point, source elements are going here -->

    <add-linker name="xsiframe" />

    <extend-property name="locale" values="uk" />
    <set-property-fallback name="locale" value="uk" />

    <set-property name="compiler.stackMode" value="emulated" />
    <set-configuration-property name="compiler.emulatedStack.recordLineNumbers" value="true" />

    <set-property name="gwt.logging.logLevel" value="INFO" />            
    <set-property name="gwt.logging.enabled" value="TRUE" />  
    <set-property name="gwt.logging.developmentModeHandler" value="ENABLED" />    
    <set-property name="gwt.logging.systemHandler" value="DISABLED" />  
    <set-property name="gwt.logging.popupHandler" value="DISABLED" />  
    <set-property name="gwt.logging.consoleHandler" value="ENABLED" />   
    <set-property name="gwt.logging.firebugHandler" value="ENABLED" />
</module>

Following is server-side code that handles client side exceptions:

import static com.google.gwt.user.client.rpc.RpcRequestBuilder.STRONG_NAME_HEADER;
import com.google.gwt.core.client.impl.SerializableThrowable;
import com.google.gwt.logging.server.StackTraceDeobfuscator;

// ....

@Override
public void logClientException(final SerializableThrowable ex, final String userAgent, final String platform, final String moduleName) {
    final HttpServletRequest request = getThreadLocalRequest();

    final String symbolMapsDirectory = "webapps/" + getTomcatWebappFolder(request.getServletContext()) + "/WEB-INF/deploy/" + moduleName + "/symbolMaps";
    final String permutationName = request.getHeader(STRONG_NAME_HEADER);
    final Throwable original = new StackTraceDeobfuscator(symbolMapsDirectory).deobfuscateThrowable(ex.getThrowable(), permutationName);

    logClientException(original, userAgent, platform);
}

Did I omit something when transferred from GWT 2.5.1 to GWT 2.6.1?

Thanks a lot in advance for any help!

Yuriy Nakonechnyy
  • 3,742
  • 4
  • 29
  • 41

2 Answers2

3

This is an unfortunate known issue. See here and here.

The problem is that with each recompile an entire new incremental directory tree gets created (see the compile-1, compile-2 etc subdirs). Hence the runnning application server (the one that hosts your servlets) will not be able to pick up the right compile-x/extras/<module-name>/symbolMaps directory to use with a call to setSymbolMapsDirectory (as @Vadim pointed out). And of course, is a quite a PITA to copy such symbolMaps in the expected directory each time you recompile (and I'm not even sure if it will work wrt permutation names).

This was the same for GWT-RPC at the beginning of the SuperDevMode era, but with the difference that the codeserver (SDM) now exposes all those *.gwt.rpc output files directly and if the gwt.codeserver.port java flag is used, your servlets will download policy files automatically (only in localhost, and with GTW >= 2.5.1).

Anyway, the point is to let the codeserver expose/serve also the symbolMaps files (which is already somehow does, by hitting http://localhost:9876/sourcemaps/<module-name>/gwtSourceMap.json but only for sourcemaps and not in a StackTraceCreator comprehensible way) in some way, as descibed in the first issue.

Fortunately stacktraces are not that bad to live with on development.

Andrea Boscolo
  • 3,038
  • 1
  • 16
  • 21
  • Thanks for the answer! Basically I came to same conclusion myself a day ago but didn't have a chance to write similar answer, hence accepting yours! Yes, I agree that during development it's not a huge problem. Let's hope GWT team will solve this in the nearest future. – Yuriy Nakonechnyy Jul 10 '14 at 14:14
2

Just yesterday I had a similar problem. With one exception - we use a build-in deobfuscation functionality in GWT logging. So my problem was in incorrect symbolMapsDirectory path. The bad news here is that GWT won't tell you if your symbolMaps path is incorrect:

com.google.gwt.core.server.StackTraceDeobfuscator#loadSymbolMap:

try {
  BufferedReader bin = ...
} catch (IOException e) {
  // If the symbol map isn't found or there's an I/O error reading the file, the returned
  // mapping may contain some or all empty data (see below).
}

So our working solution looks like this:

setSymbolMapsDirectory(getServletContext().getRealPath("/WEB-INF/deploy/" + moduleName + "/symbolMaps/"));
Vadim
  • 1,125
  • 8
  • 18
  • Thanks for your answer! But did you try to use this deobfuscator in `SuperDevMode` (not plain `DevMode` or production mode)? Because in `DevMode` or production mode everything works fine, the only problem is with `SuperDevMode`. – Yuriy Nakonechnyy Jul 09 '14 at 08:36
  • No, I didn't try. In SDM you works with symbolMap that is hosted by the localhost:9876. But GWT module sends request to /remote_logger to your real application server. If you don't put symbolMap from localhost:9876 to your real application server the /remote_logger will not be able to deobfustace stacktraces because of missing symbolMap. I think this is the problem. – Vadim Jul 17 '14 at 05:06
  • Yes, you're right - I've also came to this conclusion. Let's wait till GWT team release a solution for this :) – Yuriy Nakonechnyy Jul 17 '14 at 08:53