View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements. See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache license, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License. You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the license for the specific language governing permissions and
15   * limitations under the license.
16   */
17  package org.apache.logging.log4j.audit.rest;
18  
19  import java.io.IOException;
20  import java.text.DecimalFormat;
21  import java.util.Enumeration;
22  
23  import javax.servlet.Filter;
24  import javax.servlet.FilterChain;
25  import javax.servlet.FilterConfig;
26  import javax.servlet.ServletException;
27  import javax.servlet.ServletRequest;
28  import javax.servlet.ServletResponse;
29  import javax.servlet.http.HttpServletRequest;
30  import javax.servlet.http.HttpServletResponse;
31  
32  import org.apache.logging.log4j.LogManager;
33  import org.apache.logging.log4j.Logger;
34  import org.apache.logging.log4j.ThreadContext;
35  import org.apache.logging.log4j.audit.request.ChainedMapping;
36  import org.apache.logging.log4j.audit.request.RequestContextMapping;
37  import org.apache.logging.log4j.audit.request.RequestContextMappings;
38  
39  /**
40   * Filter to initialize and clear the RequestContext.
41   */
42  public class RequestContextFilter implements Filter {
43  
44      private static final Logger logger = LogManager.getLogger(RequestContextFilter.class);
45      private final Class<?> requestContextClass;
46      private RequestContextMappings mappings;
47  
48      public RequestContextFilter() {
49          requestContextClass = null;
50      }
51  
52      public RequestContextFilter(Class<?> clazz) {
53          requestContextClass = clazz;
54      }
55  
56      /**
57       * @param filterConfig
58       * @throws ServletException
59       */
60      @Override
61      public void init(FilterConfig filterConfig) throws ServletException {
62          if (requestContextClass != null) {
63              mappings = new RequestContextMappings(requestContextClass);
64          } else {
65              String requestContextClassName = filterConfig.getInitParameter("requestContextClass");
66              if (requestContextClassName == null) {
67                  logger.error("No RequestContext class name was provided");
68                  throw new IllegalArgumentException("No RequestContext class name provided");
69              }
70              mappings = new RequestContextMappings(requestContextClassName);
71          }
72      }
73  
74      /**
75       * Manages the initialization and clearing of the RequestContext.
76       */
77      public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
78              throws IOException, ServletException {
79          if (servletRequest instanceof HttpServletRequest) {
80              HttpServletRequest request = (HttpServletRequest) servletRequest;
81              HttpServletResponse response = (HttpServletResponse) servletResponse;
82              logger.trace("Starting request {}", request.getRequestURI());
83              try {
84                  Enumeration<String> headers = request.getHeaderNames();
85                  while (headers.hasMoreElements()) {
86                      String name = headers.nextElement();
87                      RequestContextMapping mapping = mappings.getMappingByHeader(name);
88                      logger.debug("Got Mapping:{} for Header:{}", mapping, name);
89                      if (mapping != null) {
90                          if (mapping.isChained()) {
91                              ThreadContext.put(mapping.getChainKey(), request.getHeader(name));
92                              logger.debug("Setting Context Key:{} with value:{}", mapping.getChainKey(), request.getHeader(name));
93                              String value = ((ChainedMapping)mapping).getSupplier().get();
94                              ThreadContext.put(mapping.getFieldName(), value);
95                              logger.debug("Setting Context Key:{} with value:{}", mapping.getFieldName(), value);
96                          } else {
97                              ThreadContext.put(mapping.getFieldName(), request.getHeader(name));
98                              logger.debug("Setting Context Key:{} with value:{}", mapping.getFieldName(), request.getHeader(name));
99                          }
100                     }
101                 }
102                 long start = 0;
103                 if (logger.isTraceEnabled()) {
104                     start = System.nanoTime();
105                 }
106                 filterChain.doFilter(servletRequest, servletResponse);
107                 if (logger.isTraceEnabled()) {
108                     long elapsed = System.nanoTime() - start;
109                     StringBuilder sb = new StringBuilder("Request ").append(request.getRequestURI()).append(" completed in ");
110                     ElapsedUtil.addElapsed(elapsed, sb);
111                     logger.trace(sb.toString());
112                 }
113             } catch (Throwable e) {
114                 logger.error("Application cascaded error", e);
115                 response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
116             } finally {
117                 ThreadContext.clearMap();
118             }
119         }
120     }
121 
122     public void destroy() {
123     }
124 }