Search code examples
javaspringspring-bootaccess-log

Tomcat Access Logs in Spring Boot for different operating systems


Recently I've started to work with Spring Boot and have a following question:

We have different environments (like stage, development, production) and all of them can be run on windows or linux. So I've created application-stage.properties, application-prod.properties, application-devl.properties to specify stuff like db connections and so on because its OS agnostic (the same for windows and linux).

Now I would like to enable access logs for embedded Tomcat server. So following various guides I used the following in my application.properties file:

server.tomcat.accesslog.directory=logs
server.tomcat.accesslog.enabled=true

I was forced to specify a relative path because we use both linux and windows, however I would like the access log to be created in different places depending on the OS . For example, we store logs in windows under c:\<product>\logs and in linux we use /var/log/<product>/...

For usual logs we use logbacks and it allows stuff like this, but since access log is not actually logback driven and instead uses Valves, my question is: how we can achieve the same level of flexibility here?

I don't think I should provide additional profile for this and use it like:

--spring.profiles.active=windows / linux

Because I believe spring boot has some solution up on its sleeves for this :) Thanks a lot in advance


Solution

  • Here is the solution I've come up with. Maybe it will help someone.

    There are 2 steps.

    Step 1 I've created application-windows.properties and application-linux.properties files in src/main/resources. These files hold the OS dependent configuration.

    For example in Linux I specify something like this:

    server.tomcat.accesslog.directory=/var/log/access_logs 
    

    For windows it can be (for example):

    server.tomcat.accesslog.directory=C:\\Temp\\access_logs 
    

    Step 2

    The spring boot application (the file with a main method) usually looks like this:

    // maybe some additional annotations
    @SpringBootApplication
    public class MySpringBootApplication {
        public static void main(String[] args) throws Exception {
           SpringApplication.run(..., args); 
        }
    }
    

    The documentation of spring boot in paragraph 25.2 states that profiles can be added programmatically So I've slightly changed the main class to allow this programmatic addition:

    // maybe some additional annotations
    @SpringBootApplication
    public class MySpringBootApplication {
        public static void main(String[] args) throws Exception {
           SpringApplication myApp = new SpringApplication(...);
           myApp.setAdditionalProfiles(getOSName());
           myApp.run(args); 
        }
    
        private static String getOSName() {
         String os = System.getProperty("os.name");
         if (os.toLowerCase().contains("win")) {
             return "windows";      
         }
         else {
              return "linux";
         }
        }
    }
    

    That's it, now there is no need to specify the profiles in --spring.profiles.active property (I usually use this to specify the environment, like staging, production, etc. The point it that spring will load the relevant property file automatically now.

    Thanks to all the people who have suggested their solutions!