diff options
Diffstat (limited to 'openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/servlet/jaxrs/LoggingResponseFilter.java')
-rw-r--r-- | openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/servlet/jaxrs/LoggingResponseFilter.java | 147 |
1 files changed, 147 insertions, 0 deletions
diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/servlet/jaxrs/LoggingResponseFilter.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/servlet/jaxrs/LoggingResponseFilter.java new file mode 100644 index 0000000000..fbe28a79eb --- /dev/null +++ b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/servlet/jaxrs/LoggingResponseFilter.java @@ -0,0 +1,147 @@ +/* + * Copyright © 2016-2018 European Support Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openecomp.sdc.logging.servlet.jaxrs; + +import static org.openecomp.sdc.logging.api.StatusCode.COMPLETE; +import static org.openecomp.sdc.logging.api.StatusCode.ERROR; + +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ContainerResponseContext; +import javax.ws.rs.container.ContainerResponseFilter; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.Response; +import javax.ws.rs.ext.Provider; +import org.openecomp.sdc.logging.api.AuditData; +import org.openecomp.sdc.logging.api.Logger; +import org.openecomp.sdc.logging.api.LoggerFactory; +import org.openecomp.sdc.logging.api.LoggingContext; +import org.openecomp.sdc.logging.api.StatusCode; + +/** + * <p>Takes care of logging when an HTTP request leaves the application. This includes writing to audit and clearing + * logging context. This filter <b>only works properly in tandem</b> with {@link LoggingRequestFilter} or a similar + * implementation.</p> + * <p>Sample configuration for a Spring environment:</p> + * <pre> + * <jaxrs:providers> + * <bean class="org.openecomp.sdc.logging.ws.rs.LoggingResponseFilter"/> + * </jaxrs:providers> + * </pre> + * <p><i>It is highly recommended to configure a custom JAX-RS exception mapper so that this filter will not be bypassed + * due to unhandled application or container exceptions.</i></p> + * + * @author evitaliy + * @since 29 Oct 17 + * + * @see ContainerResponseFilter + */ +@Provider +public class LoggingResponseFilter implements ContainerResponseFilter { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + /** + * Tracks reporting configuration problems to the log. We want to report them only once, and not to write to log + * upon every request, as the configuration will not change in runtime. + */ + private boolean reportBadConfiguration = true; + + private HttpServletRequest httpRequest; + + /** + * Injection of HTTP request object from JAX-RS context. + * + * @param httpRequest automatically injected by JAX-RS container + */ + @Context + public void setHttpRequest(HttpServletRequest httpRequest) { + this.httpRequest = httpRequest; + } + + @Override + public void filter(ContainerRequestContext containerRequestContext, + ContainerResponseContext containerResponseContext) { + + try { + writeAudit(containerRequestContext, containerResponseContext); + } finally { + LoggingContext.clear(); + } + } + + private void writeAudit(ContainerRequestContext containerRequestContext, + ContainerResponseContext containerResponseContext) { + + if (!logger.isAuditEnabled()) { + return; + } + + long start = readStartTime(containerRequestContext); + long end = System.currentTimeMillis(); + + Response.StatusType statusInfo = containerResponseContext.getStatusInfo(); + int responseCode = statusInfo.getStatusCode(); + StatusCode statusCode = isSuccess(responseCode) ? COMPLETE : ERROR; + + AuditData auditData = AuditData.builder().startTime(start).endTime(end).statusCode(statusCode) + .responseCode(Integer.toString(responseCode)) + .responseDescription(statusInfo.getReasonPhrase()) + .clientIpAddress(httpRequest.getRemoteAddr()).build(); + logger.audit(auditData); + } + + private boolean isSuccess(int responseCode) { + return responseCode > 199 && responseCode < 400; + } + + private long readStartTime(ContainerRequestContext containerRequestContext) { + + Object startTime = containerRequestContext.getProperty(LoggingRequestFilter.START_TIME_KEY); + if (startTime == null) { + return handleMissingStartTime(); + } + + return parseStartTime(startTime); + } + + private long handleMissingStartTime() { + reportConfigProblem("{} key was not found in JAX-RS request context. " + + "Make sure you configured a request filter", LoggingRequestFilter.START_TIME_KEY); + return 0; + } + + private long parseStartTime(Object startTime) { + + try { + return Long.class.cast(startTime); + } catch (ClassCastException e) { + reportConfigProblem("{} key in JAX-RS request context contains an object of type '{}', but 'java.lang.Long'" + + " is expected", LoggingRequestFilter.START_TIME_KEY, startTime.getClass().getName()); + return 0; + } + } + + private void reportConfigProblem(String message, Object... arguments) { + + if (reportBadConfiguration) { + reportBadConfiguration = false; + logger.error(message, arguments); + } + } +} + |