spring-bootlogbacksyslogaccess-log

Spring boot application with embedded tomcat, send access logs to syslog


I have a spring boot application, which runs on AWS EC2 instances.

The deployable is just a jar that has tomcat embedded in it.

I am trying to get the application to send its access log to syslog so that I can use AWS CloudWatch to collect logs from different EC2 instances.

I have tried https://logback.qos.ch/access.html, but it does not work with syslog due to this issue: https://jira.qos.ch/browse/LOGBACK-317

Then I tried CommonsRequestLoggingFilter, this does not seem to send its logs to syslog.

I guess trying to send logs to syslog with Spring boot application is not a rare desire.

Is there any comprehensive way to do this?


Solution

  • I just implemented this in my application. (For Spring boot 1.5.6)

    1. Make sure your tomcat access logging is on, below is the way access logging is enabled in application.yml -

      server: 
       tomcat:
        accesslog:
          enabled: true
          pattern: "<APPNAME> %h %l %u %t \"%r\" %s %b %D"
          prefix: "localhost_access_log"
          suffix: .txt
        basedir: /opt/tomcat 
      
    2. The above will output the access logs in your instances.

    3. Now have your logging defined. For example in application.yml file

      logging:
        level:
          org.springframework.web: INFO
          com.project.path : DEBUG
        config: <path to your config xxml>/logback-springboot.xml
      
    4. The above will get your logback config file from the desired location.
    5. Now, in your code, you need to define your own tomcat access config. For example -

      @Configuration
      public class AccessValveConfig extends WebMvcConfigurerAdapter implements
       EmbeddedServletContainerCustomizer {
      
       private static XLogger logger = XLoggerFactory
          .getXLogger(AccessValveConfig.class);
      
      
       @Override
        public void customize(ConfigurableEmbeddedServletContainer container) {
      
           if (container instanceof TomcatEmbeddedServletContainerFactory) {
      
              TomcatEmbeddedServletContainerFactory factory = 
                    (TomcatEmbeddedServletContainerFactory) container;
              AbstractAccessLogValve accessLogValve = new ApiAccessLogValve();
              accessLogValve.setPattern("common");
              factory.addContextValves(accessLogValve);
           } else {
           logger.error("WARNING! this customizer does not support your 
                   configured container");
          }
       }
      }
      
      public class ApiAccessLogValve extends AbstractAccessLogValve {
      
        private static XLogger logger = XLoggerFactory
          .getXLogger(ApiAccessLogValve.class);
      
        public ApiAccessLogValve(){
         super();
        }
      
       @Override
       protected void log(CharArrayWriter message) {
         synchronized (this) {
          logger.info(message.toString());
         }
       }
      }
      
    6. Now make the necessary configs in your logback xml.

      <!--This will print app logs in user facility-->
      <appender name="SYSLOG" class="ch.qos.logback.classic.net.SyslogAppender">
       <syslogHost><<your host name>></syslogHost>
       <port>514</port>
       <facility>USER</facility>
       <suffixPattern><<your pattern>></suffixPattern>
      </appender>
      <!-- This will print your access logs in local0 facility-->
      <appender name="LOCAL0" class="ch.qos.logback.classic.net.SyslogAppender">
        <syslogHost><<your host name>></syslogHost>
        <port>514</port>
        <facility>LOCAL0</facility>
        <suffixPattern><<pattern>></suffixPattern>
      </appender>
      
      <Logger name="package path to ApiAccessLogValve" level="INFO" 
          additivity="false">
         <appender-ref ref="LOCAL0" />
      </Logger>
      

    Now you are all set.