Showing posts with label tomcat. Show all posts
Showing posts with label tomcat. Show all posts

Thursday, October 31, 2013

Quick Start to tracing JDBC SQL operations using log4jdbc

Keywords:
database logging show SQL log4jdbc tomcat JNDI log4j trace performance timing

Problem:
Given a complex web application (with many moving parts), there's performance issues that first impressions seem to point at environment-specific database latency. Is there any way to trace/profile/monitor all the SQL statements being made to the database (preferably with timings)?

Solution:
log4jdbc seamlessly lets you configure a logger between your application and the JDBC connection. Documentation on the log4jdbc site is very good and has just about all you need to know, below is a "quick start" for the impatient.

Step 1: Jar File(s)

Drop the log4jdbc4-[version].jar file into [webapp]/WEB-INF/lib.
You'll also need:
  • a supported logging framework (log4j: log4j-[version].jar)
  • the SLF4J API (slf4j-api-[version].jar - already had it)
  • the SLF4J jar to use this logging framework (slf4j-log4j12-[version].jar - already had it)

Step 2: Driver Class and URL

  1. Change the database resource definition to use the driver class net.sf.log4jdbc.DriverSpy ('spy' as it will work out the correct 'real' driver class to use).
  2. Simply prepend jdbc:log4 to the existing URL.

For a PostgreSQL database connection configured as a JNDI/JDBC Resource in Tomcat, this will look like:
    <Resource
            name="jdbc/example"
            type="javax.sql.DataSource"
            factory="org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory"
            driverClassName="net.sf.log4jdbc.DriverSpy"
            url="jdbc:log4jdbc:postgresql://localhost:5432/example"
            username="postgres" password="***" 
            maxActive="20" maxIdle="10" maxWait="-1" 
            removeAbandoned="true" removeAbandonedTimeout="120" logAbandoned="true"
            auth="Container"
            charset="UTF-8" />

Step 3: Logging Config

There's detailed notes on the five key loggers and an example log4j.properties is available. But if you just want to see SQL + timings, the following will log this all to console:
log4j.logger.jdbc.audit=FATAL,Log4JDBC
log4j.additivity.jdbc.audit=false

log4j.logger.jdbc.resultset=FATAL,Log4JDBC
log4j.additivity.jdbc.resultset=false

log4j.logger.jdbc.sqlonly=FATAL,Log4JDBC
log4j.additivity.jdbc.sqlonly=false

log4j.logger.jdbc.sqltiming=INFO,Log4JDBC
log4j.additivity.jdbc.sqltiming=false

log4j.logger.jdbc.connection=FATAL,Log4JDBC
log4j.additivity.jdbc.connection=false

log4j.appender.Log4JDBC=org.apache.log4j.ConsoleAppender
log4j.appender.Log4JDBC.layout=org.apache.log4j.PatternLayout
log4j.appender.Log4JDBC.layout.ConversionPattern=%-5p [%d{DATE} %c]: %m%n


That's it. Start up the application and it should function exactly as it did before, but all SQL operations (made via the JNDI connection pool resource in my example) will be logged in the form:
INFO  [01 Nov 2013 12:00:00,000 jdbc.sqltiming]: SELECT NAME FROM PERSON WHERE ID=54321
{executed in 1 msec}


Notes:

Bonus Step: Trace back to the Application Code

If your issue is working what part of the application code triggered the execution of a given SQL statement, a neat feature of the log4jdbc loggers is including the class & method-name of the code that invoked the JDBC driver. As there may be a few layers between your code and the JDBC driver (hibernate > application server connection pool, etc) you can tell it what level you what to capture from.
  1. change log level to DEBUG
    log4j.logger.jdbc.sqltiming=DEBUG,Log4JDBC
  2. set the system property log4jdbc.debug.stack.prefix
    -Dlog4jdbc.debug.stack.prefix=com.example
Log statements will then be in the form:
DEBUG [01 Nov 2013 12:30:00,000 jdbc.sqltiming]:  com.example.PersonDAO.findPerson(PersonDAO.java:111)
2. SELECT NAME FROM PERSON WHERE ID=54321
{executed in 53 msec}

NB: this extra logging adds a noticeable overhead to the database usage (and timings).



Friday, August 02, 2013

Tomcat IIS Connector "request entity is too large"

Keywords:
tomcat IIS IIS7 jk connector max_packet_size packetSize "The page was not displayed because the request entity is too large"

