diff options
author | vempo <vitaliy.emporopulo@amdocs.com> | 2018-07-31 18:50:14 +0300 |
---|---|---|
committer | Avi Gaffa <avi.gaffa@amdocs.com> | 2018-08-05 12:15:49 +0000 |
commit | 1b01b984901d5f69d5e421e459d62a6d03292444 (patch) | |
tree | 2e172e9c4ba8b19a286b89d93270629a5b768a89 /openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main | |
parent | d05277df22ddde79458cd853f98e7ab3a4d98913 (diff) |
Simplified logging code for servlets
Added and simplified unit tests, organized imports,
refactored for simplicity and reuse.
Change-Id: I4c4837447329528ae855f2e8d1a1f4b883617f33
Issue-ID: SDC-1580
Signed-off-by: vempo <vitaliy.emporopulo@amdocs.com>
Diffstat (limited to 'openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main')
15 files changed, 466 insertions, 308 deletions
diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/api/LoggerFactory.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/api/LoggerFactory.java index 30517cd5fb..96debb56b0 100644 --- a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/api/LoggerFactory.java +++ b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/api/LoggerFactory.java @@ -16,9 +16,8 @@ package org.openecomp.sdc.logging.api; -import org.openecomp.sdc.logging.spi.LoggerCreationService; - import java.util.Objects; +import org.openecomp.sdc.logging.spi.LoggerCreationService; /** * <a>Factory to hide a concrete, framework-specific implementation of logger creation.</a> diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/api/LoggingContext.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/api/LoggingContext.java index 9526713093..894dd2c00c 100644 --- a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/api/LoggingContext.java +++ b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/api/LoggingContext.java @@ -16,10 +16,9 @@ package org.openecomp.sdc.logging.api; -import org.openecomp.sdc.logging.spi.LoggingContextService; - import java.util.Objects; import java.util.concurrent.Callable; +import org.openecomp.sdc.logging.spi.LoggingContextService; /** * <p>Factory to hide a concrete, framework-specific implementation of diagnostic context.</p> diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/api/ServiceBinder.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/api/ServiceBinder.java index 5aaa301a9c..6e5b3e3501 100644 --- a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/api/ServiceBinder.java +++ b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/api/ServiceBinder.java @@ -16,13 +16,12 @@ package org.openecomp.sdc.logging.api; -import org.openecomp.sdc.logging.spi.LoggerCreationService; -import org.openecomp.sdc.logging.spi.LoggingContextService; -import org.openecomp.sdc.logging.spi.LoggingServiceProvider; - import java.util.Iterator; import java.util.Optional; import java.util.ServiceLoader; +import org.openecomp.sdc.logging.spi.LoggerCreationService; +import org.openecomp.sdc.logging.spi.LoggingContextService; +import org.openecomp.sdc.logging.spi.LoggingServiceProvider; /** * <p>Binds to a concrete implementation of logging services.</p> @@ -37,7 +36,7 @@ import java.util.ServiceLoader; // No advanced logging can be used here because we don't know // which underlying implementation will be used -@SuppressWarnings({"UseOfSystemOutOrSystemErr", "squid:S106"}) +@SuppressWarnings({"UseOfSystemOutOrSystemErr", "squid:S106", "squid:S1166"}) class ServiceBinder { private static final LoggingServiceProvider PROVIDER = lookupProvider(); diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/servlet/AuditTracker.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/servlet/AuditTracker.java new file mode 100644 index 0000000000..af9b5061fd --- /dev/null +++ b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/servlet/AuditTracker.java @@ -0,0 +1,85 @@ +/* + * 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; + +import java.util.Objects; +import javax.servlet.http.HttpServletRequest; +import org.openecomp.sdc.logging.api.AuditData; +import org.openecomp.sdc.logging.api.Logger; +import org.openecomp.sdc.logging.api.LoggerFactory; + +/** + * Tracks and logs audit information when a request is being processed. An instance of this class cannot be reused, and + * the pre- and post-request methods must be called only once. + * + * @author evitaliy + * @since 31 Jul 2018 + */ +public class AuditTracker implements Tracker { + + private final Logger logger; + private volatile long started; + private volatile String clientIpAddress; + + /** + * Allows passing a class that will be used to log audit. + * + * @param resourceType audit will be logged through the logger of this class + */ + public AuditTracker(Class<?> resourceType) { + this.logger = LoggerFactory.getLogger(resourceType); + } + + /** + * Allows passing a logger that will be used to log audit. + * + * @param logger audit will be logged through this logger, cannot be null + */ + public AuditTracker(Logger logger) { + this.logger = Objects.requireNonNull(logger); + } + + @Override + public synchronized void preRequest(HttpServletRequest request) { + + if (this.started > 0) { + throw new IllegalStateException("Pre-request has been already called"); + } + + this.started = System.currentTimeMillis(); + this.clientIpAddress = request.getRemoteAddr(); + } + + @Override + public synchronized void postRequest(RequestProcessingResult result) { + + if (this.started == 0) { + throw new IllegalStateException("Pre-request must be called first"); + } + + if (!logger.isAuditEnabled()) { + return; + } + + long end = System.currentTimeMillis(); + AuditData auditData = AuditData.builder().startTime(started).endTime(end).statusCode(result.getStatusCode()) + .responseCode(Integer.toString(result.getStatus())) + .responseDescription(result.getStatusPhrase()).clientIpAddress(clientIpAddress) + .build(); + logger.audit(auditData); + } +} diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/servlet/CombinedTracker.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/servlet/CombinedTracker.java new file mode 100644 index 0000000000..2dd2c12143 --- /dev/null +++ b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/servlet/CombinedTracker.java @@ -0,0 +1,55 @@ +/* + * 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; + +import javax.servlet.http.HttpServletRequest; +import org.openecomp.sdc.logging.api.Logger; + +/** + * Tracker for all the elements of ONAP logging and tracing at an entry point to an application - context and audit. + * The order of invocations is important, assuming the context must be kept as long as audit hasn't been finished. + * + * @author evitaliy + * @since 01 Aug 2018 + */ +public class CombinedTracker implements Tracker { + + private final ContextTracker context; + private final AuditTracker audit; + + public CombinedTracker(Logger logger, HttpHeader partnerNameHeader, HttpHeader requestIdHeader) { + this.context = new ContextTracker(partnerNameHeader, requestIdHeader); + this.audit = new AuditTracker(logger); + } + + public CombinedTracker(Class<?> resourceType, HttpHeader partnerNameHeader, HttpHeader requestIdHeader) { + this.context = new ContextTracker(partnerNameHeader, requestIdHeader); + this.audit = new AuditTracker(resourceType); + } + + @Override + public void preRequest(HttpServletRequest request) { + this.context.preRequest(request); + this.audit.preRequest(request); + } + + @Override + public void postRequest(RequestProcessingResult result) { + this.audit.postRequest(result); + this.context.postRequest(result); + } +} diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/servlet/ContextTracker.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/servlet/ContextTracker.java new file mode 100644 index 0000000000..2334f373bc --- /dev/null +++ b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/servlet/ContextTracker.java @@ -0,0 +1,66 @@ +/* + * 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; + +import java.util.Objects; +import java.util.UUID; +import javax.servlet.http.HttpServletRequest; +import org.openecomp.sdc.logging.api.ContextData; +import org.openecomp.sdc.logging.api.LoggingContext; + +/** + * Populates the context before a request is processed, and cleans it after the request has been processed. + * + * @author evitaliy + * @since 31 Jul 2018 + */ +public class ContextTracker implements Tracker { + + private final HttpHeader partnerNameHeaders; + private final HttpHeader requestIdHeaders; + + /** + * Constructs tracker to handle required logging context in Servlet-based applications. Refer to ONAP logging + * guidelines for fields required to be put on logging context. + * + * @param partnerNameHeaders HTTP headers to check for a partner name, cannot be null + * @param requestIdHeaders HTTP headers to check for a request ID, cannot be null + */ + public ContextTracker(HttpHeader partnerNameHeaders, HttpHeader requestIdHeaders) { + this.partnerNameHeaders = Objects.requireNonNull(partnerNameHeaders); + this.requestIdHeaders = Objects.requireNonNull(requestIdHeaders); + } + + @Override + public void preRequest(HttpServletRequest request) { + + LoggingContext.clear(); + + String serviceName = ServiceNameFormatter.format(request); + String requestId = requestIdHeaders.getAny(request::getHeader).orElse(UUID.randomUUID().toString()); + ContextData.ContextDataBuilder contextBuilder = + ContextData.builder().serviceName(serviceName).requestId(requestId); + + partnerNameHeaders.getAny(request::getHeader).ifPresent(contextBuilder::partnerName); + LoggingContext.put(contextBuilder.build()); + } + + @Override + public void postRequest(RequestProcessingResult result) { + LoggingContext.clear(); + } +} diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/servlet/HttpHeader.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/servlet/HttpHeader.java index 4dcc197796..db10c2e4f3 100644 --- a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/servlet/HttpHeader.java +++ b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/servlet/HttpHeader.java @@ -16,6 +16,11 @@ package org.openecomp.sdc.logging.servlet; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.Optional; import java.util.function.Function; /** @@ -28,28 +33,80 @@ import java.util.function.Function; */ public class HttpHeader { - private final String[] keys; + private static final String NAMES_CANNOT_BE_NULL = "Names cannot be null"; + private static final String AT_LEAST_ONE_NAME_REQUIRED = "At least one name required"; - public HttpHeader(String... keys) { - this.keys = keys; + private final List<String> headerNames; + + /** + * Receives a list of accepted header names as a String array. + * + * @param headerNames cannot be null or empty + */ + public HttpHeader(String[] headerNames) { + + if (Objects.requireNonNull(headerNames, NAMES_CANNOT_BE_NULL).length < 1) { + throw new IllegalArgumentException(AT_LEAST_ONE_NAME_REQUIRED); + } + + this.headerNames = Arrays.asList(headerNames); + } + + /** + * Receives a list of accepted header names as a list of String. + * + * @param headerNames cannot be null or empty + */ + public HttpHeader(List<String> headerNames) { + + if (Objects.requireNonNull(headerNames, NAMES_CANNOT_BE_NULL).isEmpty()) { + throw new IllegalArgumentException(AT_LEAST_ONE_NAME_REQUIRED); + } + + this.headerNames = new ArrayList<>(headerNames); } /** * Returns the value of any of the possible headers. * * @param reader function for reading an HTTP header. - * @return value or null if not found + * @return value or empty if not found */ - public String getAny(Function<String, String> reader) { + public Optional<String> getAny(Function<String, String> reader) { - for (String k : keys) { + for (String k : headerNames) { String value = reader.apply(k); if (value != null) { - return value; + return Optional.of(value); } } - return null; + return Optional.empty(); + } + + @Override + public boolean equals(Object o) { + + if (this == o) { + return true; + } + + if (o == null || getClass() != o.getClass()) { + return false; + } + + HttpHeader that = (HttpHeader) o; + return Objects.equals(headerNames, that.headerNames); + } + + @Override + public int hashCode() { + return Objects.hash(headerNames); + } + + @Override + public String toString() { + return "HttpHeader{headerNames=" + headerNames + '}'; } } diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/servlet/LoggingFilter.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/servlet/LoggingFilter.java deleted file mode 100644 index e53f28119c..0000000000 --- a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/servlet/LoggingFilter.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * 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; - -import static org.openecomp.sdc.logging.LoggingConstants.DEFAULT_PARTNER_NAME_HEADER; -import static org.openecomp.sdc.logging.LoggingConstants.DEFAULT_REQUEST_ID_HEADER; - -import java.io.IOException; -import java.util.UUID; -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; -import org.openecomp.sdc.logging.api.ContextData; -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.servlet.jaxrs.LoggingRequestFilter; -import org.openecomp.sdc.logging.servlet.jaxrs.LoggingResponseFilter; - -/** - * <p>Places logging context information. Must be configured as a servlet filter in <i>web.xml</i>. The behavior can be - * customized via init-params.</p> - * <p>Example:</p> - * <pre> - * - * <filter> - * <filter-name>LoggingServletFilter</filter-name> - * <filter-class>org.openecomp.sdc.logging.servlet.LoggingFilter</filter-class> - * <init-param> - * <param-name>requestIdHeaders</param-name> - * <param-value>X-ONAP-RequestID</param-value> - * </init-param> - * <init-param> - * <param-name>partnerNameHeaders</param-name> - * <param-value>USER_ID</param-value> - * </init-param> - * </filter> - * - * <filter-mapping> - * <filter-name>LoggingServletFilter</filter-name> - * <url-pattern>/*</url-pattern> - * </filter-mapping> - * - * </pre> - * - * @author evitaliy - * @since 25 Jul 2016 - * @deprecated Kept for backward compatibility. For JAX-RS application, use - * {@link LoggingRequestFilter} and - * {@link LoggingResponseFilter} instead. - */ -@Deprecated -public class LoggingFilter implements Filter { - - static final String MULTI_VALUE_SEPARATOR = ","; - - static final String REQUEST_ID_HEADERS_PARAM = "requestIdHeaders"; - static final String PARTNER_NAME_HEADERS_PARAM = "partnerNameHeaders"; - - private static final Logger LOGGER = LoggerFactory.getLogger(LoggingFilter.class); - - private HttpHeader requestIdHeaders; - private HttpHeader partnerNameHeaders; - - @Override - public void init(FilterConfig config) { - requestIdHeaders = getInitParam(config, REQUEST_ID_HEADERS_PARAM, DEFAULT_REQUEST_ID_HEADER); - partnerNameHeaders = getInitParam(config, PARTNER_NAME_HEADERS_PARAM, DEFAULT_PARTNER_NAME_HEADER); - } - - @Override - public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) - throws IOException, ServletException { - - HttpServletRequest httpRequest = HttpServletRequest.class.cast(request); - - try { - - LoggingContext.clear(); - - ContextData.ContextDataBuilder contextData = ContextData.builder(); - - contextData.serviceName(httpRequest.getRequestURI()); - - String requestId = requestIdHeaders.getAny(httpRequest::getHeader); - contextData.requestId(requestId == null ? UUID.randomUUID().toString() : requestId); - - String partner = partnerNameHeaders.getAny(httpRequest::getHeader); - if (partner != null) { - contextData.partnerName(partner); - } - - LoggingContext.put(contextData.build()); - - chain.doFilter(request, response); - - } finally { - LoggingContext.clear(); - } - } - - @Override - public void destroy() { - // forced by the interface - not implemented - } - - private HttpHeader getInitParam(FilterConfig config, String paramName, String defaultValue) { - - String value = config.getInitParameter(paramName); - LOGGER.debug("Logging filter configuration param '{}' value '{}'", paramName, value); - - if (value == null) { - return new HttpHeader(defaultValue); - } else { - return new HttpHeader(value.split(MULTI_VALUE_SEPARATOR)); - } - } -} diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/servlet/RequestProcessingResult.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/servlet/RequestProcessingResult.java new file mode 100644 index 0000000000..d3625ed303 --- /dev/null +++ b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/servlet/RequestProcessingResult.java @@ -0,0 +1,49 @@ +/* + * 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; + +import org.openecomp.sdc.logging.api.StatusCode; + +/** + * Interpretation of request processing results. + * + * @author evitaliy + * @since 02 Aug 2018 + */ +public interface RequestProcessingResult { + + /** + * Numeric status code. + * + * @return usually HTTP response status. + */ + int getStatus(); + + /** + * Whether the response is considered success or failure. + * + * @return on of pre-defined status codes + */ + StatusCode getStatusCode(); + + /** + * Human-friendly description of the numeric status. + * + * @return usually HTTP reason phrase + */ + String getStatusPhrase(); +} diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/servlet/ServiceNameFormatter.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/servlet/ServiceNameFormatter.java new file mode 100644 index 0000000000..f65490bf18 --- /dev/null +++ b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/servlet/ServiceNameFormatter.java @@ -0,0 +1,36 @@ +/* + * 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; + +import javax.servlet.http.HttpServletRequest; + +/** + * Formats a service name based on HTTP method and request URI. + * + * @author evitaliy + * @since 01 Aug 2018 + */ +class ServiceNameFormatter { + + private ServiceNameFormatter() { + // utility class, prevent instantiation + } + + public static String format(HttpServletRequest request) { + return request.getMethod() + ": " + request.getRequestURI(); + } +}
\ No newline at end of file diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/servlet/Tracker.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/servlet/Tracker.java new file mode 100644 index 0000000000..c0337cfb4d --- /dev/null +++ b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/servlet/Tracker.java @@ -0,0 +1,44 @@ +/* + * 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; + +import javax.servlet.http.HttpServletRequest; + +/** + * Tracks logging and tracing information through the processing of an HTTP request. + * + * @author evitaliy + * @since 31 Jul 2018 + */ +public interface Tracker { + + /** + * Will be executed before request processing has started. + * + * @param request provided by every Servlet container + */ + void preRequest(HttpServletRequest request); + + /** + * Will be executed after a request has been processed. Results may be treated differently depending on a container + * and application. For instance, JAX-RS applications may take into account exception mappers before generating a + * response; some applications may Swagger annotations to map a response status to a human-friendly message, etc. + * + * @param result application- and container-specific request results + */ + void postRequest(RequestProcessingResult result); +} diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/servlet/jaxrs/LoggingRequestFilter.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/servlet/jaxrs/LoggingRequestFilter.java index 0e1b7d715b..f846359b82 100644 --- a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/servlet/jaxrs/LoggingRequestFilter.java +++ b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/servlet/jaxrs/LoggingRequestFilter.java @@ -19,25 +19,24 @@ package org.openecomp.sdc.logging.servlet.jaxrs; import static org.openecomp.sdc.logging.LoggingConstants.DEFAULT_PARTNER_NAME_HEADER; import static org.openecomp.sdc.logging.LoggingConstants.DEFAULT_REQUEST_ID_HEADER; -import java.util.UUID; import javax.servlet.http.HttpServletRequest; import javax.ws.rs.container.ContainerRequestContext; import javax.ws.rs.container.ContainerRequestFilter; +import javax.ws.rs.container.ResourceInfo; import javax.ws.rs.core.Context; import javax.ws.rs.ext.Provider; -import org.openecomp.sdc.logging.api.ContextData; 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.servlet.CombinedTracker; import org.openecomp.sdc.logging.servlet.HttpHeader; +import org.openecomp.sdc.logging.servlet.Tracker; /** * <p>Takes care of logging initialization an HTTP request hits the application. This includes populating logging - * context and storing the request processing start time, so that it can be used for audit. The filter was built - * <b>works in tandem</b> with {@link LoggingResponseFilter} or a similar implementation.</p> + * context and tracking the request for audit. The filter <b>works in tandem</b> with {@link LoggingResponseFilter} or + * a similar implementation.</p> * <p>The filter requires a few HTTP header names to be configured. These HTTP headers are used for propagating logging - * and tracing information between ONAP components.</p> - * <p>Sample configuration for a Spring environment:</p> + * and tracing information between ONAP components. Sample configuration for a Spring environment:</p> * <pre> * <jaxrs:providers> * <bean class="org.openecomp.sdc.logging.ws.rs.LoggingRequestFilter"> @@ -51,40 +50,42 @@ import org.openecomp.sdc.logging.servlet.HttpHeader; * </p> * * @author evitaliy, katyr - * @since 29 Oct 17 - * * @see ContainerRequestFilter + * @since 29 Oct 17 */ @Provider public class LoggingRequestFilter implements ContainerRequestFilter { - static final String MULTI_VALUE_SEPARATOR = ","; - - static final String START_TIME_KEY = "audit.start.time"; + static final String LOGGING_TRACKER_KEY = "onap.logging.tracker"; + private static final String MULTI_VALUE_SEPARATOR = ","; private static final Logger LOGGER = LoggerFactory.getLogger(LoggingRequestFilter.class); private HttpServletRequest httpRequest; - private HttpHeader requestIdHeader = new HttpHeader(DEFAULT_REQUEST_ID_HEADER); - private HttpHeader partnerNameHeader = new HttpHeader(DEFAULT_PARTNER_NAME_HEADER); - private boolean includeHttpMethod = true; + private HttpHeader requestIdHeader = new HttpHeader(new String[] {DEFAULT_REQUEST_ID_HEADER}); + private HttpHeader partnerNameHeader = new HttpHeader(new String[] {DEFAULT_PARTNER_NAME_HEADER}); + + private ResourceInfo resource; /** - * Injection of HTTP request object from JAX-RS context. + * Injection of a resource that matches the request from JAX-RS context. * - * @param httpRequest automatically injected by JAX-RS container + * @param resource automatically injected by JAX-RS container */ @Context - public void setHttpRequest(HttpServletRequest httpRequest) { - this.httpRequest = httpRequest; + public void setResource(ResourceInfo resource) { + this.resource = resource; } /** - * Configuration parameter to include the HTTP method of a request in service name. + * Injection of HTTP request object from JAX-RS context. + * + * @param httpRequest automatically injected by JAX-RS container */ - public void setHttpMethodInServiceName(boolean includeHttpMethod) { - this.includeHttpMethod = includeHttpMethod; + @Context + public void setHttpRequest(HttpServletRequest httpRequest) { + this.httpRequest = httpRequest; } /** @@ -104,33 +105,10 @@ public class LoggingRequestFilter implements ContainerRequestFilter { } @Override - public void filter(ContainerRequestContext containerRequestContext) { - - LoggingContext.clear(); - - containerRequestContext.setProperty(START_TIME_KEY, System.currentTimeMillis()); - - ContextData.ContextDataBuilder contextData = ContextData.builder(); - contextData.serviceName(getServiceName()); - - String partnerName = partnerNameHeader.getAny(containerRequestContext::getHeaderString); - if (partnerName != null) { - contextData.partnerName(partnerName); - } - - String requestId = requestIdHeader.getAny(containerRequestContext::getHeaderString); - contextData.requestId(requestId == null ? UUID.randomUUID().toString() : requestId); - - LoggingContext.put(contextData.build()); - } - - private String getServiceName() { - return includeHttpMethod - ? formatServiceName(this.httpRequest.getMethod(), this.httpRequest.getRequestURI()) - : this.httpRequest.getRequestURI(); - } - - static String formatServiceName(String httpMethod, String requestUri) { - return httpMethod + " " + requestUri; + public void filter(ContainerRequestContext requestContext) { + Class<?> resourceClass = resource.getResourceMethod().getDeclaringClass(); + Tracker tracker = new CombinedTracker(resourceClass, partnerNameHeader, requestIdHeader); + requestContext.setProperty(LOGGING_TRACKER_KEY, tracker); + tracker.preRequest(httpRequest); } } 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 index 4609620be1..fa9e815db8 100644 --- 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 @@ -16,19 +16,22 @@ package org.openecomp.sdc.logging.servlet.jaxrs; -import org.openecomp.sdc.logging.api.*; +import static javax.ws.rs.core.Response.Status.Family.REDIRECTION; +import static javax.ws.rs.core.Response.Status.Family.SUCCESSFUL; +import static org.openecomp.sdc.logging.api.StatusCode.COMPLETE; +import static org.openecomp.sdc.logging.api.StatusCode.ERROR; +import static org.openecomp.sdc.logging.servlet.jaxrs.LoggingRequestFilter.LOGGING_TRACKER_KEY; -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.container.ResourceInfo; -import javax.ws.rs.core.Context; import javax.ws.rs.core.Response; import javax.ws.rs.ext.Provider; - -import static org.openecomp.sdc.logging.api.StatusCode.COMPLETE; -import static org.openecomp.sdc.logging.api.StatusCode.ERROR; +import org.openecomp.sdc.logging.api.Logger; +import org.openecomp.sdc.logging.api.LoggerFactory; +import org.openecomp.sdc.logging.api.StatusCode; +import org.openecomp.sdc.logging.servlet.RequestProcessingResult; +import org.openecomp.sdc.logging.servlet.Tracker; /** * <p>Takes care of logging when an HTTP request leaves the application. This includes writing to audit and clearing @@ -44,123 +47,49 @@ import static org.openecomp.sdc.logging.api.StatusCode.ERROR; * due to unhandled application or container exceptions.</i></p> * * @author evitaliy - * @since 29 Oct 17 - * * @see ContainerResponseFilter + * @since 29 Oct 17 */ @Provider public class LoggingResponseFilter implements ContainerResponseFilter { - private static final int UNKNOWN_START_TIME = 0; - private static final Logger LOGGER = LoggerFactory.getLogger(LoggingResponseFilter.class); - /** - * 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; - - private ResourceInfo resource; - - /** - * 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; - } - - /** - * Injection of a resource that matches the request from JAX-RS context. - * - * @param resource automatically injected by JAX-RS container - */ - @Context - public void setResource(ResourceInfo resource) { - this.resource = resource; - } - @Override - public void filter(ContainerRequestContext containerRequestContext, - ContainerResponseContext containerResponseContext) { + public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) { - try { + Tracker tracker = (Tracker) requestContext.getProperty(LOGGING_TRACKER_KEY); - if ((resource == null) || (resource.getResourceClass() == null)) { - LOGGER.debug("No matching resource, skipping audit."); - return; - } - - writeAudit(containerRequestContext, containerResponseContext); - - } finally { - LoggingContext.clear(); - } - } - - private void writeAudit(ContainerRequestContext containerRequestContext, - ContainerResponseContext containerResponseContext) { - - Logger resourceLogger = LoggerFactory.getLogger(resource.getResourceMethod().getDeclaringClass()); - if (!resourceLogger.isAuditEnabled()) { + if (tracker == null) { + LOGGER.debug("No logging tracker received"); 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(); - resourceLogger.audit(auditData); + tracker.postRequest(new ContainerResponseResult(responseContext.getStatusInfo())); } - private boolean isSuccess(int responseCode) { - return responseCode > 199 && responseCode < 400; - } + private static class ContainerResponseResult implements RequestProcessingResult { - private long readStartTime(ContainerRequestContext containerRequestContext) { + private final Response.StatusType statusInfo; - Object startTime = containerRequestContext.getProperty(LoggingRequestFilter.START_TIME_KEY); - if (startTime == null) { - return handleMissingStartTime(); + private ContainerResponseResult(Response.StatusType statusInfo) { + this.statusInfo = statusInfo; } - 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 UNKNOWN_START_TIME; - } - - 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(), e); - return 0; + @Override + public int getStatus() { + return statusInfo.getStatusCode(); } - } - private void reportConfigProblem(String message, Object... arguments) { + @Override + public StatusCode getStatusCode() { + Response.Status.Family family = statusInfo.getFamily(); + return family.equals(SUCCESSFUL) || family.equals(REDIRECTION) ? COMPLETE : ERROR; + } - if (reportBadConfiguration) { - reportBadConfiguration = false; - LOGGER.error(message, arguments); + @Override + public String getStatusPhrase() { + return statusInfo.getReasonPhrase(); } } } diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/spi/LoggerCreationService.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/spi/LoggerCreationService.java index 90aebfa221..54b5be3a27 100644 --- a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/spi/LoggerCreationService.java +++ b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/spi/LoggerCreationService.java @@ -20,7 +20,6 @@ import org.openecomp.sdc.logging.api.Logger; import org.openecomp.sdc.logging.api.LoggerFactory; /** - * * Implements a framework-specific logging, to be used by {@link LoggerFactory}. * * @author evitaliy diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/spi/LoggingContextService.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/spi/LoggingContextService.java index 7c71465846..37e212ac54 100644 --- a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/spi/LoggingContextService.java +++ b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/spi/LoggingContextService.java @@ -16,9 +16,8 @@ package org.openecomp.sdc.logging.spi; -import org.openecomp.sdc.logging.api.ContextData; - import java.util.concurrent.Callable; +import org.openecomp.sdc.logging.api.ContextData; /** * Should be used to implement a framework-specific mechanism of managing a per-thread diagnostic context (for instance |