Tomcat access log Source Code Analysis and Application
Tomcat logs can be divided into two types:
1. Access logs record the access time, source, data, and other relevant information (all information available for ServletRequest can be recorded );
2. The running log records tomcat running, exception, and error information.
Tomcat's log records are often replaced by log4j or slf4j. However, we will not discuss other log components here. Here we will talk about tomcat's native access logs. I have the opportunity to write another article on running log analysis. For access logs, tomcat defines the following interfaces:
Public interface AccessLog {
// Record access logs
Public void log (Request request, Response response, long time );
// Ip
Public static final String REMOTE_ADDR_ATTRIBUTE =
"Org. apache. catalina. AccessLog. RemoteAddr ";
// Host name
Public static final String REMOTE_HOST_ATTRIBUTE =
"Org. apache. catalina. AccessLog. RemoteHost ";
// Access Protocol
Public static final String PROTOCOL_ATTRIBUTE =
"Org. apache. catalina. AccessLog. Protocol ";
// Port number
Public static final String SERVER_PORT_ATTRIBUTE =
"Org. apache. catalina. AccessLog. ServerPort ";
// Set whether to record ip address, host name, protocol, and port number
Public void setRequestAttributesEnabled (boolean requestAttributesEnabled );
Public boolean getRequestAttributesEnabled ();
}
One default implementation is AccessLogValue (configured in server. xml ). Let's take a look at how to configure and use AccessLogValue. In $ atat_home %/conf/server. xml, we have the following code:
<Valve className = "org. apache. catalina. valves. AccessLogValve" directory = "logs"
Prefix = "localhost_access_log." suffix = ". txt"
Pattern = "% h % l % u % t & quot; % r & quot; % s % B"/>
The parameters are described as follows:
ClassName: The Implementation class of access logs (implements AccessLog)
Directory: log location
Prefix: the prefix of the log name.
Suffix: log name suffix
Pattern: the log mode parameter. (For details about setting the mode parameter, refer to the appendix)
For more parameter settings, you can view the parameters of AccessLogValue.
For pattern, tomcat provides two convenient shorthand for pattern: common: % h % l % u % t "% r" % s % B; combined-% h % l % u % t "% r" % s % B "% {Referer} I" "% {User-Agent} I"
Because of the above configuration method, we often see the following log file (in $ atat_home $/logs/). The following date is generated by code:
For the configuration and source code of other basic field settings, it should not be easy to understand (similar to the Common Explanation of xml files). The following focuses on, if you write logs based on patten (read the following appendix first ):
There are two pattern writing methods: % XXX or % {XXX} XX. Use code analysis to analyze pattern, then obtain the corresponding information based on pattern, and write the information to a StringBuilder. The Analysis of pattern is as follows: for various configuration parameters, such as a and A, all should belong to a XXXElenment, and for spaces or other characters, add A StringElement. When analyzing pattern, each time a special character is encountered, a specified element is created. Otherwise, a StringElement is created. The analysis of pattern is as follows:
List <AccessLogElement> list = new ArrayList <AccessLogElement> ();
Boolean replace = false;
StringBuilder buf = new StringBuilder ();
For (int I = 0; I <pattern. length (); I ++ ){
Char ch = pattern. charAt (I );
If (replace ){
/*
* It is used to process '{'. If '}' is not met afterwards, ignore '{' and do not process it.
* Handle the following three situations:
* % {Xxx} I header field information
* % {Xxx} c cookie Information
* % {Xxx} r ServletRequest's attribute
* % {Xxx} s attribut of an HttpSession
*/
If ('{' = ch ){
StringBuilder name = new StringBuilder ();
Int j = I + 1;
For (; j <pattern. length ()&&'}'! = Pattern. charAt (j); j ++ ){
Name. append (pattern. charAt (j ));
}
If (j + 1 <pattern. length ()){
// J + 1, skip the character '} x'
J ++;
List. add (createAccessLogElement (name. toString (),
Pattern. charAt (j )));
I = j; // skip % {xxx} x
} Else {
// A single character, such as a, directly creates the corresponding Element
List. add (createAccessLogElement (ch ));
}
} Else {
List. add (createAccessLogElement (ch ));
}
Replace = false;
} Else if (ch = '% '){
Replace = true;
List. add (new StringElement (buf. toString ()));
Buf = new StringBuilder ();
} Else {
Buf. append (ch );
}
}
If (buf. length ()> 0 ){
List. add (new StringElement (buf. toString ()));
}
Through the above analysis, we can obtain the required information based on pattern (stored in the list). For the creation of various elements, such:
·/*
* Create one of the following six types of information based on pattern:
* % {Xxx} I gets an attribute of the header
* % {Xxx} c obtains an attribute of the cookie.
* % {Xxx} o gets an attribute of response
* % {Xxx} r gets an attribute of the request.
* % {Xxx} s gets an attribute of the session.
* % {Xxx} t obtains an attribute of dateAndTime.
*/
Protected AccessLogElement createAccessLogElement (String attribute, char pattern ){
Switch (pattern ){
Case 'I ':
Return new HeaderElement (attribute );
Case 'C ':
Return new CookieElement (attribute );
Case 'O ':
Return new ResponseHeaderElement (attribute );
Case 'r ':
Return new RequestAttributeElement (attribute );
Case's ':
Return new SessionAttributeElement (attribute );
Case 'T ':
Return new DateAndTimeElement (attribute );
Default:
Return new StringElement ("??? ");
}
}
Create a regular element:
Protected AccessLogElement createAccessLogElement (char pattern ){
Switch (pattern ){
Case 'A ':
Return new RemoteAddrElement ();
Case 'A ':
Return new LocalAddrElement ();
Case 'B ':
Return new ByteSentElement (true );
Case 'B ':
Return new ByteSentElement (false );
Case 'D ':
Return new ElapsedTimeElement (true );
Case 'F ':
Return new FirstByteTimeElement ();
Case 'H ':
Return new HostElement ();
Case 'H ':
Return new ProtocolElement ();
Case 'l ':
Return new LogicalUserNameElement ();
Case 'M ':
Return new MethodElement ();
Case 'p ':
Return new LocalPortElement ();
Case 'q ':
Return new QueryElement ();
Case 'r ':
Return new RequestElement ();
Case's ':
Return new HttpStatusCodeElement ();
Case's ':
Return new SessionIdElement ();
Case 'T ':
Return new DateAndTimeElement ();
Case 'T ':
Return new ElapsedTimeElement (false );
Case 'U ':
Return new UserElement ();
Case 'U ':
Return new RequestURIElement ();
Case 'V ':
Return new LocalServerNameElement ();
Case 'I ':
Return new ThreadNameElement ();
Default:
Return new StringElement ("??? "+ Pattern + "??? ");
}
}
For various elements, only a few of them are provided here. Others are similar:
// AccessElement Interface
Protected interface AccessLogElement {
Public void addElement (StringBuilder buf, Date date, Request request,
Response response, long time );
}
// SessionElement % {xxx} s
Protected static class SessionAttributeElement implements AccessLogElement {
Private final String header;
Public SessionAttributeElement (String header ){
This. header = header;
}
@ Override
Public void addElement (StringBuilder buf, Date date, Request request,
Response response, long time ){
Object value = null;
If (null! = Request ){
HttpSession sess = request. getSession (false );
If (null! = Sess ){
Value = sess. getAttribute (header );
}
} Else {
Value = "?? ";
}
If (value! = Null ){
If (value instanceof String ){
Buf. append (String) value );
} Else {
Buf. append (value. toString ());
}
} Else {
Buf. append ('-');
}
}
}
// QueryElement % q
Protected static class QueryElement implements AccessLogElement {
@ Override
Public void addElement (StringBuilder buf, Date date, Request request,
Response response, long time ){
String query = null;
If (request! = Null ){
Query = request. getQueryString ();
}
If (query! = Null ){
Buf. append ('? ');
Buf. append (query );
}
}
}
For more details, please continue to read the highlights on the next page:
Load Balancing between Apache and multiple Tomcat clusters in Linux
Nginx Tomcat Cluster load balancing solution notes
Instance details Tomcat component installation + Nginx reverse proxy Tomcat + Apache use mod_jk and mod_proxy Reverse Proxy and load balancing
Deploy a log server using Rsyslog + LogAnalyzer + MySQL in CentOS 6.5
Build an Apache + Tomcat environment (JK deployment process)