Problem:
With IIS successfully configured with tomcat using the Apache Tomcat Connector (aside: if you haven't got that far the IIS Admin Blog - How To Configure IIS 7.0 and Tomcat is a good reference - with screenshots) you find that some users can access the web-apps ok, others cannot. They get a plain error page saying:
The page was not displayed because the request entity is too large
How do you fix it?

Solution:
The issue is with attributes in the request exceeding the AJP 8kb default (for me, the ISAPI redirector was logging the error was with the 'Authorization' attribute). You can increase this to maximum of 65Kb.

This needs to be done in the tomcat-connector and tomcat itself.

Step 1: Set max_packet_size in the worker definition

In the workers.properties file referenced by the tomcat-connection definition, set the packet size to the maximum:
worker.<worker name>.max_packet_size=65536
for example:
worker.ajp13w.max_packet_size=65536
Check the workers documentation for more information.

Step 2: Set packetSize in the AJP Connector definition

In the server.xml configuration file for tomcat, set the packet size to the maximum:
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" packetSize="65536"
        tomcatAuthentication="false" />
Check the AJP Connector documentation for more information.


You'll then need to restart tomcat and IIS Site for the changes to take effect (then hope for the best).

Tuesday, April 05, 2011

IIS7 hiding tomcat webapp error pages

Keywords:
IIS IIS7 custom error pages hiding masking tomcat 500 webapp error page jk connector AJP

Problem:
With tomcat integrated into IIS7 using the jk connector error pages from the webapp that have the http-response status set (eg to 500) get "replaced" with a generic IIS custom error page:
500 - Internal server error. 
There is a problem with the resource you are looking for, and it cannot be displayed


A quick web-search reveals it's a common issue for ASP.NET developers and the solution is simply to make changes to the ASP.NET application config or in code setting a special HttpResponse.TrySkipIisCustomErrors property(!) ... but what are the options for when the pages are being supplied by an ISAPI redirector/plugin (i.e. the JK connector in this case)?

Solution:
Based on the detailed notes on the IIS Blog (What to expect from IIS7 custom error module) the minimal steps required seem to be the following:

Step 1: create a Web.config file in the root folder of the Web Site


This is the Web Site where you've configured the "jakarta" virtual directory. If it's "Default Web Site" this may be C:\inetpub\wwwroot but check the properties to be sure (Right click Web Site > Manage Web Site > Advanced Settings ... and note the setting for 'Physical Path').

Step 2: add configuration to the Web.config file


<configuration>
   <system.webServer>
      <httpErrors errorMode="Detailed" existingResponse="Auto" />
   </system.webServer>
</configuration>


Step 3: restart the web site


Eg Right click Web Site > Manage Web Site > Restart


Be sure to to test this on the local machine (where IIS7 is installed) and from another machine in the network as IIS may give different error-page behaviour for local and 'remote' requests.

Wednesday, March 03, 2010

Enable debug/trace level logging for Tomcat 6 Realms

Keywords:
tomcat 6 realm logging juli logging.properties debug="9" debug="99" debug="true" JNDIRealm trace verbose jndi realm JNDIRealm

Problem:
Apparently Tomcat 6 Logging is greatly improved ... more granularity, flexibility in choosing java.util.logging or log4j, etc. This is great, but I'm happy with the default logging - ie if something goes wrong let me get the detail from a log file.

This attitude hits a snag where things go wrong and there's nothing in the logs - in my case, setup of a org.apache.catalina.realm.JNDIRealm is not letting me in but there's no details why. It used to be a matter of simply setting debug="9" on the Realm definition and you have verbose logging - the examples in the Tomcat 6 Realm documentation still use this:
<Realm className="org.apache.catalina.realm.JNDIRealm" debug="99"
    connectionURL="ldap://localhost:389"
    userPattern="uid={0},ou=people,dc=mycompany,dc=com"
    roleBase="ou=groups,dc=mycompany,dc=com"
    roleName="cn"
    roleSearch="(uniqueMember={0})"
/>
But this has no effect on logging. You'll get a warning telling you as much:
03/03/2010 10:56:08 AM org.apache.tomcat.util.digester.SetPropertiesRule begin
WARNING: [SetPropertiesRule]{Server/Service/Engine/Realm} Setting property 'debug'
 to '99' did not find a matching property.
What's the minimum I have to do to enable debug?

Solution:
You have to edit the $CATALINA_HOME/conf/logging.properties file.

1. Configure debug logging for Realms and Authentication

Insert the following lines (in blue):
############################################################
# Facility specific properties.
# Provides extra control for each logger.
############################################################
# This would turn on trace-level for everything
# the possible levels are: SEVERE, WARNING, INFO, CONFIG, FINE, FINER, FINEST or ALL
#org.apache.catalina.level = ALL
#org.apache.catalina.handlers = 2localhost.org.apache.juli.FileHandler
org.apache.catalina.realm.level = ALL
org.apache.catalina.realm.useParentHandlers = true
org.apache.catalina.authenticator.level = ALL
org.apache.catalina.authenticator.useParentHandlers = true

org.apache.catalina.core.ContainerBase.[Catalina].[localhost].level = INFO
org.apache.catalina.core.ContainerBase.[Catalina].[localhost].handlers = 2localhost.org.apache.juli.FileHandler
This will give you debug/trace level logging to console and the file assuming you've kept the default config. But you only see debug in the console, not the catalina.[date yyyy-MM-dd].log file - in fact, the log file empty? The buffering means the file-logging is only written when the buffer is full.

2. Disable buffering for FileHandler logging

(until the issue is resolved of course) Insert the line (in blue):
1catalina.org.apache.juli.FileHandler.level = FINE
1catalina.org.apache.juli.FileHandler.directory = ${catalina.base}/logs
1catalina.org.apache.juli.FileHandler.prefix = catalina.
1catalina.org.apache.juli.FileHandler.bufferSize = -1
These two inserts give you pretty much the equivalent of the old debug="9" and you'll (hopefully) get the verbose information required - happy debugging ...

Thursday, February 18, 2010

Configure endorsed libraries in Tomcat 6

Keywords:
Tomcat 6 endorsed java.endorsed.dirs Endorsed Standards Override Mechanism XML libraries xerces

Problem:
If your webapp needs its own XML libraries (xerces in particular) how do you get Tomcat 6 to use this and not the JAXP APIs packaged into the JSE? This used to be as simple as dropping them into ${CATALINA_BASE}/common/endorsed but there's only a ${CATALINA_BASE}/lib folder ...

Solution:
Thankfully found the solution in this blog (and comments).

Simply, create a ${CATALINA_BASE}/endorsed folder and drop the jar files in there. Tomcat will be setup to use this if it exists.


Notes:
No explicit mention of this in Tomcat 6 Class Loader notes

It does note the -Djava.endorsed.dirs system property is set but you need to check setclasspath.[bat|sh] for when it's set and what it's set to by default - ie ${CATALINA_BASE}/endorsed.

Wednesday, June 18, 2008

HTTP Status 405 - HTTP method POST is not supported by this URL

Keywords:
HTTP Status 405 - HTTP method POST is not supported by this URL form login tomcat

Problem:
What does this error mean when reported by tomcat?
HTTP Status 405 - HTTP method POST is not supported by this URL
Status report

HTTP method POST is not supported by this URL

The specified HTTP method is not allowed for the requested resource (HTTP method POST is not supported by this URL).


Solution:
Simple answer: your servlet needs to implement doPost(HttpServletRequest, HttpServletResponse). Your servlet probably already implements doGet() so if you don't care about implementing different logic for POST, then just get it to call doGet():
public void doPost(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
        // same logic
        this.doGet(request, response);
}


Notes:
It's a bit confusing if the servlet is a login form. GET should be returning the login form, POST from this form is handled by j_security_check. But if the client's initial request was a POST then the login servlet just needs to implement doPost() to keep the servlet container happy (calling doGet() as mentioned above is fine).

It seems that the servlet container (tomcat at least) makes sure the data from the original POST is not lost once the user gets past the j_security_check: Tomcat - User - [is] post data lost when redirecting

Wednesday, July 18, 2007

NullPointerException tomcat5 realWriteChars

Keywords:
NullPointerException tomcat5 realWriteChars servlet

Problem:
Getting this stack trace on each access of a servlet:

java.lang.NullPointerException
 at org.apache.coyote.tomcat5.OutputBuffer.realWriteChars(OutputBuffer.java:569)
 at org.apache.tomcat.util.buf.CharChunk.flushBuffer(CharChunk.java:435)
 at org.apache.tomcat.util.buf.CharChunk.append(CharChunk.java:366)
 at org.apache.coyote.tomcat5.OutputBuffer.write(OutputBuffer.java:516)
 at org.apache.coyote.tomcat5.CoyoteWriter.write(CoyoteWriter.java:149)
 at org.apache.coyote.tomcat5.CoyoteWriter.write(CoyoteWriter.java:158)
 at org.apache.coyote.tomcat5.CoyoteWriter.print(CoyoteWriter.java:208)
 at org.apache.coyote.tomcat5.CoyoteWriter.println(CoyoteWriter.java:265)
 at com.example.MyServlet.doGet(MyServlet.java:56)


The line number in "MyServlet" code that's kicking this off is a simple PrintWriter.println() ... what it's writing to the stream is definitely not null. How could a NPE be caused in tomcat?

Solution:
I wouldn't have guessed at the issue if not trying the same servlet on WebSphere ... then you get a more useful error message:
Invalid character encoding "UTF=8"

There's a typo (ie '=' instead of '-') in the call to set the content type on the HttpResponse object! Correcting this to "UTF-8" fixes the issue:
response.setContentType("text/html; charset=UTF-8");

Wednesday, March 21, 2007

JSP EL expressions are being ignored by tomcat

Keywords:
tomcat JSP JSTL EL

Problem:
Hopefully this is my last post about the possible problems with JSP/web-app specs and EL. In this case, there's a JSP using EL
Eg:

<%
String myUrl = (String)session.getAttribute("SESSION_KEY_MY_URL");
pageContext.setAttribute("myUrl", returnUrl);
%>
<form name="load" action="${myUrl}" method="GET">


It's coming out in HTML with the EL untouched (but the scriptlet is definitely being run).

<form name="load" action="${myUrl}" method="GET">


Why is the EL being ignored?

Solution:
As with the previous 2 posts on this issue, you have to fix the schema reference in the web.xml (there's too many differing copies of the web.xml(s) I'm dealing with here) and make sure the JSP has the right tablib uri reference - see this post.

For the first time I found this didn't immediately solve the problem! The HTML is coming out the same with EL unevaluated. The issue is that the JSP has been compiled to TOMCAT_HOME\work\Catalina\localhost\MyApp\org\apache\jsp\jsp\myfolder\MyJSP.java and tomcat sees no need to recompile even though I've updated the spec of the webapp.

The solution is to stop tomcat, remove the contents of TOMCAT_HOME\work and restart (OR update the timestamp on the JSP source file(s) to force recompilation). The JSP will be recompiled (to the right spec 2.0 now) and the EL will be evaluated as you expect.

Tuesday, March 20, 2007

How-to turn off tomcat session serialization

Keywords:
tomcat session serialization NotSerializableException "Cannot serialize session attribute" Manager

Problem:
On restarting tomcat there's a stacktrace (below) about an attribute in the session not being serializable. It doesn't seem to effect the application starting up and the application works fine, but these messages at startup are annoying.

2007-03-20 10:50:57,890 INFO [org.apache.catalina.session.ManagerBase@898] - 
java.io.NotSerializableException: com.example.package.MyBeanClassName
        at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1054)
        at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:278)
        at java.util.ArrayList.writeObject(ArrayList.java:531)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)


