Skip to content

Commit 297072a

Browse files
Migrate RequestLoggingFilter to new implementation
The RequestLoggingFilter is the originally provided filter of the module. Goal of the refactoring was, to provide its functionality by several stand-alone filters. To enable backwards-compatibility and ease of use, the original filter was reimplemented as composite filter. This can be used as an example for custom filter configurations and implementations.
1 parent 8ceba01 commit 297072a

File tree

6 files changed

+72
-312
lines changed

6 files changed

+72
-312
lines changed

cf-java-logging-support-servlet/src/main/java/com/sap/hcp/cf/logging/servlet/filter/CorrelationIdFilter.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.sap.hcp.cf.logging.servlet.filter;
22

3+
import static com.sap.hcp.cf.logging.common.customfields.CustomField.customField;
4+
35
import java.util.UUID;
46

57
import javax.servlet.http.HttpServletRequest;
@@ -27,7 +29,7 @@ public class CorrelationIdFilter extends AbstractLoggingFilter {
2729
public CorrelationIdFilter() {
2830
this(HttpHeaders.CORRELATION_ID);
2931
}
30-
32+
3133
public CorrelationIdFilter(HttpHeader correlationHeader) {
3234
this.correlationHeader = correlationHeader;
3335
}
@@ -43,7 +45,10 @@ private String determineCorrelationId(HttpServletRequest request) {
4345
String correlationId = HttpHeaderUtilities.getHeaderValue(request, correlationHeader);
4446
if (correlationId == null || correlationId.isEmpty() || correlationId.equals(Defaults.UNKNOWN)) {
4547
correlationId = String.valueOf(UUID.randomUUID());
46-
LOG.debug("Generated new correlation-id <{}>", correlationId);
48+
// add correlation-id as custom field, since it is added to MDC only
49+
// in the next step
50+
LOG.debug("Generated new correlation-id <{}>", correlationId, customField(correlationHeader.getField(),
51+
correlationId));
4752
}
4853
return correlationId;
4954
}
@@ -53,7 +58,7 @@ private void addCorrelationIdHeader(HttpServletResponse response, String correla
5358
response.setHeader(correlationHeader.getName(), correlationId);
5459
}
5560
}
56-
61+
5762
@Override
5863
protected void postProcess(HttpServletRequest request, HttpServletResponse response) {
5964
LogContext.remove(correlationHeader.getField());

cf-java-logging-support-servlet/src/main/java/com/sap/hcp/cf/logging/servlet/filter/RequestLoggingBaseFilter.java

Lines changed: 0 additions & 172 deletions
This file was deleted.
Lines changed: 30 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,16 @@
11
package com.sap.hcp.cf.logging.servlet.filter;
22

3-
import java.io.IOException;
4-
import java.util.Optional;
5-
6-
import javax.servlet.FilterChain;
7-
import javax.servlet.ServletException;
8-
import javax.servlet.http.HttpServletRequest;
9-
import javax.servlet.http.HttpServletResponse;
10-
11-
import org.apache.commons.lang3.concurrent.ConcurrentException;
12-
import org.apache.commons.lang3.concurrent.ConcurrentInitializer;
13-
import org.apache.commons.lang3.concurrent.LazyInitializer;
14-
import org.slf4j.Logger;
15-
import org.slf4j.LoggerFactory;
16-
17-
import com.sap.hcp.cf.logging.servlet.dynlog.DynamicLogLevelConfiguration;
18-
import com.sap.hcp.cf.logging.servlet.dynlog.DynLogEnvironment;
19-
import com.sap.hcp.cf.logging.servlet.dynlog.DynamicLogLevelProcessor;
3+
import org.slf4j.MDC;
204

215
/**
226
* <p>
23-
* A simple servlet filter that logs HTTP request processing info. It will read
24-
* several HTTP Headers and store them in the SLF4J MDC, so that all log
25-
* messages created during request handling will have those additional fields.
26-
* It will also instrument the request to generate a request log containing
27-
* metrics such as request and response sizes and response time. This
28-
* instrumentation can be disabled by denying logs from {@link RequestLogger}
29-
* with marker "request".
7+
* THe {@link RequestLoggingFilter} extracts information from HTTP requests and
8+
* can create request logs. It will read several HTTP Headers and store them in
9+
* the SLF4J MDC, so that all log messages created during request handling will
10+
* have those additional fields. It will also instrument the request to generate
11+
* a request log containing metrics such as request and response sizes and
12+
* response time. This instrumentation can be disabled by denying logs from
13+
* {@link RequestLogger} with marker "request".
3014
* </p>
3115
* <p>
3216
* This filter will generate a correlation id, from the HTTP header
@@ -37,116 +21,37 @@
3721
* <p>
3822
* This filter supports dynamic log levels activated by JWT tokens in HTTP
3923
* headers. Setup and processing of these tokens can be changed with own
40-
* implementations of {@link DynLogEnvironment} and
41-
* {@link DynamicLogLevelProcessor}. For integration provide a subclass of
42-
* {@link RequestLoggingFilter} and overwrite
43-
* {@link RequestLoggingFilter#getDynLogConfiguration()} and
44-
* {@link RequestLoggingFilter#getDynLogLevelProcessor()}.
24+
* implementations of {@link DynamicLogLevelFilter}.
4525
* </p>
4626
* <p>
4727
* To use the filter, it needs to be added to the servlet configuration. It has
48-
* a default constructor to support web.xml configuration. There are several
49-
* other constructors that support some customization, in case dynamic
50-
* configuration (e.g. Spring Boot) is used. You can add further customization
51-
* by subclassing the filter and overwrite its methods.
28+
* a default constructor to support web.xml configuration. You can customize the
29+
* filter by creating your own subclass of {@link CompositeFilter} and mix and
30+
* match any of the provided filters and add your own implementation:
31+
* <ul>
32+
* <li>{@link AddVcapEnvironmentToLogContextFilter} provide application metadata
33+
* (app_id, app_name, ...) from environment</li>
34+
* <li>{@link AddHttpHeadersToLogContextFilter} provides certain HTTP headers to
35+
* {@link MDC}</li>
36+
* <li>{@link CorrelationIdFilter} extracts "X-CorrelationId" HTTP header or
37+
* generates new to add to {@link MDC}</li>
38+
* <li>{@link DynamicLogLevelFilter} supports JWT based dynamic changes of log
39+
* level per request</li>
40+
* <li>{@link GenerateRequestLogFilter} instruments the request to generate the
41+
* final request log</li>
42+
* </ul>
5243
* </p>
5344
*/
54-
public class RequestLoggingFilter extends RequestLoggingBaseFilter {
55-
56-
private static final Logger LOG = LoggerFactory.getLogger(RequestLoggingFilter.class);
57-
58-
public static final String LOG_PROVIDER = RequestLoggingBaseFilter.LOG_PROVIDER;
59-
public static final String WRAP_RESPONSE_INIT_PARAM = RequestLoggingBaseFilter.WRAP_REQUEST_INIT_PARAM;
60-
public static final String WRAP_REQUEST_INIT_PARAM = RequestLoggingBaseFilter.WRAP_REQUEST_INIT_PARAM;
61-
62-
private ConcurrentInitializer<DynamicLogLevelConfiguration> dynLogEnvironment;
63-
private ConcurrentInitializer<DynamicLogLevelProcessor> dynamicLogLevelProcessor;
45+
public class RequestLoggingFilter extends CompositeFilter {
6446

6547
public RequestLoggingFilter() {
66-
this(createDefaultRequestRecordFactory());
48+
super(new AddVcapEnvironmentToLogContextFilter(), new AddHttpHeadersToLogContextFilter(),
49+
new CorrelationIdFilter(), new DynamicLogLevelFilter(), new GenerateRequestLogFilter());
6750
}
6851

6952
public RequestLoggingFilter(RequestRecordFactory requestRecordFactory) {
70-
this(requestRecordFactory, createDefaultDynLogEnvironment());
71-
}
72-
73-
private static ConcurrentInitializer<DynamicLogLevelConfiguration> createDefaultDynLogEnvironment() {
74-
DynLogEnvironment environment = new DynLogEnvironment();
75-
return () -> environment;
76-
}
77-
78-
public RequestLoggingFilter(ConcurrentInitializer<DynamicLogLevelConfiguration> dynLogEnvironment) {
79-
this(createDefaultRequestRecordFactory(), dynLogEnvironment);
80-
}
81-
82-
public RequestLoggingFilter(RequestRecordFactory requestRecordFactory,
83-
ConcurrentInitializer<DynamicLogLevelConfiguration> dynLogEnvironment) {
84-
super(requestRecordFactory);
85-
this.dynLogEnvironment = dynLogEnvironment;
86-
this.dynamicLogLevelProcessor = new LazyInitializer<DynamicLogLevelProcessor>() {
87-
88-
@Override
89-
protected DynamicLogLevelProcessor initialize() throws ConcurrentException {
90-
return getDynLogConfiguration().map(DynamicLogLevelConfiguration::getRsaPublicKey).map(DynamicLogLevelProcessor::new)
91-
.get();
92-
}
93-
};
94-
}
95-
96-
public RequestLoggingFilter(ConcurrentInitializer<DynamicLogLevelConfiguration> dynLogEnvironment,
97-
ConcurrentInitializer<DynamicLogLevelProcessor> dynamicLogLevelProcessor) {
98-
this(createDefaultRequestRecordFactory(), dynLogEnvironment, dynamicLogLevelProcessor);
53+
super(new AddVcapEnvironmentToLogContextFilter(), new AddHttpHeadersToLogContextFilter(),
54+
new CorrelationIdFilter(), new DynamicLogLevelFilter(), new GenerateRequestLogFilter(
55+
requestRecordFactory));
9956
}
100-
101-
public RequestLoggingFilter(RequestRecordFactory requestRecordFactory,
102-
ConcurrentInitializer<DynamicLogLevelConfiguration> dynLogEnvironment,
103-
ConcurrentInitializer<DynamicLogLevelProcessor> dynamicLogLevelProcessor) {
104-
super(requestRecordFactory);
105-
this.dynLogEnvironment = dynLogEnvironment;
106-
this.dynamicLogLevelProcessor = dynamicLogLevelProcessor;
107-
}
108-
109-
protected Optional<DynamicLogLevelConfiguration> getDynLogConfiguration() {
110-
try {
111-
return Optional.of(dynLogEnvironment.get());
112-
} catch (ConcurrentException cause) {
113-
LOG.debug("Cannot initialize dynamic log level environment. Will continue without this feature", cause);
114-
return Optional.empty();
115-
}
116-
}
117-
118-
protected Optional<DynamicLogLevelProcessor> getDynLogLevelProcessor() {
119-
try {
120-
if (getDynLogConfiguration().map(DynamicLogLevelConfiguration::getRsaPublicKey).isPresent()) {
121-
return Optional.of(dynamicLogLevelProcessor.get());
122-
}
123-
} catch (ConcurrentException cause) {
124-
LOG.debug("Cannot initialize dynamic log level processor. Will continue without this feature", cause);
125-
}
126-
return Optional.empty();
127-
}
128-
129-
@Override
130-
protected void doFilterRequest(HttpServletRequest httpRequest, HttpServletResponse httpResponse, FilterChain chain)
131-
throws IOException,
132-
ServletException {
133-
activateDynamicLogLevels(httpRequest);
134-
try {
135-
super.doFilterRequest(httpRequest, httpResponse, chain);
136-
} finally {
137-
deactivateDynamicLogLevels();
138-
}
139-
}
140-
141-
private void activateDynamicLogLevels(HttpServletRequest httpRequest) {
142-
getDynLogLevelProcessor().ifPresent(processor -> {
143-
getDynLogConfiguration().map(env -> env.getDynLogHeaderValue(httpRequest)).ifPresent(
144-
processor::copyDynamicLogLevelToMDC);
145-
});
146-
}
147-
148-
private void deactivateDynamicLogLevels() {
149-
getDynLogLevelProcessor().ifPresent(DynamicLogLevelProcessor::removeDynamicLogLevelFromMDC);
150-
}
151-
15257
}

0 commit comments

Comments
 (0)