1. Introduction
Spring Boot comes with an embedded Tomcat server, which is super-handy. However, we can’t see Tomcat’s logs by default.
In this tutorial, we’ll learn how to configure Spring Boot to show Tomcat’s internal and access logs via a toy application.
2. Sample Application
First of all, let’s create a REST API. We’ll define a GreetingsController to greet the user:
@GetMapping("/greetings/{username}") public String getGreetings(@PathVariable("username") String userName) { return "Hello " + userName + ", Good day...!!!"; }
3. Tomcat Log Types
Embedded Tomcat stores two types of logs:
- Access logs
- Internal server logs
The access logs keep the records of all the requests processed by the application. These logs can be used to track things like page hit counts and user session activity. In contrast, internal server logs will help us to troubleshoot any issues in our running application.
4. Access Logs
By default, the access logs aren’t enabled.
We can easily enable them, though, by adding a property to application.properties:
server.tomcat.accesslog.enabled=true
Similarly, we can use VM arguments to enable the access logs:
java -jar -Dserver.tomcat.basedir=tomcat -Dserver.tomcat.accesslog.enabled=true app.jar
These log files will be created in a temporary directory. For example, on Windows, the directory for access logs will look something like AppData\Local\Temp\tomcat.2142886552084850151.40123\logs
4.1. Format
So, with this property enabled, we’d see something like the following in our running application:
0:0:0:0:0:0:0:1 - - [13/May/2019:23:14:51 +0530] "GET /greetings/Harry HTTP/1.1" 200 27 0:0:0:0:0:0:0:1 - - [13/May/2019:23:17:23 +0530] "GET /greetings/Harry HTTP/1.1" 200 27
These are the access logs, and they have the format:
%h %l %u %t \"%r\" %>s %b
Which we can interpret as:
%h – the client IP which has sent the request, 0:0:0:0:0:0:0:1 in this case
%l – the identity of the user
%u – the user name determined by HTTP authentication
%t – the time the request was received
%r – the request line from the client, GET /greetings/Harry HTTP/1.1 in this case
%>s – the status code sent from the server to the client, like 200 here
%b – the size of the response to the client, or 27 for these requests
Since this request didn’t have an authenticated user, %l and %u printed dashes.
In fact, if any information is missing, Tomcat will print a dash for that slot.
4.2. Customizing Access Logs
We can override the default Spring Boot configuration by adding few properties in application.properties.
Firstly, to change the default log file name:
server.tomcat.accesslog.suffix=.log server.tomcat.accesslog.prefix=access_log server.tomcat.accesslog.file-date-format=.yyyy-MM-dd
Also, we can change the location of the log files:
server.tomcat.basedir=tomcat server.tomcat.accesslog.directory=logs
Finally, we can override the way logs are written in the log file:
server.tomcat.accesslog.pattern=common
There are a few more configurable properties in Spring Boot, too.
5. Internal Logs
Tomcat server’s internal logs are very helpful to solve any server-side issues.
To view these logs, we have to add below logging configuration in application.properties:
logging.level.org.apache.tomcat=DEBUG logging.level.org.apache.catalina=DEBUG
And then we’ll see something like:
2019-05-17 15:41:07.261 DEBUG 31160 --- [0124-Acceptor-0] o.apache.tomcat.util.threads.LimitLatch : Counting up[http-nio-40124-Acceptor-0] latch=1 2019-05-17 15:41:07.262 DEBUG 31160 --- [0124-Acceptor-0] o.apache.tomcat.util.threads.LimitLatch : Counting up[http-nio-40124-Acceptor-0] latch=2 2019-05-17 15:41:07.278 DEBUG 31160 --- [io-40124-exec-1] org.apache.tomcat.util.modeler.Registry : Managed= Tomcat:type=RequestProcessor,worker="http-nio-40124",name=HttpRequest1 ... 2019-05-17 15:41:07.279 DEBUG 31160 --- [io-40124-exec-1] m.m.MbeansDescriptorsIntrospectionSource : Introspected attribute virtualHost public java.lang.String org.apache.coyote.RequestInfo.getVirtualHost() null ... 2019-05-17 15:41:07.280 DEBUG 31160 --- [io-40124-exec-1] o.a.tomcat.util.modeler.BaseModelMBean : preRegister org.apache.coyote.RequestInfo@1e6f89ad Tomcat:type=RequestProcessor,worker="http-nio-40124",name=HttpRequest1 2019-05-17 15:41:07.281 DEBUG 31160 --- [io-40124-exec-1] o.a.tomcat.util.net.SocketWrapperBase : Socket: [org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper@4cb3cc24:org.apache.tomcat.util.net.NioChannel@510e2d43:java.nio.channels.SocketChannel[connected local=/0:0:0:0:0:0:0:1:40124 remote=/0:0:0:0:0:0:0:1:55189]], Read from buffer: [0] 2019-05-17 15:41:07.282 DEBUG 31160 --- [io-40124-exec-1] org.apache.tomcat.util.net.NioEndpoint : Socket: [org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper@4cb3cc24:org.apache.tomcat.util.net.NioChannel@510e2d43:java.nio.channels.SocketChannel[connected local=/0:0:0:0:0:0:0:1:40124 remote=/0:0:0:0:0:0:0:1:55189]], Read direct from socket: [507] 2019-05-17 15:41:07.292 DEBUG 31160 --- [io-40124-exec-1] org.apache.tomcat.util.http.Parameters : Set query string encoding to UTF-8 2019-05-17 15:41:07.294 DEBUG 31160 --- [io-40124-exec-1] o.a.t.util.http.Rfc6265CookieProcessor : Cookies: Parsing b[]: jenkins-timestamper-offset=-19800000 2019-05-17 15:41:07.296 DEBUG 31160 --- [io-40124-exec-1] o.a.c.authenticator.AuthenticatorBase : Security checking request GET /greetings/Harry 2019-05-17 15:41:07.296 DEBUG 31160 --- [io-40124-exec-1] org.apache.catalina.realm.RealmBase : No applicable constraints defined
6. Conclusion
In this article, we’ve learned the difference between Tomcat’s internal and access logs. Then, we saw how to enable and customize them.
Make sure to check out the sample over on GitHub.