If you want to put (transient) non-serializable objects in the session, how do you stop tomcat from serializing them at shutdown/startup?

Solution:
This was hard to find, but you need to configure a Manager in the context of the application. This should be put in either:
  • the YourApp.war:/META-INF/context.xml

  • the TOMCAT_HOME/conf/Catalina/localhost/YourApp.xml file

  • OR the default context ...

<!-- Turn off session serialization -->
    <Manager className="org.apache.catalina.session.PersistentManager"
      debug="0" distributable="false" saveOnRestart="false">
        <Store className="org.apache.catalina.session.FileStore"/>
    </Manager>


The tomcat documentation for the Manager element will give a bit more information, but it doesn't show the className for the file-store Store element, which is crucial if you're using the PersistentManager class - even if you're configuring it to do nothing!

You'll know it's working when there are no longer any files called "SESSIONS.ser" in the TOMCAT_HOME/work/Catalina/localhost/YourApp folder.

Wednesday, February 28, 2007

org.apache.taglibs.standard.lang.jstl.parser.ParseException: EL functions are not supported.

Keywords:
Compile JSP tomcat JSTL error functions "org.apache.taglibs.standard.lang.jstl.parser.ParseException: EL functions are not supported"

Problem:
Some fairly standard use of JSTL:
<c:out value="${fn:escapeXml(myvalue)}" />

