5

We are using spring boot framework, generating access logs by embedded tomcat, the format of access logs is following the property below :

server.tomcat.access-log-enabled=true
server.tomcat.access-log-pattern="%h %l %u %t '%r' %s %b %D"
server.tomcat.basedir=/data/logs/Waijule/SchoolService/access

Fortunately, access logs generated succeed, we got a positive result :

"127.0.0.1 - - [01/Mar/2016:11:25:47 +0800] 'POST /school-svc/index-summary HTTP/1.1' 200 127 21"
"127.0.0.1 - - [01/Mar/2016:11:25:47 +0800] 'POST /school-svc/wechat/signature/get HTTP/1.1' 200 238 9"
"127.0.0.1 - - [01/Mar/2016:11:25:47 +0800] 'POST /school-svc/wechat/ticket/get HTTP/1.1' 200 225 148"

To make sure the service healthy, we have kept running health check every 5 seconds, the requests which we want to filter so that we could get clear access logs, health check url is like the sample :

"127.0.0.1 - - [01/Mar/2016:12:04:10 +0800] 'GET /school-svc/isHealth HTTP/1.1' 200 6 104"

How to filter health check requests?

Thanks for help.


According to documentation on access loging, I tried to use conditionIf to solve the problems, in our spring framework, I tried to override customize function in EmbeddedServletContainerCustomizer class so that conditionIf could set up, our realization likes the following sample :

 @Configuration
 public class Application implements EmbeddedServletContainerCustomizer {
     @Override
     public void customize(ConfigurableEmbeddedServletContainer container)
     {
         if (container instanceof TomcatEmbeddedServletContainerFactory)
            {
                log.debug("It is TomcatEmbeddedServletContainerFactory");
                TomcatEmbeddedServletContainerFactory factory = (TomcatEmbeddedServletContainerFactory) container;
                AccessLogValve accessLogValve = new AccessLogValve();                    
                accessLogValve.setConditionIf("ignore");
                factory.addContextValves(accessLogValve);
            }
            else
            {
                log.error("WARNING! this customizer does not support your configured container");
            }
      }    
}

In my comprehension, the next step we need to do is set attribute parameter, so I wrote interceptor on the above of health check controller, realization likes that:

@Component
@Aspect
public class HealthCheckInterceptor
{
    @Before("execution(* com.waijule.home.controller.HealthCheckController.process(..))")
    private void beforeGetHomeDetailByHomeIdWithTry(JoinPoint joinPoint)
    {
        try
        {
            Object[] args = joinPoint.getArgs();
            Prediction.checkTrue(args[0] instanceof HttpServletRequest);
            HttpServletRequest request = (HttpServletRequest) args[0];
            request.setAttribute("ignore", "true");
        }
        catch (Exception e)
        {
            log.error(e.getMessage());
        }
    }
}

In the end, checked if attribute("ignore") of RequestServlet evaluated.

@RestController
@RequestMapping(value = { "/home-svc/isHealth" }, method = { RequestMethod.GET, RequestMethod.HEAD })
public class HealthCheckController
{
    private String HEALTH = "health";

    @RequestMapping
    public String process(HttpServletRequest request)
    {
        log.debug("ignore attribute is {}", request.getAttribute("ignore"));
        return HEALTH;
    }
}

output: ignore attribute is true

However, access informs of health check still be found in access logs:

"127.0.0.1 - - [03/Mar/2016:11:34:00 +0800] 'GET /home-svc/isHealth HTTP/1.1' 200 6 120"

I supposed attribute parameter 'ignore' set up late in the process, when and how to setAttribute for HttpServletRequest?

If our supposition not correct, what makes the operations not work?

Thanks for help.

Shog9
  • 156,901
  • 35
  • 231
  • 235
Ivan
  • 661
  • 1
  • 8
  • 15
  • 1
    Have you read Tomcat's [documentation on access loging](https://tomcat.apache.org/tomcat-8.0-doc/config/valve.html#Access_Log_Valve/Attributes), in particular the three `condition` attributes? That should point you in the right direction. – Andy Wilkinson Mar 01 '16 at 10:17
  • @AndyWilkinson, I followed you proposal, met some difficulties. I recorded it in the next module, focus on the first answer. Thanks. – Ivan Mar 03 '16 at 03:46
  • I tried the exact steps mentioned and it worked perfectly. I think there is a typo in solution to use setConditionIf instead of setConditionUnless. Even after using setConditionUnless, I didn't need the interceptor and I could set the attribute in the method call itself. – Atul May 21 '18 at 09:35
  • Also instead of creating new AccessLogValue, I fetched existing one and changed the property of it. This helps to ensure I can set values from application properties also. – Atul May 21 '18 at 09:37

2 Answers2

0

As suggested by the response https://stackoverflow.com/a/55569199/3346298 on this question Exclude certain requests from Tomcat's log, you should use a filter and add this filter to the filterChain instead of adding it by AOP.

For same reason seems like the log/not log feature is checked before the execution of you AOP aspect.

PD: Sorry for the late response

Damian229
  • 482
  • 5
  • 10
0

You can use the condition-unless properties of tomcat to exclude request who contains this attribute with not null value. (doc)

Here is the code, I used with springboot 2.7.

  1. configure tomcat, adding this properties
    server.tomcat.accesslog.enabled=true
    server.tomcat.accesslog.condition-unless=NO_LOG
  1. Create a webfilter and register it in spring. This filter will add the "NO_LOG" attribute for the request who don't need to be log
    @Component
    public class AccessLogFilter implements Filter {
        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
            if (request instanceof HttpServletRequest) {
                String uri = ((HttpServletRequest) request).getRequestURI();
                //detect the uri who dontt need to be log 
                if (uri.startsWith("/actuator")) {
                    //add the "No_LOG" Attribute to request, the value is not important, there only need to be not null
                    request.setAttribute("NO_LOG", "true");
                }
            }
            chain.doFilter(request, response);
        }
    }
Bertrand Cedric
  • 653
  • 6
  • 11