diff --git a/README.md b/README.md index 53939952..94aacb29 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ All in all, you should do the following: * adjust your logging configuration accordingly. -Say, you want to make use of the *servlet filter* feature, then you need to add the following dependency to your POM with property `cf-logging-version` referring to the latest nexus version (currently `2.1.5`): +Say, you want to make use of the *servlet filter* feature, then you need to add the following dependency to your POM with property `cf-logging-version` referring to the latest nexus version (currently `2.2.0`): ```xml diff --git a/cf-java-logging-support-core/pom.xml b/cf-java-logging-support-core/pom.xml index 60391daf..3a2d56a5 100644 --- a/cf-java-logging-support-core/pom.xml +++ b/cf-java-logging-support-core/pom.xml @@ -32,7 +32,7 @@ com.sap.hcp.cf.logging cf-java-logging-support-parent - 2.1.5 + 2.2.0 ../pom.xml diff --git a/cf-java-logging-support-core/src/main/java/com/sap/hcp/cf/logging/common/RequestRecord.java b/cf-java-logging-support-core/src/main/java/com/sap/hcp/cf/logging/common/RequestRecord.java index 636e76a3..78bb1cde 100644 --- a/cf-java-logging-support-core/src/main/java/com/sap/hcp/cf/logging/common/RequestRecord.java +++ b/cf-java-logging-support-core/src/main/java/com/sap/hcp/cf/logging/common/RequestRecord.java @@ -1,6 +1,5 @@ package com.sap.hcp.cf.logging.common; -import java.io.Closeable; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -39,7 +38,7 @@ * * */ -public class RequestRecord implements Closeable { +public class RequestRecord { /* * -- default values for request fields that are marked as "required" @@ -100,7 +99,6 @@ public RequestRecord(String layerKey, Direction direction) { addTag(Fields.DIRECTION, direction.toString()); setDefaults(); start(); - RequestRecordHolder.add(this); } /** @@ -198,11 +196,6 @@ public long stop() { return endMs; } - @Override - public void close() { - RequestRecordHolder.remove(this); - } - @Override public String toString() { /* diff --git a/cf-java-logging-support-core/src/main/java/com/sap/hcp/cf/logging/common/RequestRecordHolder.java b/cf-java-logging-support-core/src/main/java/com/sap/hcp/cf/logging/common/RequestRecordHolder.java deleted file mode 100644 index d286b081..00000000 --- a/cf-java-logging-support-core/src/main/java/com/sap/hcp/cf/logging/common/RequestRecordHolder.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.sap.hcp.cf.logging.common; - -import java.util.HashSet; -import java.util.Set; - -/** - * As we need to keep track of nested calls we use thread local storage to - * manage a set of RequestRecord instances that are "in flight" for individual - * thread. - * - * Upon removal of a record, we check whether that one is the last one so that - * we can clear context information. - * - */ -public class RequestRecordHolder { - - private static final ThreadLocal> RECORD_SETS = new ThreadLocal>(); - - public static void add(RequestRecord rr) { - if (rr == null) { - return; - } - Set recSet = RECORD_SETS.get(); - if (recSet == null) { - recSet = new HashSet(); - RECORD_SETS.set(recSet); - } - recSet.add(rr); - } - - public static void remove(RequestRecord rr) { - if (rr == null) { - return; - } - Set recSet = RECORD_SETS.get(); - if (recSet.remove(rr)) { - /* - * -- time to clean up if this was the last - */ - if (recSet.isEmpty()) { - rr.resetContext(); - } - } - } -} diff --git a/cf-java-logging-support-core/src/test/java/com/sap/hcp/cf/logging/common/RequestRecordConfiguratorTest.java b/cf-java-logging-support-core/src/test/java/com/sap/hcp/cf/logging/common/RequestRecordConfiguratorTest.java index c704a4e2..b7b2c6bc 100644 --- a/cf-java-logging-support-core/src/test/java/com/sap/hcp/cf/logging/common/RequestRecordConfiguratorTest.java +++ b/cf-java-logging-support-core/src/test/java/com/sap/hcp/cf/logging/common/RequestRecordConfiguratorTest.java @@ -20,7 +20,6 @@ public void testAddingSingleActivatedOptionalTagToRequestRecord() throws JSONObj String tag = "TestTag"; to(requestRecord).addOptionalTag(canBeLogged, key, tag); - requestRecord.close(); assertEquals(tag, getFieldFromRequestRecord(requestRecord, key)); } @@ -33,7 +32,6 @@ public void testAddingSingleForbiddenOptionalTagToRequestRecord() throws JSONObj String tag = "TestTag"; to(requestRecord).addOptionalTag(canBeLogged, key, tag); - requestRecord.close(); assertEquals(Defaults.REDACTED, getFieldFromRequestRecord(requestRecord, key)); } @@ -46,7 +44,6 @@ public void testAddingSingleForbiddenOptionalNullTagToRequestRecord() throws JSO String tag = Defaults.UNKNOWN; to(requestRecord).addOptionalTag(canBeLogged, key, tag); - requestRecord.close(); assertEquals(Defaults.UNKNOWN, getFieldFromRequestRecord(requestRecord, key)); } @@ -59,7 +56,6 @@ public void testAddingSingleActivatedOptionalNullTagToRequestRecord() throws JSO String tag = Defaults.UNKNOWN; to(requestRecord).addOptionalTag(canBeLogged, key, tag); - requestRecord.close(); assertEquals(Defaults.UNKNOWN, getFieldFromRequestRecord(requestRecord, key)); } diff --git a/cf-java-logging-support-core/src/test/java/com/sap/hcp/cf/logging/common/converter/TestJsonMessageConverter.java b/cf-java-logging-support-core/src/test/java/com/sap/hcp/cf/logging/common/converter/TestJsonMessageConverter.java index d5d808f0..e135da45 100644 --- a/cf-java-logging-support-core/src/test/java/com/sap/hcp/cf/logging/common/converter/TestJsonMessageConverter.java +++ b/cf-java-logging-support-core/src/test/java/com/sap/hcp/cf/logging/common/converter/TestJsonMessageConverter.java @@ -58,7 +58,6 @@ public void testLogRecordMsgNotFlattened() { RequestRecord lrec = new RequestRecord(LOG_PROVIDER); String lmsg = lrec.toString(); assertThat(formatMsg(jmc, lmsg), is(lmsg)); - lrec.close(); } @Test @@ -68,7 +67,6 @@ public void testLogRecordMsgFlattened() { RequestRecord lrec = new RequestRecord(LOG_PROVIDER); String lmsg = lrec.toString(); assertThat(formatMsg(jmc, lmsg), is(lmsg.substring(1, lmsg.length() - 1))); - lrec.close(); } @Test diff --git a/cf-java-logging-support-jersey/pom.xml b/cf-java-logging-support-jersey/pom.xml index 10552e1d..a50fc3e4 100644 --- a/cf-java-logging-support-jersey/pom.xml +++ b/cf-java-logging-support-jersey/pom.xml @@ -9,7 +9,7 @@ ../pom.xml com.sap.hcp.cf.logging cf-java-logging-support-parent - 2.1.5 + 2.2.0 cf-java-logging-support-jersey diff --git a/cf-java-logging-support-jersey/src/main/java/com/sap/hcp/cf/logging/jersey/filter/ResponseHandler.java b/cf-java-logging-support-jersey/src/main/java/com/sap/hcp/cf/logging/jersey/filter/ResponseHandler.java index dd7d726a..4a79c4f8 100644 --- a/cf-java-logging-support-jersey/src/main/java/com/sap/hcp/cf/logging/jersey/filter/ResponseHandler.java +++ b/cf-java-logging-support-jersey/src/main/java/com/sap/hcp/cf/logging/jersey/filter/ResponseHandler.java @@ -20,10 +20,6 @@ public void handle(ResponseContextAdapter responseContext, RequestRecord rr) { rr.addValue(Fields.RESPONSE_STATUS, new LongValue(responseContext.getStatus())); rr.stop(); LOGGER.info(Markers.REQUEST_MARKER, "{}", rr); - /* - * -- close this instance - */ - rr.close(); } else { LOGGER.error("No record found to handle response {}", responseContext); } diff --git a/cf-java-logging-support-log4j2/pom.xml b/cf-java-logging-support-log4j2/pom.xml index 2b28aff5..2982900b 100644 --- a/cf-java-logging-support-log4j2/pom.xml +++ b/cf-java-logging-support-log4j2/pom.xml @@ -11,7 +11,7 @@ ../pom.xml com.sap.hcp.cf.logging cf-java-logging-support-parent - 2.1.5 + 2.2.0 diff --git a/cf-java-logging-support-log4j2/src/test/java/com/sap/hcp/cf/log4j2/converter/TestJsonMessageConverter.java b/cf-java-logging-support-log4j2/src/test/java/com/sap/hcp/cf/log4j2/converter/TestJsonMessageConverter.java index 4f09b9b1..98dec5db 100644 --- a/cf-java-logging-support-log4j2/src/test/java/com/sap/hcp/cf/log4j2/converter/TestJsonMessageConverter.java +++ b/cf-java-logging-support-log4j2/src/test/java/com/sap/hcp/cf/log4j2/converter/TestJsonMessageConverter.java @@ -56,7 +56,6 @@ public void testLogRecordMsgNotFlattened() { RequestRecord lrec = new RequestRecord(LOG_PROVIDER); String lmsg = lrec.toString(); assertThat(format(jmc, makeEvent(lmsg, NO_ARGS)), is(lmsg)); - lrec.close(); } @Test @@ -65,7 +64,6 @@ public void testLogRecordMsgFlattened() { RequestRecord lrec = new RequestRecord(LOG_PROVIDER); String lmsg = lrec.toString(); assertThat(format(jmc, makeEvent(lmsg, NO_ARGS)), is(lmsg.substring(1, lmsg.length() - 1))); - lrec.close(); } @Test diff --git a/cf-java-logging-support-logback/pom.xml b/cf-java-logging-support-logback/pom.xml index 9a6f9ec5..7711472e 100644 --- a/cf-java-logging-support-logback/pom.xml +++ b/cf-java-logging-support-logback/pom.xml @@ -10,7 +10,7 @@ ../pom.xml com.sap.hcp.cf.logging cf-java-logging-support-parent - 2.1.5 + 2.2.0 diff --git a/cf-java-logging-support-logback/src/main/java/com/sap/hcp/cf/logback/perf/PerfTestRequestRecord.java b/cf-java-logging-support-logback/src/main/java/com/sap/hcp/cf/logback/perf/PerfTestRequestRecord.java index f9d24b7b..8446a85a 100644 --- a/cf-java-logging-support-logback/src/main/java/com/sap/hcp/cf/logback/perf/PerfTestRequestRecord.java +++ b/cf-java-logging-support-logback/src/main/java/com/sap/hcp/cf/logback/perf/PerfTestRequestRecord.java @@ -12,44 +12,39 @@ public class PerfTestRequestRecord { - private static final int DEF_ITERATIONS = 1000000; - private final int iterations; - private static final Logger LOGGER = LoggerFactory.getLogger(PerfTestRequestRecord.class); - - public PerfTestRequestRecord(int iterations) { - if (iterations > 0) { - this.iterations = iterations; - } else { - this.iterations = DEF_ITERATIONS; - } - } - - public static void main(String[] args) { - new PerfTestRequestRecord(DEF_ITERATIONS).run(args); - } - - private void run(String[] args) { - long start = System.nanoTime(); - PrintStream defOut = System.out; - System.setOut(new PrintStream(new OutputStream() { - - @Override - public void write(int b) throws IOException { - } - })); - for (int i = 0; i < iterations; i++) { - RequestRecord rrec = null; - try { - rrec = new RequestRecord(PerfTestRequestRecord.class.getName()); - LOGGER.info(Markers.REQUEST_MARKER, rrec.toString()); - } finally { - rrec.close(); - } - } - double delta = (System.nanoTime() - start) / 1000000.0; - System.setOut(defOut); - System.out.println("Writing " + iterations + " records took " + delta + " msecs, " + delta / iterations + - " msecs per record"); - } + private static final int DEF_ITERATIONS = 1000000; + private final int iterations; + private static final Logger LOGGER = LoggerFactory.getLogger(PerfTestRequestRecord.class); + + public PerfTestRequestRecord(int iterations) { + if (iterations > 0) { + this.iterations = iterations; + } else { + this.iterations = DEF_ITERATIONS; + } + } + + public static void main(String[] args) { + new PerfTestRequestRecord(DEF_ITERATIONS).run(args); + } + + private void run(String[] args) { + long start = System.nanoTime(); + PrintStream defOut = System.out; + System.setOut(new PrintStream(new OutputStream() { + + @Override + public void write(int b) throws IOException { + } + })); + for (int i = 0; i < iterations; i++) { + RequestRecord rrec = new RequestRecord(PerfTestRequestRecord.class.getName()); + LOGGER.info(Markers.REQUEST_MARKER, rrec.toString()); + } + double delta = (System.nanoTime() - start) / 1000000.0; + System.setOut(defOut); + System.out.println("Writing " + iterations + " records took " + delta + " msecs, " + delta / iterations + + " msecs per record"); + } } diff --git a/cf-java-logging-support-logback/src/test/java/com/sap/hcp/cf/logback/converter/TestJsonMessageConverter.java b/cf-java-logging-support-logback/src/test/java/com/sap/hcp/cf/logback/converter/TestJsonMessageConverter.java index c9fbdb17..af649988 100644 --- a/cf-java-logging-support-logback/src/test/java/com/sap/hcp/cf/logback/converter/TestJsonMessageConverter.java +++ b/cf-java-logging-support-logback/src/test/java/com/sap/hcp/cf/logback/converter/TestJsonMessageConverter.java @@ -66,7 +66,6 @@ public void testLogRecordMsgNotFlattened() { RequestRecord lrec = new RequestRecord(LOG_PROVIDER); String lmsg = lrec.toString(); assertThat(jmc.convert(makeEvent(lmsg, NO_ARGS)), is(lmsg)); - lrec.close(); } @Test @@ -77,7 +76,6 @@ public void testLogRecordMsgFlattened() { RequestRecord lrec = new RequestRecord(LOG_PROVIDER); String lmsg = lrec.toString(); assertThat(jmc.convert(makeEvent(lmsg, NO_ARGS)), is(lmsg.substring(1, lmsg.length() - 1))); - lrec.close(); } @Test diff --git a/cf-java-logging-support-servlet/pom.xml b/cf-java-logging-support-servlet/pom.xml index db120faf..d340c655 100644 --- a/cf-java-logging-support-servlet/pom.xml +++ b/cf-java-logging-support-servlet/pom.xml @@ -9,7 +9,7 @@ com.sap.hcp.cf.logging cf-java-logging-support-parent - 2.1.5 + 2.2.0 ../pom.xml diff --git a/cf-java-logging-support-servlet/src/main/java/com/sap/hcp/cf/logging/servlet/filter/LoggingAsyncContextImpl.java b/cf-java-logging-support-servlet/src/main/java/com/sap/hcp/cf/logging/servlet/filter/LoggingAsyncContextImpl.java new file mode 100644 index 00000000..2809320a --- /dev/null +++ b/cf-java-logging-support-servlet/src/main/java/com/sap/hcp/cf/logging/servlet/filter/LoggingAsyncContextImpl.java @@ -0,0 +1,162 @@ +package com.sap.hcp.cf.logging.servlet.filter; + +import java.io.IOException; +import java.util.Collections; +import java.util.Map; + +import javax.servlet.AsyncContext; +import javax.servlet.AsyncEvent; +import javax.servlet.AsyncListener; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.slf4j.MDC; + +public class LoggingAsyncContextImpl implements AsyncContext { + + private AsyncContext asyncContext; + + public LoggingAsyncContextImpl(AsyncContext asyncContext, final RequestLoggingVisitor loggingVisitor) { + this.asyncContext = asyncContext; + asyncContext.addListener(new AsyncListener() { + + @Override + public void onTimeout(AsyncEvent event) throws IOException { + generateLog(loggingVisitor); + } + + private void generateLog(final RequestLoggingVisitor loggingVisitor) { + ServletRequest request = getRequest(); + ServletResponse response = getResponse(); + if (request instanceof HttpServletRequest && response instanceof HttpServletResponse) { + HttpServletRequest httpRequest = (HttpServletRequest) request; + HttpServletResponse httpResponse = (HttpServletResponse) response; + Map contextMap = getContextMap(); + Map currentContextMap = MDC.getCopyOfContextMap(); + try { + MDC.setContextMap(contextMap); + loggingVisitor.logRequest(httpRequest, httpResponse); + } finally { + if (currentContextMap != null) { + MDC.setContextMap(currentContextMap); + } + } + } + } + + + @Override + public void onStartAsync(AsyncEvent event) throws IOException { + } + + @Override + public void onError(AsyncEvent event) throws IOException { + generateLog(loggingVisitor); + } + + @Override + public void onComplete(AsyncEvent event) throws IOException { + generateLog(loggingVisitor); + } + }); + } + + private Map getContextMap() { + try { + @SuppressWarnings("unchecked") + Map fromRequest = (Map) getRequest().getAttribute(MDC.class.getName()); + return fromRequest != null ? fromRequest : Collections.emptyMap(); + } catch (ClassCastException ignored) { + return Collections.emptyMap(); + } + } + + @Override + public void start(Runnable run) { + try { + Map contextMap = getContextMap(); + asyncContext.start(new Runnable() { + + @Override + public void run() { + Map currentContextMap = MDC.getCopyOfContextMap(); + try { + MDC.setContextMap(contextMap); + run.run(); + } finally { + if (currentContextMap != null) { + MDC.setContextMap(currentContextMap); + } + } + } + }); + } catch (ClassCastException ignored) { + asyncContext.start(run); + } + } + + @Override + public ServletRequest getRequest() { + return asyncContext.getRequest(); + } + + @Override + public ServletResponse getResponse() { + return asyncContext.getResponse(); + } + + @Override + public boolean hasOriginalRequestAndResponse() { + return asyncContext.hasOriginalRequestAndResponse(); + } + + @Override + public void dispatch() { + asyncContext.dispatch(); + } + + @Override + public void dispatch(String path) { + asyncContext.dispatch(path); + } + + @Override + public void dispatch(ServletContext context, String path) { + asyncContext.dispatch(context, path); + } + + @Override + public void complete() { + asyncContext.complete(); + } + + @Override + public void addListener(AsyncListener listener) { + asyncContext.addListener(listener); + } + + @Override + public void addListener(AsyncListener listener, ServletRequest servletRequest, ServletResponse servletResponse) { + asyncContext.addListener(listener, servletRequest, servletResponse); + } + + @Override + public T createListener(Class clazz) throws ServletException { + return asyncContext.createListener(clazz); + } + + @Override + public void setTimeout(long timeout) { + asyncContext.setTimeout(timeout); + } + + @Override + public long getTimeout() { + return asyncContext.getTimeout(); + } + +} diff --git a/cf-java-logging-support-servlet/src/main/java/com/sap/hcp/cf/logging/servlet/filter/LoggingContextRequestWrapper.java b/cf-java-logging-support-servlet/src/main/java/com/sap/hcp/cf/logging/servlet/filter/LoggingContextRequestWrapper.java new file mode 100644 index 00000000..d5b1f124 --- /dev/null +++ b/cf-java-logging-support-servlet/src/main/java/com/sap/hcp/cf/logging/servlet/filter/LoggingContextRequestWrapper.java @@ -0,0 +1,28 @@ +package com.sap.hcp.cf.logging.servlet.filter; + +import javax.servlet.AsyncContext; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; + +public class LoggingContextRequestWrapper extends HttpServletRequestWrapper { + + private RequestLoggingVisitor loggingVisitor; + + public LoggingContextRequestWrapper(HttpServletRequest request, RequestLoggingVisitor loggingVisitor) { + super(request); + this.loggingVisitor = loggingVisitor; + } + + @Override + public AsyncContext startAsync() throws IllegalStateException { + return new LoggingAsyncContextImpl(super.startAsync(), loggingVisitor); + } + + @Override + public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse) + throws IllegalStateException { + return new LoggingAsyncContextImpl(super.startAsync(servletRequest, servletResponse), loggingVisitor); + } +} diff --git a/cf-java-logging-support-servlet/src/main/java/com/sap/hcp/cf/logging/servlet/filter/RequestLoggingFilter.java b/cf-java-logging-support-servlet/src/main/java/com/sap/hcp/cf/logging/servlet/filter/RequestLoggingFilter.java index 39fdd6c6..7aaa35fb 100644 --- a/cf-java-logging-support-servlet/src/main/java/com/sap/hcp/cf/logging/servlet/filter/RequestLoggingFilter.java +++ b/cf-java-logging-support-servlet/src/main/java/com/sap/hcp/cf/logging/servlet/filter/RequestLoggingFilter.java @@ -13,8 +13,6 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.slf4j.MDC; import com.sap.hcp.cf.logging.common.Defaults; @@ -22,8 +20,6 @@ import com.sap.hcp.cf.logging.common.HttpHeaders; import com.sap.hcp.cf.logging.common.LogContext; import com.sap.hcp.cf.logging.common.LogOptionalFieldsSettings; -import com.sap.hcp.cf.logging.common.LongValue; -import com.sap.hcp.cf.logging.common.Markers; import com.sap.hcp.cf.logging.common.RequestRecord; import com.sap.hcp.cf.logging.servlet.dynlog.DynLogEnvironment; import com.sap.hcp.cf.logging.servlet.dynlog.DynamicLogLevelProcessor; @@ -34,163 +30,143 @@ */ public class RequestLoggingFilter implements Filter { - private static final Logger LOGGER = LoggerFactory.getLogger(RequestLoggingFilter.class); - public static final String LOG_PROVIDER = "[SERVLET]"; - public static final String WRAP_RESPONSE_INIT_PARAM = "wrapResponse"; - public static final String WRAP_REQUEST_INIT_PARAM = "wrapRequest"; - - private boolean wrapResponse = true; - private boolean wrapRequest = true; - private DynLogEnvironment dynLogEnvironment; - private DynamicLogLevelProcessor dynamicLogLevelProcessor; - protected LogOptionalFieldsSettings logOptionalFieldsSettings; - - public RequestLoggingFilter() { - String invokingClass = this.getClass().getName().toString(); - logOptionalFieldsSettings = new LogOptionalFieldsSettings(invokingClass); - dynLogEnvironment = new DynLogEnvironment(); - if (dynLogEnvironment.getRsaPublicKey() != null) { - dynamicLogLevelProcessor = new DynamicLogLevelProcessor(dynLogEnvironment); - } - } - - @Override - public void init(FilterConfig filterConfig) throws ServletException { - String value = filterConfig.getInitParameter(WRAP_RESPONSE_INIT_PARAM); - if (value != null && "false".equalsIgnoreCase(value)) { - wrapResponse = false; - } - value = filterConfig.getInitParameter(WRAP_REQUEST_INIT_PARAM); - if (value != null && "false".equalsIgnoreCase(value)) { - wrapRequest = false; - } - } - - @Override - public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, - ServletException { - if (HttpServletRequest.class.isAssignableFrom(request.getClass()) && HttpServletResponse.class.isAssignableFrom( - response.getClass())) { - doFilterRequest((HttpServletRequest) request, (HttpServletResponse) response, chain); - } else { - chain.doFilter(request, response); - } - } - - @Override - public void destroy() { - MDC.clear(); - } - - private void doFilterRequest(HttpServletRequest httpRequest, HttpServletResponse httpResponse, FilterChain chain) - throws IOException, - ServletException { - if (httpRequest.getHeader(dynLogEnvironment.getDynLogHeaderKey()) != null && dynamicLogLevelProcessor != null) { - dynamicLogLevelProcessor.copyDynamicLogLevelToMDC(httpRequest); - } - /* - * -- make sure correlation id is read from headers - */ - LogContext.initializeContext(getCorrelationIdFromHeader(httpRequest)); - - RequestRecord rr = null; - try { - rr = new RequestRecord(LOG_PROVIDER); - ContentLengthTrackingResponseWrapper responseWrapper = null; - ContentLengthTrackingRequestWrapper requestWrapper = null; - - /* - * -- we essentially do three things here: -- a) we create a log - * record using our library and log it via STDOUT -- b) keep track - * of certain header fields so that they are available in later - * processing steps -- b) inject a response wrapper to keep track of - * content length (hopefully) - */ - if (wrapResponse) { - responseWrapper = new ContentLengthTrackingResponseWrapper(httpResponse); - } - if (wrapRequest) { - - requestWrapper = new ContentLengthTrackingRequestWrapper(httpRequest); - } - - addHeaders(httpRequest, rr); - - /* -- start measuring right before calling up the filter chain -- */ - rr.start(); - if (chain != null) { - chain.doFilter(requestWrapper != null ? requestWrapper : httpRequest, responseWrapper != null - ? responseWrapper - : httpResponse); - } - rr.stop(); - - if (requestWrapper != null) { - rr.addValue(Fields.REQUEST_SIZE_B, new LongValue(requestWrapper.getContentLength())); - } else { - rr.addValue(Fields.REQUEST_SIZE_B, new LongValue(httpRequest.getContentLength())); - } - String headerValue = httpResponse.getHeader(HttpHeaders.CONTENT_LENGTH); - if (headerValue != null) { - rr.addValue(Fields.RESPONSE_SIZE_B, new LongValue(Long.valueOf(headerValue))); - } else { - if (responseWrapper != null) { - rr.addValue(Fields.RESPONSE_SIZE_B, new LongValue(responseWrapper.getContentLength())); - } - } - rr.addTag(Fields.RESPONSE_CONTENT_TYPE, getValue(httpResponse.getHeader(HttpHeaders.CONTENT_TYPE))); - rr.addValue(Fields.RESPONSE_STATUS, new LongValue(httpResponse.getStatus())); - /* - * -- log info - */ - LOGGER.info(Markers.REQUEST_MARKER, "{}", rr); - /* - * -- close this - */ - } finally { - rr.close(); - - if (dynamicLogLevelProcessor != null) { - dynamicLogLevelProcessor.removeDynamicLogLevelFromMDC(); - } - } - } - - private String getCorrelationIdFromHeader(HttpServletRequest httpRequest) { - String cId = httpRequest.getHeader(HttpHeaders.CORRELATION_ID); - if (cId == null || cId.length() == 0) { - cId = httpRequest.getHeader(HttpHeaders.X_VCAP_REQUEST_ID); - } - return cId; - } - - private String getHeader(HttpServletRequest request, String headerName) { - return getValue(request.getHeader(headerName)); - } - - private String getValue(String value) { - return value != null ? value : Defaults.UNKNOWN; - } - - private void addHeaders(HttpServletRequest request, RequestRecord lrec) { - lrec.addTag(Fields.REQUEST, request.getQueryString() != null ? request.getRequestURI() + "?" + request - .getQueryString() - : request.getRequestURI()); - lrec.addTag(Fields.METHOD, request.getMethod()); - lrec.addTag(Fields.PROTOCOL, getValue(request.getProtocol())); - - boolean isSensitiveConnectionData = logOptionalFieldsSettings.isLogSensitiveConnectionData(); - - to(lrec).addOptionalTag(isSensitiveConnectionData, Fields.REMOTE_IP, getValue(request.getRemoteAddr())) - .addOptionalTag(isSensitiveConnectionData, Fields.REMOTE_HOST, getValue(request.getRemoteHost())) - .addOptionalTag(isSensitiveConnectionData, Fields.REMOTE_PORT, Integer.toString(request - .getRemotePort())) - .addOptionalTag(isSensitiveConnectionData, Fields.X_FORWARDED_FOR, getHeader(request, - HttpHeaders.X_FORWARDED_FOR)) - .addOptionalTag(logOptionalFieldsSettings.isLogRemoteUserField(), Fields.REMOTE_USER, getValue(request - .getRemoteUser())) - .addOptionalTag(logOptionalFieldsSettings.isLogRefererField(), Fields.REFERER, getHeader(request, - HttpHeaders.REFERER)); - lrec.addContextTag(Fields.REQUEST_ID, getHeader(request, HttpHeaders.X_VCAP_REQUEST_ID)); - } + public static final String LOG_PROVIDER = "[SERVLET]"; + public static final String WRAP_RESPONSE_INIT_PARAM = "wrapResponse"; + public static final String WRAP_REQUEST_INIT_PARAM = "wrapRequest"; + + private boolean wrapResponse = true; + private boolean wrapRequest = true; + private DynLogEnvironment dynLogEnvironment; + private DynamicLogLevelProcessor dynamicLogLevelProcessor; + protected LogOptionalFieldsSettings logOptionalFieldsSettings; + + public RequestLoggingFilter() { + String invokingClass = this.getClass().getName().toString(); + logOptionalFieldsSettings = new LogOptionalFieldsSettings(invokingClass); + dynLogEnvironment = new DynLogEnvironment(); + if (dynLogEnvironment.getRsaPublicKey() != null) { + dynamicLogLevelProcessor = new DynamicLogLevelProcessor(dynLogEnvironment); + } + } + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + String value = filterConfig.getInitParameter(WRAP_RESPONSE_INIT_PARAM); + if (value != null && "false".equalsIgnoreCase(value)) { + wrapResponse = false; + } + value = filterConfig.getInitParameter(WRAP_REQUEST_INIT_PARAM); + if (value != null && "false".equalsIgnoreCase(value)) { + wrapRequest = false; + } + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException { + if (HttpServletRequest.class.isAssignableFrom(request.getClass()) + && HttpServletResponse.class.isAssignableFrom(response.getClass())) { + doFilterRequest((HttpServletRequest) request, (HttpServletResponse) response, chain); + } else { + chain.doFilter(request, response); + } + } + + @Override + public void destroy() { + MDC.clear(); + } + + private void doFilterRequest(HttpServletRequest httpRequest, HttpServletResponse httpResponse, FilterChain chain) + throws IOException, ServletException { + if (httpRequest.getHeader(dynLogEnvironment.getDynLogHeaderKey()) != null && dynamicLogLevelProcessor != null) { + dynamicLogLevelProcessor.copyDynamicLogLevelToMDC(httpRequest); + } + /* + * -- make sure correlation id is read from headers + */ + LogContext.initializeContext(getCorrelationIdFromHeader(httpRequest)); + + try { + RequestRecord rr = new RequestRecord(LOG_PROVIDER); + ContentLengthTrackingResponseWrapper responseWrapper = null; + ContentLengthTrackingRequestWrapper requestWrapper = null; + + /* + * -- we essentially do three things here: -- a) we create a log + * record using our library and log it via STDOUT -- b) keep track + * of certain header fields so that they are available in later + * processing steps -- b) inject a response wrapper to keep track of + * content length (hopefully) + */ + if (wrapResponse) { + responseWrapper = new ContentLengthTrackingResponseWrapper(httpResponse); + } + + RequestLoggingVisitor loggingVisitor = new RequestLoggingVisitor(rr, responseWrapper); + + if (wrapRequest) { + httpRequest = new LoggingContextRequestWrapper(httpRequest, loggingVisitor); + httpRequest = new ContentLengthTrackingRequestWrapper(httpRequest); + } + + addHeaders(httpRequest, rr); + httpRequest.setAttribute(MDC.class.getName(), MDC.getCopyOfContextMap()); + + + /* -- start measuring right before calling up the filter chain -- */ + rr.start(); + if (chain != null) { + chain.doFilter(httpRequest, httpResponse); + } + + if (!httpRequest.isAsyncStarted()) { + loggingVisitor.logRequest(httpRequest, httpResponse); + } + /* + * -- close this + */ + } finally { + if (dynamicLogLevelProcessor != null) { + dynamicLogLevelProcessor.removeDynamicLogLevelFromMDC(); + } + } + } + + private String getCorrelationIdFromHeader(HttpServletRequest httpRequest) { + String cId = httpRequest.getHeader(HttpHeaders.CORRELATION_ID); + if (cId == null || cId.length() == 0) { + cId = httpRequest.getHeader(HttpHeaders.X_VCAP_REQUEST_ID); + } + return cId; + } + + private String getHeader(HttpServletRequest request, String headerName) { + return getValue(request.getHeader(headerName)); + } + + private String getValue(String value) { + return value != null ? value : Defaults.UNKNOWN; + } + + private void addHeaders(HttpServletRequest request, RequestRecord lrec) { + lrec.addTag(Fields.REQUEST, request.getQueryString() != null + ? request.getRequestURI() + "?" + request.getQueryString() : request.getRequestURI()); + lrec.addTag(Fields.METHOD, request.getMethod()); + lrec.addTag(Fields.PROTOCOL, getValue(request.getProtocol())); + + boolean isSensitiveConnectionData = logOptionalFieldsSettings.isLogSensitiveConnectionData(); + + to(lrec).addOptionalTag(isSensitiveConnectionData, Fields.REMOTE_IP, getValue(request.getRemoteAddr())) + .addOptionalTag(isSensitiveConnectionData, Fields.REMOTE_HOST, getValue(request.getRemoteHost())) + .addOptionalTag(isSensitiveConnectionData, Fields.REMOTE_PORT, + Integer.toString(request.getRemotePort())) + .addOptionalTag(isSensitiveConnectionData, Fields.X_FORWARDED_FOR, + getHeader(request, HttpHeaders.X_FORWARDED_FOR)) + .addOptionalTag(logOptionalFieldsSettings.isLogRemoteUserField(), Fields.REMOTE_USER, + getValue(request.getRemoteUser())) + .addOptionalTag(logOptionalFieldsSettings.isLogRefererField(), Fields.REFERER, + getHeader(request, HttpHeaders.REFERER)); + lrec.addContextTag(Fields.REQUEST_ID, getHeader(request, HttpHeaders.X_VCAP_REQUEST_ID)); + } } diff --git a/cf-java-logging-support-servlet/src/main/java/com/sap/hcp/cf/logging/servlet/filter/RequestLoggingVisitor.java b/cf-java-logging-support-servlet/src/main/java/com/sap/hcp/cf/logging/servlet/filter/RequestLoggingVisitor.java new file mode 100644 index 00000000..123d896d --- /dev/null +++ b/cf-java-logging-support-servlet/src/main/java/com/sap/hcp/cf/logging/servlet/filter/RequestLoggingVisitor.java @@ -0,0 +1,50 @@ +package com.sap.hcp.cf.logging.servlet.filter; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.sap.hcp.cf.logging.common.Defaults; +import com.sap.hcp.cf.logging.common.Fields; +import com.sap.hcp.cf.logging.common.HttpHeaders; +import com.sap.hcp.cf.logging.common.LongValue; +import com.sap.hcp.cf.logging.common.Markers; +import com.sap.hcp.cf.logging.common.RequestRecord; + +public class RequestLoggingVisitor { + + private static final Logger LOG = LoggerFactory.getLogger(RequestLoggingVisitor.class); + + private ContentLengthTrackingResponseWrapper responseWrapper; + private RequestRecord requestRecord; + + public RequestLoggingVisitor(RequestRecord requestRecord, ContentLengthTrackingResponseWrapper responseWrapper) { + this.requestRecord = requestRecord; + this.responseWrapper = responseWrapper; + } + + public void logRequest(HttpServletRequest httpRequest, HttpServletResponse httpResponse) { + requestRecord.stop(); + requestRecord.addValue(Fields.REQUEST_SIZE_B, new LongValue(httpRequest.getContentLength())); + String headerValue = httpResponse.getHeader(HttpHeaders.CONTENT_LENGTH); + if (headerValue != null) { + requestRecord.addValue(Fields.RESPONSE_SIZE_B, new LongValue(Long.valueOf(headerValue))); + } else { + if (responseWrapper != null) { + requestRecord.addValue(Fields.RESPONSE_SIZE_B, new LongValue(responseWrapper.getContentLength())); + } + } + requestRecord.addTag(Fields.RESPONSE_CONTENT_TYPE, getValue(httpResponse.getHeader(HttpHeaders.CONTENT_TYPE))); + requestRecord.addValue(Fields.RESPONSE_STATUS, new LongValue(httpResponse.getStatus())); + + LOG.info(Markers.REQUEST_MARKER, "{}", requestRecord); + + } + + private String getValue(String value) { + return value != null ? value : Defaults.UNKNOWN; + } + +} diff --git a/cf-java-logging-support-servlet/src/test/java/com/sap/hcp/cf/logging/servlet/filter/LoggingAsyncContextImplTest.java b/cf-java-logging-support-servlet/src/test/java/com/sap/hcp/cf/logging/servlet/filter/LoggingAsyncContextImplTest.java new file mode 100644 index 00000000..3cf7453b --- /dev/null +++ b/cf-java-logging-support-servlet/src/test/java/com/sap/hcp/cf/logging/servlet/filter/LoggingAsyncContextImplTest.java @@ -0,0 +1,170 @@ +package com.sap.hcp.cf.logging.servlet.filter; + +import static java.util.Collections.emptyMap; +import static java.util.concurrent.Executors.newSingleThreadExecutor; +import static org.hamcrest.Matchers.both; +import static org.hamcrest.Matchers.empty; +import static org.hamcrest.Matchers.hasEntry; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.not; +import static org.junit.Assert.assertThat; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; + +import javax.servlet.AsyncContext; +import javax.servlet.AsyncEvent; +import javax.servlet.AsyncListener; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.runners.MockitoJUnitRunner; +import org.mockito.stubbing.Answer; +import org.slf4j.MDC; + +@RunWith(MockitoJUnitRunner.class) +public class LoggingAsyncContextImplTest { + + @Mock + private AsyncContext wrappedContext; + + @Mock + private RequestLoggingVisitor loggingVisitor; + + @Mock + private HttpServletRequest request; + + @Mock + private HttpServletResponse response; + + private ExecutorService executor = newSingleThreadExecutor(); + + @Captor + private ArgumentCaptor asyncListener; + + @InjectMocks + private LoggingAsyncContextImpl testedContext; + + @Before + public void initWrappedContext() { + when(wrappedContext.getRequest()).thenReturn(request); + when(wrappedContext.getResponse()).thenReturn(response); + verify(wrappedContext).addListener(asyncListener.capture()); + doAnswer(new Answer() { + + @Override + public Void answer(InvocationOnMock invocation) throws Throwable { + Runnable runnable = (Runnable) invocation.getArguments()[0]; + Future future = executor.submit(runnable); + future.get(); + return null; + } + }).when(wrappedContext).start(any(Runnable.class)); + } + + @Test + public void hasEmptyMDCWhenNoMapInRequest() throws Exception { + Map contextMap = new HashMap<>(); + testedContext.start(putAllContextMap(contextMap)); + assertThat(contextMap.entrySet(), is(empty())); + } + + private Runnable putAllContextMap(Map contextMap) { + return new Runnable() { + + @Override + public void run() { + contextMap.putAll(MDC.getCopyOfContextMap()); + } + }; + } + + @Test + public void importsMDCEntriesFromRequest() throws Exception { + Map mdcAttributes = new HashMap<>(); + mdcAttributes.put("this-key", "this-value"); + mdcAttributes.put("that-key", "that-value"); + when(request.getAttribute(MDC.class.getName())).thenReturn(mdcAttributes); + Map contextMap = new HashMap<>(); + testedContext.start(putAllContextMap(contextMap)); + assertThat(contextMap, both(hasEntry("that-key", "that-value")).and(hasEntry("this-key", "this-value"))); + } + + @Test + public void resetsMDCEntriesBetweenConsequtiveRuns() throws Exception { + Map mdcAttributes = new HashMap<>(); + mdcAttributes.put("this-key", "this-value"); + mdcAttributes.put("that-key", "that-value"); + when(request.getAttribute(MDC.class.getName())).thenReturn(mdcAttributes); + Map firstContextMap = new HashMap<>(); + testedContext.start(putAllContextMap(firstContextMap)); + reset(request); + when(request.getAttribute(MDC.class.getName())).thenReturn(emptyMap()); + Map secondContextMap = new HashMap<>(); + testedContext.start(putAllContextMap(secondContextMap)); + + assertThat(firstContextMap.entrySet(), is(not(empty()))); + assertThat(secondContextMap.entrySet(), is(empty())); + } + + @Test + public void savesAndRestoresThreadMDC() throws Exception { + executor.submit(new Runnable() { + + @Override + public void run() { + MDC.put("initial-key", "initial-value"); + } + }); + Map requestContextMap = new HashMap<>(); + testedContext.start(putAllContextMap(requestContextMap)); + Map finalContextMap = new HashMap<>(); + executor.submit(new Runnable() { + + @Override + public void run() { + finalContextMap.putAll(MDC.getCopyOfContextMap()); + } + }); + + assertThat(requestContextMap.entrySet(), is(empty())); + assertThat(finalContextMap, hasEntry("initial-key", "initial-value")); + } + + @Test + public void writesRequestLogWithMDCEntries() throws Exception { + Map mdcAttributes = new HashMap<>(); + mdcAttributes.put("this-key", "this-value"); + mdcAttributes.put("that-key", "that-value"); + when(request.getAttribute(MDC.class.getName())).thenReturn(mdcAttributes); + Map contextMap = new HashMap<>(); + doAnswer(new Answer() { + + @Override + public Void answer(InvocationOnMock invocation) throws Throwable { + contextMap.putAll(MDC.getCopyOfContextMap()); + return null; + } + }).when(loggingVisitor).logRequest(any(HttpServletRequest.class), any(HttpServletResponse.class)); + asyncListener.getValue().onComplete(mock(AsyncEvent.class)); + + assertThat(contextMap, both(hasEntry("that-key", "that-value")).and(hasEntry("this-key", "this-value"))); + + } +} diff --git a/cf-java-logging-support-servlet/src/test/java/com/sap/hcp/cf/logging/servlet/filter/LoggingContextRequestWrapperTest.java b/cf-java-logging-support-servlet/src/test/java/com/sap/hcp/cf/logging/servlet/filter/LoggingContextRequestWrapperTest.java new file mode 100644 index 00000000..25e5a48a --- /dev/null +++ b/cf-java-logging-support-servlet/src/test/java/com/sap/hcp/cf/logging/servlet/filter/LoggingContextRequestWrapperTest.java @@ -0,0 +1,40 @@ +package com.sap.hcp.cf.logging.servlet.filter; + +import static org.hamcrest.Matchers.instanceOf; +import static org.junit.Assert.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import javax.servlet.AsyncContext; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class LoggingContextRequestWrapperTest { + + @Mock + private HttpServletRequest request; + + @Mock + private HttpServletResponse response; + + @Test + public void wrapsAsyncContext() throws Exception { + when(request.startAsync()).thenReturn(mock(AsyncContext.class)); + LoggingContextRequestWrapper wrapper = new LoggingContextRequestWrapper(request, null); + assertThat(wrapper.startAsync(), instanceOf(LoggingAsyncContextImpl.class)); + } + + @Test + public void wrapsAsyncContextWithRequestResponseParameters() throws Exception { + when(request.startAsync(request, response)).thenReturn(mock(AsyncContext.class)); + LoggingContextRequestWrapper wrapper = new LoggingContextRequestWrapper(request, null); + assertThat(wrapper.startAsync(request, response), instanceOf(LoggingAsyncContextImpl.class)); + } + +} diff --git a/cf-java-logging-support-servlet/src/test/java/com/sap/hcp/cf/logging/servlet/filter/RequestLoggingVisitorTest.java b/cf-java-logging-support-servlet/src/test/java/com/sap/hcp/cf/logging/servlet/filter/RequestLoggingVisitorTest.java new file mode 100644 index 00000000..e00cec28 --- /dev/null +++ b/cf-java-logging-support-servlet/src/test/java/com/sap/hcp/cf/logging/servlet/filter/RequestLoggingVisitorTest.java @@ -0,0 +1,93 @@ +package com.sap.hcp.cf.logging.servlet.filter; + +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; +import static org.mockito.Mockito.when; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +import com.sap.hcp.cf.logging.common.Fields; +import com.sap.hcp.cf.logging.common.HttpHeaders; +import com.sap.hcp.cf.logging.common.RequestRecord; +import com.sap.hcp.cf.logging.common.Value; + +@RunWith(MockitoJUnitRunner.class) +public class RequestLoggingVisitorTest { + + @Mock + private ContentLengthTrackingResponseWrapper responseWrapper; + + @Mock + private RequestRecord requestRecord; + + @Mock + private HttpServletRequest httpRequest; + + @Mock + private HttpServletResponse httpResponse; + + @InjectMocks + private RequestLoggingVisitor visitor; + + @Captor + private ArgumentCaptor valueCaptor; + + @Test + public void stopsRequestRecord() throws Exception { + visitor.logRequest(httpRequest, httpResponse); + verify(requestRecord).stop(); + } + + @Test + public void addsHttpStatusAsValue() throws Exception { + when(httpResponse.getStatus()).thenReturn(123); + visitor.logRequest(httpRequest, httpResponse); + verify(requestRecord).addValue(eq(Fields.RESPONSE_STATUS), valueCaptor.capture()); + assertThat(valueCaptor.getValue().asLong(), is(123L)); + } + + @Test + public void addsResponseContentTypeAsTag() throws Exception { + when(httpResponse.getHeader(HttpHeaders.CONTENT_TYPE)).thenReturn("application/vnd.test"); + visitor.logRequest(httpRequest, httpResponse); + verify(requestRecord).addTag(Fields.RESPONSE_CONTENT_TYPE, "application/vnd.test"); + } + + @Test + public void addsRequestContentLengthAsValue() throws Exception { + when(httpRequest.getContentLength()).thenReturn(12345); + visitor.logRequest(httpRequest, httpResponse); + verify(requestRecord).addValue(eq(Fields.REQUEST_SIZE_B), valueCaptor.capture()); + assertThat(valueCaptor.getValue().asLong(), is(12345L)); + } + + @Test + public void addsResponseContentLengthAsValueFromHeaderIfAvailable() throws Exception { + when(httpResponse.getHeader(HttpHeaders.CONTENT_LENGTH)).thenReturn("1234"); + visitor.logRequest(httpRequest, httpResponse); + verify(requestRecord).addValue(eq(Fields.RESPONSE_SIZE_B), valueCaptor.capture()); + verifyZeroInteractions(responseWrapper); + assertThat(valueCaptor.getValue().asLong(), is(1234L)); + } + + @Test + public void addsResponseContentLengthAsValueFromWrapperAsFAllback() throws Exception { + when(responseWrapper.getContentLength()).thenReturn(1234L); + visitor.logRequest(httpRequest, httpResponse); + verify(requestRecord).addValue(eq(Fields.RESPONSE_SIZE_B), valueCaptor.capture()); + assertThat(valueCaptor.getValue().asLong(), is(1234L)); + } + +} diff --git a/pom.xml b/pom.xml index db18bce2..6fff03c3 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.sap.hcp.cf.logging cf-java-logging-support-parent - 2.1.5 + 2.2.0 pom Cloud Foundry Java logging support components diff --git a/sample/pom.xml b/sample/pom.xml index 33f34504..6c13dfaa 100644 --- a/sample/pom.xml +++ b/sample/pom.xml @@ -6,7 +6,7 @@ com.sap.hcp.cf.logging cf-java-logging-support-parent - 2.1.5 + 2.2.0 ../pom.xml @@ -18,7 +18,7 @@ 1.7.12 2.22.2 2.0.1 - 2.1.5 + 2.2.0