i.e. using a function in the value field of the c:out tag gives the error:
org.apache.jasper.JasperException:
    <h3>Validation error messages from TagLibraryValidator for c</h3>
    <p>41: tag = 'out' / attribute = 'value': 
        An error occurred while parsing custom action attribute "value" with value "${fn:escapeXml(myvalue)}": 
            org.apache.taglibs.standard.lang.jstl.parser.ParseException: EL functions are not supported.</p>


Solution:
It's the old mismatched spec issue again. Same solution as described in According to TLD or attribute directive in tag file, attribute X does not accept any expressions - namely, fix the schema reference in the web.xml and make sure the JSP has the right tablib uri reference.

Tuesday, December 12, 2006

According to TLD or attribute directive in tag file, attribute value does not accept any expressions

Keywords:
Compile JSP tomcat JSTL error "According to TLD or attribute directive in tag file, attribute value does not accept any expressions"

Problem:
Compile error from tomcat when it encounters a JSP: "According to TLD or attribute directive in tag file, attribute value does not accept any expressions"

Solution:
For some reason the JSP is using the 1.2 JSP (and 1.0 JSTL) and EL expressions aren't understood. There's a lot of hits on the web for this but in summary there are 2 important things to do to ensure you're getting the right version of the spec:
  1. Reference the correct servlet specification in your deployment descriptor:
    <?xml version="1.0"?>
    <web-app version="2.4"
     xmlns="http://java.sun.com/xml/ns/j2ee"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
  2. Reference the correct JSTL uri in your JSP:
    change
    <%@ taglib uri='http://java.sun.com/jstl/core' prefix='c'%>

    to
    <%@ taglib uri='http://java.sun.com/jsp/jstl/core' prefix='c'%>

