2

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

Mark Bramnik
  • 39,963
  • 4
  • 57
  • 97

3 Answers3

4

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!

Mark Bramnik
  • 39,963
  • 4
  • 57
  • 97
0

My favorite solution is to use additional classpath in Tomcat and load the environment-specific properties from there.
I.e. Tomcat's 'common.loader' property in conf/catalina.properties

In addition, I normally keep default properties inside the .war file, this way you will only specify the differences in the environment-specific ones.

Alexander
  • 2,761
  • 1
  • 28
  • 33
  • I once wrote a blog post on this: http://codrspace.com/Khovansa/spring-java-project-configuration/ – Alexander Jul 08 '17 at 10:07
  • Sorry, I'm not sure I'm following: we use jar, not war and the tomcat is embedded inside the application. Thats one of the benefits of using spring boot at least as I see it... So could you please provide some technical example to illustrate your point? – Mark Bramnik Jul 08 '17 at 10:09
  • You could use the 'loader.path' property provided as e.g. a system property. java -Dloader.path=... -jar .... See for example here: https://stackoverflow.com/a/40500659/1847482 – Alexander Jul 08 '17 at 10:17
  • Or just google 'spring boot additional classpath' - there are many good resources on this. – Alexander Jul 08 '17 at 10:19
0

You will have to do some kind of env specific action if relative paths are no good. From https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-logging.html you can use profiles or you can use an environment variable or a system property. As the other answer says you can load properties from an environment specific file if that is what makes the most sense for you.

Rob Baily
  • 2,770
  • 17
  • 26