Why is Tomcat unable to show the actual stack trace?

后端 未结 3 1783
迷失自我
迷失自我 2020-12-18 09:36

Using GWT, I have deployed my server into Tomcat. This works fine, but when GWT throws an exception, a Popup shows the client the

相关标签:
3条回答
  • 2020-12-18 09:54

    This works as expected, because the optimaziation will remove the method and class names.

    You can compile as PRETTY or DETAILED, to get better readable Stacktraces.

    There is also the posibility to emulate Stacktraces.

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

    This is a bad idea for production use, because it will increase the size of your javascript.

    update: I see a Exception_FieldSerializer Exception.

    Do you try to serialize something, which is not serializable?

    Classes, without a default constructor are not serializable, Classes which aren't within your client or shared package. If you try to serialize an Exception this can be the problem.

    0 讨论(0)
  • 2020-12-18 09:58

    Why?

    As Christian Kuetbach said, this is the difference between running in DevMode (where your code executes in Java) and prod mode (where your code has been compiled to JavaScript and optimized, which includes renaming classes and methods).

    How do you fix this?

    You don't. Generally speaking, showing stack traces to your users is not a good idea. Much better is to log the exception by sending it to the server (e.g. use java.util.logging to log, along with the SimpleRemoteLogHandler to send the log to the server, where it'll be logged using java.util.logging).

    There are ways to deobfuscate the stack trace though, and the RemoteLoggingServiceImpl servlet can be configured to do it automatically.
    See http://code.google.com/p/google-web-toolkit/wiki/WebModeExceptions for the gory details.

    If you can't or don't want to use remote logging, then you can "manually" deobfuscate the stack trace: look at the file in WEB-INF/deploy (default location, can be changed by passing -deploy to the GWT compiler) corresponding with the permutation (same name as the *.cache.* file loaded by the browser), it'll tell you which Java method the Le method originates from.
    But you already have the source file name and line number, so you don't really need it, right?

    0 讨论(0)
  • 2020-12-18 10:20

    It's a bit difficult to find all the information in the GWT docs, which you need to setup de-obfuscated logging, so here's the short version:

    In your module file (.gwt.xml), add:

    <inherits name="com.google.gwt.logging.Logging"/>
    <set-property name="gwt.logging.simpleRemoteHandler" value="ENABLED" />
    <set-property name="compiler.stackMode" value="emulated" />
    <set-configuration-property name="compiler.emulatedStack.recordLineNumbers" 
         value="true" />
    

    On the client side, use something like

    import java.util.logging.Logger;
    
    private static Logger rootLogger = Logger.getLogger("");
    ...
    rootLogger.log(Level.SEVERE, "My message", e);
    

    You don't have to create a RemoteLoggingServiceAsync instance on the client side - it's used automatically by the logger, because we specified <set-property name="gwt.logging.simpleRemoteHandler" value="ENABLED" />.

    On the server side, configure the RemoteLoggingServiceImpl. You will have to tell it, where it finds the symbolMaps, which will be generated when compiling with the GWT compiler argument -extra /path/to/myExtraDir. I personally use the approach to override RemoteLoggingServiceImpl, to allow specifying the directory from web.xml's <init-param>s [*]

    package mypackage.server;
    
    public class ConfigurableRemoteLoggingServiceImpl extends RemoteLoggingServiceImpl {
    
      @Override
      public void init(final ServletConfig config) throws ServletException {
        super.init(config);
    
        final String symbolMapsDirectory = 
            config.getInitParameter("symbolMapsDirectory");
        setSymbolMapsDirectory(symbolMapsDirectory);
      }
    }
    

    In web.xml, register it like

    <servlet>
        <servlet-name>remoteLogging</servlet-name>
        <servlet-class>mypackage.server.ConfigurableRemoteLoggingServiceImpl</servlet-class>
    
      <init-param>
        <param-name>symbolMapsDirectory</param-name>
        <param-value>/path/to/myExtraDir/mymodulename/symbolMaps</param-value>
      </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>remoteLogging</servlet-name>
        <url-pattern>/mymodulename/remote_logging</url-pattern>
    </servlet-mapping>
    

    Replace /path/to/myExtraDir, mymodulename and mypackage with your own values, and don't forget to call the GWT compiler with the -extra argument (Note that you you don't have to use -style PRETTY or DETAILED, it also works with OBF). Keep all generated symbolMaps: Without them, deobfuscation will not work. As every new version gets a unique name automatically, you can collect them all in a safe central place when building.

    [*] And I really, really wonder, why RemoteLoggingServiceImpl doesn't implement that itself!

    0 讨论(0)
提交回复
热议问题