Notes:


What Specification goes with what?
Web-app(deployment schema)2.32.42.5
http://java.sun.com/dtd/web-app_2_3.dtdhttp://java.sun.com/xml/ns/j2ee/web-app_2_4.xsdhttp://java.sun.com/xml/ns/javaee/web-app_2_5.xsd
Servlet2.32.42.5
JSP1.22.02.1
JSTL(core uri reference)1.01.11.2
http://java.sun.com/jstl/corehttp://java.sun.com/jsp/jstl/corehttp://java.sun.com/jsp/jstl/core
Tomcat4.x5.x6.x
WebSphere5.x6.x7.x (?)

Tuesday, July 11, 2006

Cannot load mod_jk.so into server: The specified procedure could not be found

Keywords:
apache mod_jk mod_jk.so "The specified procedure could not be found" tomcat

Problem:
I've download the Apache HTTP server and according to the apache.org site "2.2.2 is the best available version". The downloaded mod_jk from the tomcat.apache.org where it claimed that the mod_jk-1.2.14-apache-2.0.54.so download was for Apache 2.0, and works with Apache 2.0.55 and later ... there was no 2.2.x download so I assumed (wrongly) that this would work with Apache 2.2.x as it is "later".

Added the LoadModule line in the httpd.conf file as instructed in http://tomcat.apache.org/connectors-doc/howto/apache.html
and got the following error:
Cannot load [full path]/mod_jk.so into server: The specified procedure could not be found


Solution:
You can't use a Apache 2.0.x module with Apache 2.2.x apparently - it must be built pointing at that specific version of Apache (if you're clever enough to build your own modules with the source code then this is no problem - you could get the source for JK 1.2.15 and build it pointing at your install Apache 2.2.x).

If you rely on the binaries built by Apache, use the HTTP server 2.0.x

Sunday, March 26, 2006

Missing JAAS Config

Keywords:
"Unable to locate a login configuration" JAAS Tomcat

Problem:
Starting up tomcat as a service on Windows the above error message with stack trace displayed. The file it's referring to as missing is in the folder %CATALINA_HOME%/conf/jaas.config

Solution:
You need to make sure the system property "java.security.auth.login.config"
is defined & this should be a full path to the file. This can be via the -D JVM option. eg:
-Djava.security.auth.login.config=%CATALINA_BASE%\conf\jaas.config

Depending on whether you run tomcat via "catalina.bat" or the windows service will determine the best place to put this option.


Notes:
Ok, not a profound solution to start with but it's a solution with a problem description that will hopefully come up in a similar keyword search. I had to scroll to the 6th search result on http://www.google.com.au/search?hl=en&q=%22Unable+to+locate+a+login+configuration%22+JAAS+Tomcat
which actually isn't too bad.