|
Debugging Orion Applications
This document will show you a few tricks that might help you debug your J2EE applications.
1 Introduction
In a modern application server, a great number of tasks are being made for you in an automatic way. This often enables you to increase your own efficiency and helps you write better code and focus on the problem you are solving rather than on a problem that has been solved many times before. In short, it helps you move to a higher level of abstraction when programming.
Now this might sound like it's just fine and dandy, but of course this can also make a few things more difficult. When things are being made by the application server and are out of your control, it's easy to feel powerless when the application server gives you an error. You realize that it's probably something you've done wrong, maybe a configuration error, maybe you have misunderstood how something is supposed to work or maybe you just made some mistake somewhere. In some cases it might also mean that you are not the one that have committed an error but it could actually be being the application server or even the JVM that is in error. Reaching a conclusion on what really is the source of the error can be an enormous task. You read your code to make sure it's correct and you read the configuration and the specification to make sure everything is fine. You might also step through your code in a debugger to see what happens.
A debugger might often not give you enough information though. You will easily find exactly where the problem happens, but it might be very difficult to really find out why it happens there.
This document aim to help you in this task. It shows how you can make Orion give verbose information on what exactly it is doing and how this information can be interpreted. It also explains how to interpret different error messages and how you can use debuggers in a few popular IDE's to help your task.
2 The different logs
A log file is a place where certain events are stored for future reference. In an application server with many deployed applications of different kinds a great deal of events are happening all the time. Because of this there is a need to use more than one log file. Orion uses 5 different kind of log files:
Application log
Server log
Web access log
RMI log
JMS log
2.1 The Web Access log
The Web Access log is a somewhat odd fellow among log files. Its purpose is not mainly to help finding errors but to find out what activity happens on your web site. Since this document is not about how to analyze the traffic on your web site but about debugging your applications, we will not describe how to use this file here. A full description can be found
here.
2.2 The Application log
This is the most important log file for most developers. Actually it is not one log file but one per application. It is normally located in application-deployments/<applicationname>/application.log but this location can be changed in orion-application.xml and of course the deployment directory can be changed in server.xml.
The application log contain all events that are connected to a certain application. A typical example might look like this:
2000-09-11 17:01 Started 2000-09-11 17:01 Auto-deploying shop-ejb... done. 2000-09-11 17:01 shop-web: 1.3.3 Started 2000-09-11 17:01 shop-wap: 1.3.3 Started 2000-09-11 17:02 shop-web: Servlet error java.lang.SecurityException: JspFactory already set at javax.servlet.jsp.JspFactory.setDefaultFactory(JspFactory.java) at /shop/listProducts.jsp._jspService(/shop/listProducts.jsp.java:47) (JSP page line 14) 2000-09-11 17:03 Stopped
|
Listing 1: Sample Application log
-
The first line means that the application was started at the specified time.
-
The second lines tells us that an EJB module was successfully deployed.
-
The third and fourth lines show that the application contained two web modules that were started, shop-web and shop-wap.
-
The fifth line says that a Servlet error occured in the module shop-web. After that comes a stack trace, which can look somewhat different for different exceptions and errors.
-
In this case the next line tells us that the nature of the problem is that we are trying to set the JspFactory when it is already set, which causes a SecurityException.
-
We see that the problem occurred in a call to setDefaultFactory() in the class javax.servlet.jsp.JspFactory.
-
That method was in turn being called bt the jsp page /shop/listProducts.jsp and the JSP line number for the line that called setDefaultFactory() is 14.
2.3
The Server log
The server log is where events that are not associated to a certain application or to a certain subsytem show up. It logs:
Server startup
Server shutdown
Internal server errors
The nature of the errors that show up here can be pretty difficult to debug, and may have cryptical error messages. It is usually a sign of either bad error reporting from Orion (the error should have been printed in a nicer way in some other log, because they are a programmer error), or a sign of a bug in Orion. Anyway, the structure of the file looks like this:
2000-09-10 12:12 1.3.3 Started 2000-09-10 12:14 Internal error in HttpServer java.lang.NullPointerException at java.io.File.(File.java:181) at com.evermind.server.http.HttpApplication.v5(JAX) at com.evermind.server.http.HttpApplication.ty(JAX) at com.evermind.server.http.d9.r5(JAX) at com.evermind.server.http.d9.r4(JAX) at com.evermind.util.f.run(JAX) 2000-09-10 12:15 1.3.3 Stopped
|
Listing 2: Sample Server log
-
The first line tells us when the server was started and what version was started (in this case 1.3.3)
-
The second line tells us that an error occured at the specified time. In this case it's an Internal Error in the Http Server.
-
Following this is a stack trace of the exception. In this case all useful information we can get out of this is that an invalid reference has been used (also called a NullPointer). However, the NullPointerException has occured in an internal server class. In this case it was actually a programmer error that prompted this report, and the error in Orion was to not report the error correctly. If any bug reports are made based on an error here, this stack trace should be submitted with the bug since it can sometimes be useful when correcting the bug.
-
The last line tells us that the server (with the version 1.3.3) was stopped at the specified time.
2.4
The RMI log and the JMS log
The RMI log is (not surprisingly) logging RMI events and errors. It follows the common log file layout that we have seen described when talking about the server log and application log. The JMS log works in the same way, but for JMS events and errors. The most common kinds of errors for these logs are related to failed marshalling of object.
3 The modes for debugging certain aspects
It is often easy to track down a few parts of the problem. It is normally simple to find what application it happens to and it might be able to understand which sub-system the problem occurs in. After having looked at the log files and gone through your code thoroughly you might be able to solve most of the problems. However, there are cases when this is not enough and you want the ability to dig down deeper. You want to find out exactly what Orion is doing and when it is doing it. Since you have usually tracked down the problem to a certain sub-system, for example transactions or clustering, you want to get the information about what is happening in exactly the sub-system that the error occurs in.
For this purpose Orion provides a number of system properties, that you either define in a properties file called orion.properties or by giving them to Orion on the command line using the -D switch with the java executable (java -Dproperty=value -jar orion.jar). This section describes the big number of debug modes that you can enable for Orion.
Before using this I have to a warning that these properties are sometimes added for testing very specific things related to the internals of Orion and some might disappear at any time as the internals change. Also some settings may not ever be useful to you. We want to provide this information anyway since we believe that they are often useful to finding problems with j2ee applications and we let you decide whether to try them or not. No guarantees about the behaviour when these are added can be made, so do not run it on a live mission-critical server. The most useful ones will get promoted to appear in the normal log files.
Let us group the debug modes to get a more clear picture.
| Property | Description |
| http.session.debug | Setting this to true gives you console output about session events, for example:"Created session with id 'MLKAJFMKIFDA' at Mon Sep 11 01:16:25 GMT+02:00 2000, secure-only: false" |
| http.cluster.debug | See Cluster debugging below. |
| http.virtualdirectory.debug | Setting this to true gives you verbose console output about the creation of virtual directories. |
| jsp.reuse.tags | If set to false, JSP Tags will not be pooled, but a fresh instance will be gotten every time you use a tag. If your application is correct, the behavior of the application shouldn't change when you change this value and if it does, you are using optional tag attributes incorrectly (relying on optional attributes being cleared). |
| debug.http.contentLength | Setting this to true gives you console output when the content length is set and when error page are sent. |
| http.single.threaded | Tells static file serving to just use one thread. It's unlikely that you'll want to play with this |
| http.server.header | Not really useful for debugging. Simply changes the Server: header reported by the server. |
Table 1: HTTP debugging
| Property | Description |
| datasource.verbose | Setting this to true gives you verbose info on datasource-creation. When a new datasource is created (at startup) it will print something like this to the console: "jdbc:HypersonicSQL:defaultdb: Started" or "Orion Pooled jdbc:oracle:thin:@test.foo.com:1521:oracle8i: Started". You will also be notified when connections are opened, when connections are released to the pool, etc. |
| jdbc.debug | Setting this to true gives you some very verbose information when jdbc calls are made. This information is not as useful as the one for datasource.verbose. |
| jdbc.nontx.autocommit | Can be used to set whether autocommit should be on for non-transaction connections. Specify false to turn it off, normally it is on. |
| jdbc.connection.debug | If you are having trouble with leaking jdbc connections, set this to true to find out where the leaked connection was created. |
| debug.jdbc.check | Set this to true to perform additional tests when using jdbc.debug="true". |
Table 2: JDBC debugging
| Property | Description |
| transaction.log | If set to "console" (transaction.log="console") this tells the server to print verbose information regarding transactions to the console. You will see the message "Transaction log activated..." when Orion is starting up. |
| ejb.debug.state | currently undocumented |
| ejb.assert | currently undocumented |
Table 3: EJB debugging
| Property | Description |
| xml.validate | Setting this to true turns on XML validation for the configuration files. |
| xml.rewrite | Setting this to true makes Orion try to rewrite configuration files that fail the xml validation. |
| xml.parser | Specifies which XML parser to use. javax.xml for the JAXP parser or xerces for xerces. |
Table 4: Configuration debugging
| Property | Description |
| http.cluster.debug | If set to true, prints verbose information about http clustering events to the console. |
| cluster.debug | If set to true, prints verbose information about server clustering events to the console. |
Table 5: Cluster debugging
| Property | Description |
| jms.debug | Set to true for JMS debug info |
| multicast.debug | Set to true for Multicast debug info |
Table 6: JMS debugging
| Property | Description |
| rmi.debug | Set to true for RMI debug info |
| rmi.verbose | Set to true for RMI verbose info |
Table 7: RMI debugging
| Property | Description |
| poll.files | currently undocumented |
| socket.so.timeout | Sets the socket timeout |
| ssl.provider | Sets the SSL provider |
| native.user | Used to run Orion under another user than root for unix systems |
Table 8: RMI Miscellaneous
4
Understanding error messages
This section will contain a list of common Error messages and what they mean. So far it only contains a few but we will be adding more as we go along.
-
java.io.StreamCorruptedException - Thrown when control information that was read from an object stream violates internal consistency checks. Means you are probably trying to connect to a port that is not listning to ormi calls but to some other protocol, like http or ftp.
-
Orion crashes with a "SIGBUS 10* bus error" (or similar Operating System error message) and exits to the command prompt - A SIGBUS 10* bus error is not a Java error, but a native error, which means that it is caused by a JVM bug that is pretty much out of our control. We try to work around JVM bugs as much as possible, but obviously, some JVM bugs are fatal. When you get hit by a JVM bug, this is what you should do:
1. Get the absolutely latest version of your JVM.
2. If the latest version is still buggy, report the bug to your JVM vendor and send a mail to bugs@orionserver.com. We will try to work around the bug if we can reproduce it, but there are no guarantees that this is doable. If it is not doable we can at least keep track of which JVMs are buggy which will help us help you. After reporting the bug to the VM vendor, try a JVM from another vendor. If this fails too, repeat the steps again.
The Solaris JVMs are unfortunately known to contain many bugs that affect server software. Do try the latest release to see if this fixes your problem.
-
When starting Orion's web service with IP="[ALL]" for the Orion web site and you get an error saying that the address is already in use - The problem with this behaviour, is with how the ServerSocket class handles this. When you want a Java ServerSocket to bind to all IP's, you use the special 0.0.0.0 IP address. This works fine normally.
However, if there is one IP being used, for example by another web server, the creation of the ServerSocket will fail.
Normally, 0.0.0.0 should actually mean "all available" IP:s and deal with the situation fine, but obviously it doesn't in this case.
Now you might say, if 0.0.0.0 fails, you can open 1 ServerSocket per available IP and not care about the IP:s it can get. Besides the possible performance issues, the problem with this is how to actually get a collection of all available IP:s on a box. The obvious way to do it would be to use InetAddress.getAllByName(InetAddress.getLocalHost().getHostName()); That should return an array of all IP:s, but unfortunately it doesn't on certain systems. This could be an issue with how these systems resolve localhost.
5
Using a debugger
There are many IDEs and stand-alone debuggers on the market today. This section is dedicated to explaining how to set up different debuggers with Orion. The descriptions written here are provided by Orion users and we greatly appreciate any other texts about using other debuggers. The people contributing the texts are mentioned at the end of every instruction.
5.1 NetBeans/Forte
Required Components:
Go through the following steps to setup debugging with Net.Beans:
-
Install JDK 1.2.2 to d:\jdk1.2.2
After installation check/clean up your PATH and CLASSPATH environment variables. Remove anything that points to any other JVM. CLASSPATH is not really needed by JDK 1.2.2, so you can probably remove any entries safely. And make absolutely sure there are no entries like <another JVM>\bin in your path.
Add d:\jdk1.2.2\bin to your PATH variable.
-
Install JPDA to d:\jpda
For JPDA to work, you must add d:\jpda\bin to your PATH variable
-
Install JPDA as a Java Extension
Copy d:\jpda\lib\jpda.jar to d:\jdk1.2.2\jre\lib\ext
-
Install NetBeans to d:\NetBeans
Unpack the .zip file to d:\, this will autmatically create the d:\NetBeans folder.
(at this point NetBeans is configured to allow debugging of remote JVMs)
-
Install Orion to d:\orion
If you already have orion installed, there is no need to re-install.
-
Create a batch file that starts Orion with the JPDA options turned on.
I created d:\orion\oriondebug.bat with the following contents:
set CLASSPATH=%CLASSPATH%;.\orion.jar;.\ejb.jar;.\jndi.jar;.\lib\tools.jar;d:\jpda\lib\jpda.jar
java -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -jar orion.jar
(This will run orion in a debug-enabled JVM that is listening on port 8000 for debug connections. The JVM will wait untill a connection is made to continue execution)
-
Run NetBeans and connect the debugger to the Orion JVM.
Start Orion with the batch file described above.
Run NetBeans by double-clicking d:\NetBeans\bin\runide.exe.
After netbeans comes up, select "Connect..." from the "Debug" menu. If JPDA is installed properly you should see "Default Debugger (JPDA)" in the dialog under "Connector type". If so...
Select "SocketAttach" for the connector, and enter "8000" in the "port" field.
Click "OK".
If you don't get an error, you have successfully connected the debugger to the Orion JVM. This will allow the JVM to continue executing, and Orion will initialize.
Have a source file for one of the Orion components (servlet, EJB, etc.) open, with a breakpoint set. (The source code for the class(es) you want to debug must be in the NetBeans classpath (i.e. "Filesystem"), otherwise the debugger will halt at the breakpoint(s), but you will not be able to trace through the source.) As soon as that code executes, the debugger will halt execution, allowing you to trace through it, watch variables, etc.
If you are using a browser to invoke the server-side code, you will want to use IE. Try it with Netscape and you will understand why... (the CPU gets pegged and everything slows to a crawl while Netscape blocks waiting for data).
Thanks to P. Taylor Goetz for these instructions
5.2 Kawa
Get Kawa Pro (not the enterprise version) from Tek-Tools and install it. Configure your JDK as required when you first run Kawa.
Create a new project for your servlets or EJBs. Add orion.jar, any additional jars required by the application, and the deployed class directory (i.e., c:\applications\myApp\myApp-web\WEB-INF\classes or c:\applications\myApp\myApp-ejb, or both).
From the Project/Interpreter menu, set the Java class to run to com.evermind.server.ApplicationServer and remember to tell it to use this class. Turn off JVMDI debugger from the Customize/Options/Advanced Paths form, which is for performance only and is not vital.
Add the breakpoints to your servlets and/or EJBs. F5 starts debugging.
You can also use use Jikes: Customize/Options/Advanced Paths/Compiler = D:\jikes\jikes.exe +E and set Orion to use jikes from $ORION/server.xml.
Thanks to Dave Smith for this contribution.
5.3 IntelliJ IDEA
Get IDEA from IntelliJ and install it.
Create a new project for your servlets or EJBs.
Add orion.jar and any additional jars to your project classpath.
Go the projects preferenses and select Project|Run/Debug. Add a new
run/debug target, name it something like "Orion Embedded".
Set 'Main class' to
"com.evermind.server.ApplicationServer".
Set 'Working directory' to
the Orion installation directory.
Save configuration by pressing
Ok.
Set breakpoints in your servlets and/or your EJB's.
Run "Orion Embedded" in debug-mode. Orion will now break into the
debugger whenever it encounters a valid breakpoint.
Thanks to Niclas Olofsson for this contribution.
6 Adding your own info for debugging
The most basic step for debugging your application is probably to add some debug information and even now, a long time after debuggers made their break-through a lot of people still think sprinkling the code with debug prints is the only way to go. And in many cases it might actually still be a solution that does the job faster than anything else.
Copyright ©
2005 IronFlare AB
|