diff options
Diffstat (limited to 'aai-els-onap-logging/src/main/java/org/onap/logging')
19 files changed, 2462 insertions, 0 deletions
diff --git a/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/AbstractAuditLogFilter.java b/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/AbstractAuditLogFilter.java new file mode 100644 index 00000000..ce2f4489 --- /dev/null +++ b/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/AbstractAuditLogFilter.java @@ -0,0 +1,82 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - Logging + * ================================================================================ + * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.onap.logging.filter.base; + +import javax.servlet.http.HttpServletRequest; +import org.onap.logging.ref.slf4j.ONAPLogConstants; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.MDC; + +public abstract class AbstractAuditLogFilter<GenericRequest, GenericResponse> extends MDCSetup { + protected static final Logger logger = LoggerFactory.getLogger(AbstractAuditLogFilter.class); + + protected void pre(SimpleMap headers, GenericRequest request, HttpServletRequest httpServletRequest) { + try { + String requestId = getRequestId(headers); + MDC.put(ONAPLogConstants.MDCs.REQUEST_ID, requestId); + setInvocationId(headers); + setServiceName(request); + setMDCPartnerName(headers); + setServerFQDN(); + setClientIPAddress(httpServletRequest); + setInstanceID(); + setEntryTimeStamp(); + MDC.put(ONAPLogConstants.MDCs.RESPONSE_STATUS_CODE, ONAPLogConstants.ResponseStatus.INPROGRESS.toString()); + additionalPreHandling(request); + setLogTimestamp(); + setElapsedTime(); + logger.info(ONAPLogConstants.Markers.ENTRY, "Entering"); + } catch (Exception e) { + logger.warn("Error in AbstractInboundFilter pre", e); + } + } + + protected void post(GenericResponse response) { + try { + int responseCode = getResponseCode(response); + setResponseStatusCode(responseCode); + MDC.put(ONAPLogConstants.MDCs.RESPONSE_CODE, String.valueOf(responseCode)); + setResponseDescription(responseCode); + setLogTimestamp(); + setElapsedTime(); + logger.info(ONAPLogConstants.Markers.EXIT, "Exiting."); + additionalPostHandling(response); + } catch (Exception e) { + logger.warn("Error in AbstractInboundFilter post", e); + } finally { + MDC.clear(); + } + } + + protected abstract int getResponseCode(GenericResponse response); + + protected abstract void setServiceName(GenericRequest request); + + protected void additionalPreHandling(GenericRequest request) { + // override to add additional pre handling + } + + protected void additionalPostHandling(GenericResponse response) { + // override to add additional post handling + } + +} diff --git a/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/AbstractMetricLogFilter.java b/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/AbstractMetricLogFilter.java new file mode 100644 index 00000000..ab1daab5 --- /dev/null +++ b/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/AbstractMetricLogFilter.java @@ -0,0 +1,135 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - Logging + * ================================================================================ + * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.onap.logging.filter.base; + +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.UUID; +import org.onap.logging.ref.slf4j.ONAPLogConstants; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.MDC; +import org.slf4j.Marker; +import org.slf4j.MarkerFactory; + +public abstract class AbstractMetricLogFilter<Request, Response, RequestHeaders> extends MDCSetup { + protected static final Logger logger = LoggerFactory.getLogger(AbstractMetricLogFilter.class); + private final String partnerName; + private static final Marker INVOKE_RETURN = MarkerFactory.getMarker("INVOKE-RETURN"); + + public AbstractMetricLogFilter() { + partnerName = getPartnerName(); + } + + protected abstract void addHeader(RequestHeaders requestHeaders, String headerName, String headerValue); + + protected abstract String getTargetServiceName(Request request); + + protected abstract String getServiceName(Request request); + + protected abstract int getHttpStatusCode(Response response); + + protected abstract String getResponseCode(Response response); + + protected abstract String getTargetEntity(Request request); + + protected void pre(Request request, RequestHeaders requestHeaders) { + try { + setupMDC(request); + setupHeaders(request, requestHeaders); + logger.info(ONAPLogConstants.Markers.INVOKE, "Invoke"); + } catch (Exception e) { + logger.warn("Error in AbstractMetricLogFilter pre", e); + } + } + + protected void setupHeaders(Request clientRequest, RequestHeaders requestHeaders) { + String requestId = extractRequestID(); + addHeader(requestHeaders, ONAPLogConstants.Headers.REQUEST_ID, requestId); + addHeader(requestHeaders, Constants.HttpHeaders.HEADER_REQUEST_ID, requestId); + addHeader(requestHeaders, Constants.HttpHeaders.TRANSACTION_ID, requestId); + addHeader(requestHeaders, Constants.HttpHeaders.ECOMP_REQUEST_ID, requestId); + addHeader(requestHeaders, ONAPLogConstants.Headers.INVOCATION_ID, MDC.get(ONAPLogConstants.MDCs.INVOCATION_ID)); + addHeader(requestHeaders, ONAPLogConstants.Headers.PARTNER_NAME, partnerName); + } + + protected void setupMDC(Request request) { + MDC.put(ONAPLogConstants.MDCs.INVOKE_TIMESTAMP, + ZonedDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT)); + // setup time stamp defaults + setLogTimestamp(); + setElapsedTimeInvokeTimestamp(); + MDC.put(ONAPLogConstants.MDCs.TARGET_SERVICE_NAME, getTargetServiceName(request)); + MDC.put(ONAPLogConstants.MDCs.RESPONSE_STATUS_CODE, ONAPLogConstants.ResponseStatus.INPROGRESS.toString()); + setInvocationIdFromMDC(); + + if (MDC.get(ONAPLogConstants.MDCs.TARGET_ENTITY) == null) { + String targetEntity = getTargetEntity(request); + if (targetEntity != null) { + MDC.put(ONAPLogConstants.MDCs.TARGET_ENTITY, targetEntity); + } else { + MDC.put(ONAPLogConstants.MDCs.TARGET_ENTITY, Constants.DefaultValues.UNKNOWN_TARGET_ENTITY); + } + } + + if (MDC.get(ONAPLogConstants.MDCs.SERVICE_NAME) == null) { + MDC.put(ONAPLogConstants.MDCs.SERVICE_NAME, getServiceName(request)); + } + setServerFQDN(); + } + + protected String extractRequestID() { + String requestId = MDC.get(ONAPLogConstants.MDCs.REQUEST_ID); + if (requestId == null || requestId.isEmpty()) { + requestId = UUID.randomUUID().toString(); + setLogTimestamp(); + setElapsedTimeInvokeTimestamp(); + logger.warn("No value found in MDC when checking key {} value will be set to {}", + ONAPLogConstants.MDCs.REQUEST_ID, requestId); + MDC.put(ONAPLogConstants.MDCs.REQUEST_ID, requestId); + } + return requestId; + } + + protected void post(Request request, Response response) { + try { + setLogTimestamp(); + setElapsedTimeInvokeTimestamp(); + setResponseStatusCode(getHttpStatusCode(response)); + setResponseDescription(getHttpStatusCode(response)); + MDC.put(ONAPLogConstants.MDCs.RESPONSE_CODE, getResponseCode(response)); + logger.info(INVOKE_RETURN, "InvokeReturn"); + clearClientMDCs(); + } catch (Exception e) { + logger.warn("Error in AbstractMetricLogFilter post", e); + } + } + + protected String getPartnerName() { + return getProperty(Constants.Property.PARTNER_NAME); + } + + protected void logInvoke() { + logger.info(ONAPLogConstants.Markers.INVOKE, "Invoke"); + } + +} diff --git a/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/AbstractServletFilter.java b/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/AbstractServletFilter.java new file mode 100644 index 00000000..28495c84 --- /dev/null +++ b/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/AbstractServletFilter.java @@ -0,0 +1,57 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - Logging + * ================================================================================ + * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.onap.logging.filter.base; + +import java.util.Enumeration; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.core.HttpHeaders; + +public abstract class AbstractServletFilter { + + protected String getSecureRequestHeaders(HttpServletRequest httpRequest) { + StringBuilder sb = new StringBuilder(); + String header; + for (Enumeration<String> e = httpRequest.getHeaderNames(); e.hasMoreElements();) { + header = e.nextElement(); + sb.append(header); + sb.append(":"); + if (header.equalsIgnoreCase(HttpHeaders.AUTHORIZATION)) { + sb.append(Constants.REDACTED); + } else { + sb.append(httpRequest.getHeader(header)); + } + sb.append(";"); + } + return sb.toString(); + } + + protected String formatResponseHeaders(HttpServletResponse response) { + StringBuilder sb = new StringBuilder(); + for (String headerName : response.getHeaderNames()) { + sb.append(headerName); + sb.append(":"); + sb.append(response.getHeader(headerName)); + sb.append(";"); + } + return sb.toString(); + } +} diff --git a/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/AuditLogContainerFilter.java b/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/AuditLogContainerFilter.java new file mode 100644 index 00000000..a0194850 --- /dev/null +++ b/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/AuditLogContainerFilter.java @@ -0,0 +1,67 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - Logging + * ================================================================================ + * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.onap.logging.filter.base; + +import java.io.IOException; +import javax.annotation.Priority; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.container.*; +import javax.ws.rs.core.Context; +import javax.ws.rs.ext.Provider; +import javax.ws.rs.ext.Providers; +import org.onap.logging.ref.slf4j.ONAPLogConstants; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.MDC; + +@Priority(1) +public class AuditLogContainerFilter extends AbstractAuditLogFilter<ContainerRequestContext, ContainerResponseContext> + implements ContainerRequestFilter, ContainerResponseFilter { + + @Context + private HttpServletRequest httpServletRequest; + + @Context + private Providers providers; + + @Override + public void filter(ContainerRequestContext containerRequest) { + SimpleMap headers = new SimpleJaxrsHeadersMap(containerRequest.getHeaders()); + pre(headers, containerRequest, httpServletRequest); + } + + @Override + public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) + throws IOException { + post(responseContext); + } + + @Override + protected void setServiceName(ContainerRequestContext containerRequest) { + MDC.put(ONAPLogConstants.MDCs.SERVICE_NAME, containerRequest.getUriInfo().getPath()); + } + + @Override + protected int getResponseCode(ContainerResponseContext response) { + return response.getStatus(); + } + +} diff --git a/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/AuditLogServletFilter.java b/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/AuditLogServletFilter.java new file mode 100644 index 00000000..a8f5eae9 --- /dev/null +++ b/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/AuditLogServletFilter.java @@ -0,0 +1,85 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - Logging + * ================================================================================ + * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Modifications Copyright (C) 2018 IBM. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.onap.logging.filter.base; + +import java.io.IOException; +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 javax.servlet.http.HttpServletResponse; +import org.onap.logging.ref.slf4j.ONAPLogConstants; +import org.slf4j.MDC; + +public class AuditLogServletFilter extends AbstractAuditLogFilter<HttpServletRequest, HttpServletResponse> + implements Filter { + + @Override + public void destroy() { + // this method does nothing + } + + @Override + public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain filterChain) + throws IOException, ServletException { + try { + if (request != null && request instanceof HttpServletRequest) { + pre((HttpServletRequest) request); + } + filterChain.doFilter(request, response); + } finally { + if (request != null && request instanceof HttpServletRequest) { + post((HttpServletRequest) request, (HttpServletResponse) response); + } + MDC.clear(); + } + } + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + // this method does nothing + } + + protected void pre(HttpServletRequest request) { + SimpleMap headers = new SimpleServletHeadersMap(request); + pre(headers, request, request); + } + + @Override + protected void setServiceName(HttpServletRequest request) { + MDC.put(ONAPLogConstants.MDCs.SERVICE_NAME, request.getRequestURI()); + } + + private void post(HttpServletRequest request, HttpServletResponse response) { + post(response); + } + + @Override + protected int getResponseCode(HttpServletResponse response) { + return response.getStatus(); + } + +} diff --git a/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/Constants.java b/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/Constants.java new file mode 100644 index 00000000..be28f0bc --- /dev/null +++ b/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/Constants.java @@ -0,0 +1,46 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - Logging + * ================================================================================ + * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.onap.logging.filter.base; + +public class Constants { + protected static final String REDACTED = "***REDACTED***"; + + public static final class DefaultValues { + public static final String UNKNOWN = "UNKNOWN"; + public static final String UNKNOWN_TARGET_ENTITY = "Unknown-Target-Entity"; + } + + public static final class HttpHeaders { + public static final String HEADER_FROM_APP_ID = "X-FromAppId"; + public static final String ONAP_PARTNER_NAME = "X-ONAP-PartnerName"; + public static final String HEADER_REQUEST_ID = "X-RequestID"; + public static final String TRANSACTION_ID = "X-TransactionID"; + public static final String ECOMP_REQUEST_ID = "X-ECOMP-RequestID"; + public static final String ONAP_REQUEST_ID = "X-ONAP-RequestID"; + public static final String CLIENT_ID = "X-ClientID"; + public static final String INVOCATION_ID_HEADER = "X-InvocationID"; + public static final String TARGET_ENTITY_HEADER = "X-Target-Entity"; + } + + public static final class Property { + public static final String PARTNER_NAME = "partnerName"; + } +} diff --git a/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/MDCSetup.java b/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/MDCSetup.java new file mode 100644 index 00000000..369a9f20 --- /dev/null +++ b/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/MDCSetup.java @@ -0,0 +1,238 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - Logging + * ================================================================================ + * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.onap.logging.filter.base; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoUnit; +import java.util.UUID; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.Response; +import org.onap.logging.ref.slf4j.ONAPLogConstants; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.MDC; + +public class MDCSetup { + + protected static Logger logger = LoggerFactory.getLogger(MDCSetup.class); + + private static final String INSTANCE_UUID = UUID.randomUUID().toString(); + + public void setInstanceID() { + MDC.put(ONAPLogConstants.MDCs.INSTANCE_UUID, INSTANCE_UUID); + } + + public void setServerFQDN() { + String serverFQDN = ""; + InetAddress addr = null; + try { + addr = InetAddress.getLocalHost(); + serverFQDN = addr.getCanonicalHostName(); + MDC.put(ONAPLogConstants.MDCs.SERVER_IP_ADDRESS, addr.getHostAddress()); + } catch (UnknownHostException e) { + logger.warn("Cannot Resolve Host Name"); + serverFQDN = ""; + } + MDC.put(ONAPLogConstants.MDCs.SERVER_FQDN, serverFQDN); + } + + public void setClientIPAddress(HttpServletRequest httpServletRequest) { + String clientIpAddress = ""; + if (httpServletRequest != null) { + // This logic is to avoid setting the client ip address to that of the load + // balancer in front of the application + String getForwadedFor = httpServletRequest.getHeader("X-Forwarded-For"); + if (getForwadedFor != null) { + clientIpAddress = getForwadedFor; + } else { + clientIpAddress = httpServletRequest.getRemoteAddr(); + } + } + MDC.put(ONAPLogConstants.MDCs.CLIENT_IP_ADDRESS, clientIpAddress); + } + + public void setEntryTimeStamp() { + MDC.put(ONAPLogConstants.MDCs.ENTRY_TIMESTAMP, + ZonedDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT)); + } + + public String getRequestId(SimpleMap headers) { + logger.trace("Checking X-ONAP-RequestID header for requestId."); + String requestId = headers.get(ONAPLogConstants.Headers.REQUEST_ID); + if (requestId != null && !requestId.isEmpty() && isValidUUID(requestId)) { + return requestId; + } + if (requestId != null && !requestId.isEmpty()) { + //invalid + return UUID.randomUUID().toString(); + } + logger.trace("No valid X-ONAP-RequestID header value. Checking X-RequestID header for requestId."); + requestId = headers.get(Constants.HttpHeaders.HEADER_REQUEST_ID); + if (requestId != null && !requestId.isEmpty() && isValidUUID(requestId)) { + return requestId; + } + if (requestId != null && !requestId.isEmpty()) { + //invalid + return UUID.randomUUID().toString(); + } + logger.trace("No valid X-RequestID header value. Checking X-TransactionID header for requestId."); + requestId = headers.get(Constants.HttpHeaders.TRANSACTION_ID); + if (requestId != null && !requestId.isEmpty() && isValidUUID(requestId)) { + return requestId; + } + if (requestId != null && !requestId.isEmpty()) { + //invalid + return UUID.randomUUID().toString(); + } + logger.trace("No valid X-TransactionID header value. Checking X-ECOMP-RequestID header for requestId."); + requestId = headers.get(Constants.HttpHeaders.ECOMP_REQUEST_ID); + if (requestId != null && !requestId.isEmpty() && isValidUUID(requestId)) { + return requestId; + } + if (requestId != null && !requestId.isEmpty()) { + //invalid + return UUID.randomUUID().toString(); + } + return requestId; + } + protected boolean isValidUUID(String transId) { + try { + UUID.fromString(transId); + } catch (IllegalArgumentException e) { + return false; + } + return true; + } + public void setInvocationId(SimpleMap headers) { + String invocationId = headers.get(ONAPLogConstants.Headers.INVOCATION_ID); + if (invocationId == null || invocationId.isEmpty()) + invocationId = UUID.randomUUID().toString(); + MDC.put(ONAPLogConstants.MDCs.INVOCATION_ID, invocationId); + } + + public void setInvocationIdFromMDC() { + String invocationId = MDC.get(ONAPLogConstants.MDCs.INVOCATION_ID); + if (invocationId == null || invocationId.isEmpty()) + invocationId = UUID.randomUUID().toString(); + MDC.put(ONAPLogConstants.MDCs.INVOCATION_ID, invocationId); + } + + public void setMDCPartnerName(SimpleMap headers) { + logger.trace("Checking X-ONAP-PartnerName header for partnerName."); + String partnerName = headers.get(ONAPLogConstants.Headers.PARTNER_NAME); + if (partnerName == null || partnerName.isEmpty()) { + logger.trace("No valid X-ONAP-PartnerName header value. Checking User-Agent header for partnerName."); + partnerName = headers.get(HttpHeaders.USER_AGENT); + if (partnerName == null || partnerName.isEmpty()) { + logger.trace("No valid User-Agent header value. Checking X-ClientID header for partnerName."); + partnerName = headers.get(Constants.HttpHeaders.CLIENT_ID); + if (partnerName == null || partnerName.isEmpty()) { + logger.trace("No valid partnerName headers. Defaulting partnerName to UNKNOWN."); + partnerName = Constants.DefaultValues.UNKNOWN; + } + } + } + MDC.put(ONAPLogConstants.MDCs.PARTNER_NAME, partnerName); + } + + public void setLogTimestamp() { + MDC.put(ONAPLogConstants.MDCs.LOG_TIMESTAMP, + ZonedDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT)); + } + + public void setElapsedTime() { + DateTimeFormatter timeFormatter = DateTimeFormatter.ISO_ZONED_DATE_TIME; + ZonedDateTime entryTimestamp = + ZonedDateTime.parse(MDC.get(ONAPLogConstants.MDCs.ENTRY_TIMESTAMP), timeFormatter); + ZonedDateTime endTimestamp = ZonedDateTime.parse(MDC.get(ONAPLogConstants.MDCs.LOG_TIMESTAMP), timeFormatter); + + MDC.put(ONAPLogConstants.MDCs.ELAPSED_TIME, + Long.toString(ChronoUnit.MILLIS.between(entryTimestamp, endTimestamp))); + } + + public void setElapsedTimeInvokeTimestamp() { + DateTimeFormatter timeFormatter = DateTimeFormatter.ISO_ZONED_DATE_TIME; + ZonedDateTime entryTimestamp = + ZonedDateTime.parse(MDC.get(ONAPLogConstants.MDCs.INVOKE_TIMESTAMP), timeFormatter); + ZonedDateTime endTimestamp = ZonedDateTime.parse(MDC.get(ONAPLogConstants.MDCs.LOG_TIMESTAMP), timeFormatter); + + MDC.put(ONAPLogConstants.MDCs.ELAPSED_TIME, + Long.toString(ChronoUnit.MILLIS.between(entryTimestamp, endTimestamp))); + } + + public void setResponseStatusCode(int code) { + String statusCode; + if (Response.Status.Family.familyOf(code).equals(Response.Status.Family.SUCCESSFUL)) { + statusCode = ONAPLogConstants.ResponseStatus.COMPLETE.toString(); + } else { + statusCode = ONAPLogConstants.ResponseStatus.ERROR.toString(); + setErrorCode(code); + setErrorDesc(code); + } + MDC.put(ONAPLogConstants.MDCs.RESPONSE_STATUS_CODE, statusCode); + } + + public void setTargetEntity(ONAPComponentsList targetEntity) { + MDC.put(ONAPLogConstants.MDCs.TARGET_ENTITY, targetEntity.toString()); + } + + public void clearClientMDCs() { + //MDC.remove(ONAPLogConstants.MDCs.INVOCATION_ID); + MDC.remove(ONAPLogConstants.MDCs.RESPONSE_DESCRIPTION); + MDC.remove(ONAPLogConstants.MDCs.RESPONSE_STATUS_CODE); + MDC.remove(ONAPLogConstants.MDCs.RESPONSE_CODE); + MDC.remove(ONAPLogConstants.MDCs.TARGET_ENTITY); + MDC.remove(ONAPLogConstants.MDCs.TARGET_SERVICE_NAME); + MDC.remove(ONAPLogConstants.MDCs.INVOKE_TIMESTAMP); + MDC.remove(ONAPLogConstants.MDCs.ERROR_CODE); + MDC.remove(ONAPLogConstants.MDCs.ERROR_DESC); + } + + public void setResponseDescription(int statusCode) { + MDC.put(ONAPLogConstants.MDCs.RESPONSE_DESCRIPTION, Response.Status.fromStatusCode(statusCode).toString()); + } + + public void setErrorCode(int statusCode) { + MDC.put(ONAPLogConstants.MDCs.ERROR_CODE, String.valueOf(statusCode)); + } + + public void setErrorDesc(int statusCode) { + MDC.put(ONAPLogConstants.MDCs.ERROR_DESC, Response.Status.fromStatusCode(statusCode).toString()); + } + + public String getProperty(String property) { + logger.info("Checking for system property [{}]", property); + String propertyValue = System.getProperty(property); + if (propertyValue == null || propertyValue.isEmpty()) { + logger.info("System property was null or empty. Checking environment variable for: {}", property); + propertyValue = System.getenv(property); + if (propertyValue == null || propertyValue.isEmpty()) { + logger.info("Environment variable: {} was null or empty", property ); + } + } + return propertyValue; + } +} diff --git a/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/MetricLogClientFilter.java b/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/MetricLogClientFilter.java new file mode 100644 index 00000000..da4d9827 --- /dev/null +++ b/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/MetricLogClientFilter.java @@ -0,0 +1,82 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - Logging + * ================================================================================ + * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.onap.logging.filter.base; + +import javax.annotation.Priority; +import javax.ws.rs.client.ClientRequestContext; +import javax.ws.rs.client.ClientRequestFilter; +import javax.ws.rs.client.ClientResponseContext; +import javax.ws.rs.client.ClientResponseFilter; +import javax.ws.rs.container.PreMatching; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.ext.Provider; +import javax.ws.rs.ext.Providers; + +@Priority(0) +public class MetricLogClientFilter + extends AbstractMetricLogFilter<ClientRequestContext, ClientResponseContext, MultivaluedMap<String, Object>> + implements ClientRequestFilter, ClientResponseFilter { + + @Context + private Providers providers; + + @Override + public void filter(ClientRequestContext clientRequest) { + pre(clientRequest, clientRequest.getHeaders()); + } + + @Override + public void filter(ClientRequestContext requestContext, ClientResponseContext responseContext) { + post(requestContext, responseContext); + } + + @Override + protected void addHeader(MultivaluedMap<String, Object> requestHeaders, String headerName, String headerValue) { + requestHeaders.add(headerName, headerValue); + } + + @Override + protected String getTargetServiceName(ClientRequestContext request) { + return request.getUri().toString(); + } + + @Override + protected String getServiceName(ClientRequestContext request) { + return request.getUri().getPath(); + } + + @Override + protected int getHttpStatusCode(ClientResponseContext response) { + return response.getStatus(); + } + + @Override + protected String getResponseCode(ClientResponseContext response) { + return String.valueOf(response.getStatus()); + } + + @Override + protected String getTargetEntity(ClientRequestContext request) { + return Constants.DefaultValues.UNKNOWN_TARGET_ENTITY; + } + +} diff --git a/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/ONAPComponents.java b/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/ONAPComponents.java new file mode 100644 index 00000000..06fbba9a --- /dev/null +++ b/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/ONAPComponents.java @@ -0,0 +1,80 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - Logging + * ================================================================================ + * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.onap.logging.filter.base; + +import java.util.EnumSet; +import java.util.Set; + +public enum ONAPComponents implements ONAPComponentsList { + OPENSTACK_ADAPTER, + BPMN, + GRM, + AAI, + DMAAP, + POLICY, + CATALOG_DB, + REQUEST_DB, + SNIRO, + SDC, + EXTERNAL, + VNF_ADAPTER, + SDNC_ADAPTER, + MULTICLOUD, + CLAMP, + PORTAL, + VID, + APPC, + DCAE, + HOLMES, + SDNC, + SO, + VFC, + ESR, + DBC, + DR, + MR, + OPTF; + + + public static Set<ONAPComponents> getSOInternalComponents() { + return EnumSet.of(OPENSTACK_ADAPTER, BPMN, CATALOG_DB, REQUEST_DB, VNF_ADAPTER, SDNC_ADAPTER); + } + + public static Set<ONAPComponents> getDMAAPInternalComponents() { + return EnumSet.of(DBC, DR, MR); + } + + public static Set<ONAPComponents> getAAIInternalComponents() { + return EnumSet.of(ESR); + } + + @Override + public String toString() { + if (getSOInternalComponents().contains(this)) + return SO + "." + this.name(); + else if (getDMAAPInternalComponents().contains(this)) + return DMAAP + "." + this.name(); + else if (getAAIInternalComponents().contains(this)) + return AAI + "." + this.name(); + else + return this.name(); + } +} diff --git a/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/ONAPComponentsList.java b/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/ONAPComponentsList.java new file mode 100644 index 00000000..7ffc2517 --- /dev/null +++ b/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/ONAPComponentsList.java @@ -0,0 +1,25 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - Logging + * ================================================================================ + * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.onap.logging.filter.base; + +public interface ONAPComponentsList { + +} diff --git a/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/PayloadLoggingClientFilter.java b/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/PayloadLoggingClientFilter.java new file mode 100644 index 00000000..88c95aa4 --- /dev/null +++ b/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/PayloadLoggingClientFilter.java @@ -0,0 +1,162 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - Logging + * ================================================================================ + * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.onap.logging.filter.base; + +import java.io.BufferedInputStream; +import java.io.ByteArrayOutputStream; +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.client.ClientRequestContext; +import javax.ws.rs.client.ClientRequestFilter; +import javax.ws.rs.client.ClientResponseContext; +import javax.ws.rs.client.ClientResponseFilter; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MultivaluedHashMap; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.ext.WriterInterceptor; +import javax.ws.rs.ext.WriterInterceptorContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class PayloadLoggingClientFilter implements ClientRequestFilter, ClientResponseFilter, WriterInterceptor { + + private static final Logger logger = LoggerFactory.getLogger(PayloadLoggingClientFilter.class); + private static final String ENTITY_STREAM_PROPERTY = "LoggingFilter.entityStream"; + private static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8; + private final int maxEntitySize; + + public PayloadLoggingClientFilter() { + maxEntitySize = 1024 * 1024; + } + + public PayloadLoggingClientFilter(int maxPayloadSize) { + this.maxEntitySize = Integer.min(maxPayloadSize, 1024 * 1024); + } + + protected InputStream logInboundEntity(final StringBuilder b, InputStream stream, final Charset charset) + throws IOException { + if (!stream.markSupported()) { + stream = new BufferedInputStream(stream); + } + stream.mark(maxEntitySize + 1); + final byte[] entity = new byte[maxEntitySize + 1]; + final int entitySize = stream.read(entity); + if (entitySize != -1) { + b.append(new String(entity, 0, Math.min(entitySize, maxEntitySize), charset)); + } + if (entitySize > maxEntitySize) { + b.append("...more..."); + } + b.append('\n'); + stream.reset(); + return stream; + } + + @Override + public void filter(ClientRequestContext requestContext) throws IOException { + if (requestContext.hasEntity()) { + final OutputStream stream = new LoggingStream(requestContext.getEntityStream()); + requestContext.setEntityStream(stream); + requestContext.setProperty(ENTITY_STREAM_PROPERTY, stream); + } + String method = formatMethod(requestContext); + logger.debug("Sending HTTP {} to:{} with request headers:{}", method, requestContext.getUri(), + getHeaders(requestContext.getHeaders())); + } + + protected String getHeaders(MultivaluedMap<String, Object> headers) { + MultivaluedMap<String, Object> printHeaders = new MultivaluedHashMap<>(); + for (String header : headers.keySet()) { + if (!header.equals(HttpHeaders.AUTHORIZATION)) { + printHeaders.add(header, headers.getFirst(header)); + } else { + printHeaders.add(header, Constants.REDACTED);; + } + } + return printHeaders.toString(); + } + + @Override + public void filter(ClientRequestContext requestContext, ClientResponseContext responseContext) throws IOException { + String method = formatMethod(requestContext); + logger.debug("Response from method:{} performed on uri:{} has http status code:{} and response headers:{}", + method, requestContext.getUri(), responseContext.getStatus(), responseContext.getHeaders().toString()); + if (responseContext.hasEntity()) { + final StringBuilder sb = new StringBuilder(); + responseContext.setEntityStream(logInboundEntity(sb, responseContext.getEntityStream(), DEFAULT_CHARSET)); + logger.debug(sb.toString()); + } + } + + @Override + public void aroundWriteTo(WriterInterceptorContext context) throws IOException, WebApplicationException { + final LoggingStream stream = (LoggingStream) context.getProperty(ENTITY_STREAM_PROPERTY); + context.proceed(); + if (stream != null) { + logger.debug(stream.getStringBuilder(DEFAULT_CHARSET).toString()); + } + } + + private class LoggingStream extends FilterOutputStream { + + private final StringBuilder sb = new StringBuilder(); + private final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + LoggingStream(OutputStream out) { + super(out); + } + + StringBuilder getStringBuilder(Charset charset) { + // write entity to the builder + final byte[] entity = baos.toByteArray(); + + sb.append(new String(entity, 0, entity.length, charset)); + if (entity.length > maxEntitySize) { + sb.append("...more..."); + } + sb.append('\n'); + + return sb; + } + + @Override + public void write(final int i) throws IOException { + if (baos.size() <= maxEntitySize) { + baos.write(i); + } + out.write(i); + } + } + + protected String formatMethod(ClientRequestContext requestContext) { + String httpMethodOverride = requestContext.getHeaderString("X-HTTP-Method-Override"); + if (httpMethodOverride == null) { + return requestContext.getMethod(); + } else { + return requestContext.getMethod() + " (overridden to " + httpMethodOverride + ")"; + } + } +} diff --git a/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/PayloadLoggingServletFilter.java b/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/PayloadLoggingServletFilter.java new file mode 100644 index 00000000..fa8533a7 --- /dev/null +++ b/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/PayloadLoggingServletFilter.java @@ -0,0 +1,330 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - Logging + * ================================================================================ + * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Modifications Copyright (C) 2018 IBM. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.onap.logging.filter.base; + +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.util.zip.GZIPInputStream; +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ReadListener; +import javax.servlet.ServletException; +import javax.servlet.ServletInputStream; +import javax.servlet.ServletOutputStream; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.WriteListener; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpServletResponseWrapper; + +public class PayloadLoggingServletFilter extends AbstractServletFilter implements Filter { + + private static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(PayloadLoggingServletFilter.class); + + private static class ByteArrayServletStream extends ServletOutputStream { + ByteArrayOutputStream baos; + + ByteArrayServletStream(ByteArrayOutputStream baos) { + this.baos = baos; + } + + @Override + public void write(int param) throws IOException { + baos.write(param); + } + + @Override + public boolean isReady() { + return true; + } + + @Override + public void setWriteListener(WriteListener arg0) { + // this method does nothing + } + } + + private static class ByteArrayPrintWriter extends PrintWriter { + private ByteArrayOutputStream baos; + private int errorCode = -1; + private String errorMsg = ""; + private boolean errored = false; + + public ByteArrayPrintWriter(ByteArrayOutputStream out) { + super(out); + this.baos = out; + } + + public ServletOutputStream getStream() { + return new ByteArrayServletStream(baos); + } + + public Boolean hasErrored() { + return errored; + } + + public int getErrorCode() { + return errorCode; + } + + public String getErrorMsg() { + return errorMsg; + } + + public void setError(int code) { + errorCode = code; + errored = true; + } + + public void setError(int code, String msg) { + errorMsg = msg; + errorCode = code; + errored = true; + } + + } + + private class BufferedServletInputStream extends ServletInputStream { + ByteArrayInputStream bais; + + public BufferedServletInputStream(ByteArrayInputStream bais) { + this.bais = bais; + } + + @Override + public int available() { + return bais.available(); + } + + @Override + public int read() { + return bais.read(); + } + + @Override + public int read(byte[] buf, int off, int len) { + return bais.read(buf, off, len); + } + + @Override + public boolean isFinished() { + return available() < 1; + } + + @Override + public boolean isReady() { + return true; + } + + @Override + public void setReadListener(ReadListener arg0) { + // this method does nothing + } + + } + + private class BufferedRequestWrapper extends HttpServletRequestWrapper { + ByteArrayInputStream bais; + ByteArrayOutputStream baos; + BufferedServletInputStream bsis; + byte[] buffer; + + public BufferedRequestWrapper(HttpServletRequest req) throws IOException { + super(req); + + InputStream is = req.getInputStream(); + baos = new ByteArrayOutputStream(); + byte[] buf = new byte[1024]; + int letti; + while ((letti = is.read(buf)) > 0) { + baos.write(buf, 0, letti); + } + buffer = baos.toByteArray(); + } + + @Override + public ServletInputStream getInputStream() { + try { + bais = new ByteArrayInputStream(buffer); + bsis = new BufferedServletInputStream(bais); + } catch (Exception ex) { + log.error("Exception in getInputStream", ex); + } + return bsis; + } + + public byte[] getBuffer() { + return buffer; + } + } + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + // this method does nothing + } + + @Override + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) + throws IOException, ServletException { + final HttpServletRequest httpRequest = (HttpServletRequest) servletRequest; + BufferedRequestWrapper bufferedRequest = new BufferedRequestWrapper(httpRequest); + + StringBuilder requestHeaders = new StringBuilder("REQUEST|"); + requestHeaders.append(httpRequest.getMethod()); + requestHeaders.append(":"); + requestHeaders.append(httpRequest.getRequestURL().toString()); + requestHeaders.append("|"); + requestHeaders.append(getSecureRequestHeaders(httpRequest)); + log.info(requestHeaders.toString()); + + log.info("REQUEST BODY|" + new String(bufferedRequest.getBuffer())); + + final HttpServletResponse response = (HttpServletResponse) servletResponse; + final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + final ByteArrayPrintWriter pw = new ByteArrayPrintWriter(baos); + + HttpServletResponse wrappedResp = new HttpServletResponseWrapper(response) { + @Override + public PrintWriter getWriter() { + return pw; + } + + @Override + public ServletOutputStream getOutputStream() { + return pw.getStream(); + } + + @Override + public void sendError(int sc) throws IOException { + super.sendError(sc); + pw.setError(sc); + + } + + @Override + public void sendError(int sc, String msg) throws IOException { + super.sendError(sc, msg); + pw.setError(sc, msg); + } + }; + + try { + filterChain.doFilter(bufferedRequest, wrappedResp); + } catch (Exception e) { + log.error("Chain Exception", e); + throw e; + } finally { + try { + byte[] bytes = baos.toByteArray(); + StringBuilder responseHeaders = new StringBuilder("RESPONSE HEADERS|"); + responseHeaders.append(formatResponseHeaders(response)); + responseHeaders.append("Status:"); + responseHeaders.append(response.getStatus()); + responseHeaders.append(";IsCommited:" + wrappedResp.isCommitted()); + + log.info(responseHeaders.toString()); + + if ("gzip".equals(response.getHeader("Content-Encoding"))) { + log.info("UNGZIPED RESPONSE BODY|" + decompressGZIPByteArray(bytes)); + } else { + log.info("RESPONSE BODY|" + new String(bytes)); + } + + if (pw.hasErrored()) { + log.info("ERROR RESPONSE|" + pw.getErrorCode() + ":" + pw.getErrorMsg()); + } else { + if (!wrappedResp.isCommitted()) { + response.getOutputStream().write(bytes); + response.getOutputStream().flush(); + } + } + } catch (Exception e) { + log.error("Exception in response filter", e); + } + } + } + + @Override + public void destroy() { + // this method does nothing + } + + private String decompressGZIPByteArray(byte[] bytes) { + BufferedReader in = null; + InputStreamReader inR = null; + ByteArrayInputStream byteS = null; + GZIPInputStream gzS = null; + StringBuilder str = new StringBuilder(); + try { + byteS = new ByteArrayInputStream(bytes); + gzS = new GZIPInputStream(byteS); + inR = new InputStreamReader(gzS); + in = new BufferedReader(inR); + + if (in != null) { + String content; + while ((content = in.readLine()) != null) { + str.append(content); + } + } + + } catch (Exception e) { + log.error("Failed get read GZIPInputStream", e); + } finally { + if (byteS != null) + try { + byteS.close(); + } catch (IOException e1) { + log.error("Failed to close ByteStream", e1); + } + if (gzS != null) + try { + gzS.close(); + } catch (IOException e2) { + log.error("Failed to close GZStream", e2); + } + if (inR != null) + try { + inR.close(); + } catch (IOException e3) { + log.error("Failed to close InputReader", e3); + } + if (in != null) + try { + in.close(); + } catch (IOException e) { + log.error("Failed to close BufferedReader", e); + } + } + return str.toString(); + } + +} diff --git a/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/SimpleHashMap.java b/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/SimpleHashMap.java new file mode 100644 index 00000000..1e9cedb7 --- /dev/null +++ b/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/SimpleHashMap.java @@ -0,0 +1,37 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - Logging + * ================================================================================ + * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.onap.logging.filter.base; + +import java.util.HashMap; + +public class SimpleHashMap implements SimpleMap { + private HashMap<String, String> map; + + public SimpleHashMap(HashMap<String, String> map) { + this.map = map; + } + + @Override + public String get(String key) { + return map.get(key); + } + +} diff --git a/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/SimpleJaxrsHeadersMap.java b/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/SimpleJaxrsHeadersMap.java new file mode 100644 index 00000000..50074782 --- /dev/null +++ b/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/SimpleJaxrsHeadersMap.java @@ -0,0 +1,37 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - Logging + * ================================================================================ + * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.onap.logging.filter.base; + +import javax.ws.rs.core.MultivaluedMap; + +public class SimpleJaxrsHeadersMap implements SimpleMap { + MultivaluedMap<String, String> map; + + public SimpleJaxrsHeadersMap(MultivaluedMap<String, String> map) { + this.map = map; + } + + @Override + public String get(String key) { + return map.getFirst(key); + } + +} diff --git a/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/SimpleMap.java b/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/SimpleMap.java new file mode 100644 index 00000000..9543721f --- /dev/null +++ b/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/SimpleMap.java @@ -0,0 +1,25 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - Logging + * ================================================================================ + * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.onap.logging.filter.base; + +public interface SimpleMap { + String get(String key); +} diff --git a/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/SimpleServletHeadersMap.java b/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/SimpleServletHeadersMap.java new file mode 100644 index 00000000..e6a91fbe --- /dev/null +++ b/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/SimpleServletHeadersMap.java @@ -0,0 +1,37 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - Logging + * ================================================================================ + * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.onap.logging.filter.base; + +import javax.servlet.http.HttpServletRequest; + +public class SimpleServletHeadersMap implements SimpleMap { + private HttpServletRequest request; + + public SimpleServletHeadersMap(HttpServletRequest request) { + this.request = request; + } + + @Override + public String get(String key) { + return request.getHeader(key); + } + +} diff --git a/aai-els-onap-logging/src/main/java/org/onap/logging/ref/slf4j/ONAPLogAdapter.java b/aai-els-onap-logging/src/main/java/org/onap/logging/ref/slf4j/ONAPLogAdapter.java new file mode 100644 index 00000000..aafc74d4 --- /dev/null +++ b/aai-els-onap-logging/src/main/java/org/onap/logging/ref/slf4j/ONAPLogAdapter.java @@ -0,0 +1,616 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.logging + * ================================================================================ + * Copyright © 2018 Amdocs + * All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.onap.logging.ref.slf4j; + +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.UUID; + +import javax.servlet.http.HttpServletRequest; + +import org.slf4j.Logger; +import org.slf4j.MDC; +import org.slf4j.Marker; +import org.slf4j.event.Level; + +/** + * Extensible adapter for cheaply meeting ONAP logging obligations using + * an SLF4J facade. + * + * <p>This can be used with any SLF4J-compatible logging provider, with + * appropriate provider configuration.</p> + * + * <p>The basics are that: + * <ul> + * <li>{@link #entering} sets all MDCs.</li> + * <li>{@link #exiting} unsets all MDCs *and* logs response information.</li> + * <li>{@link #invoke} logs and returns a UUID to passed during invocation, + * and optionally sets these for you on your downstream request by way of + * an adapter.</li> + * <li>Call {@link #getServiceDescriptor()} and its setters to set service-related MDCs.</li> + * <li>Call {@link #getResponseDescriptor()} and its setters to set response-related MDCs.</li> + * </ul> + * </p> + * + * <p>Minimal usage is: + * <ol> + * <li>#entering(RequestAdapter)</li> + * <li>#invoke, #invoke, ...</li> + * <li>#getResponse + setters (or #setResponse)</li> + * <li>#exiting</li> + * </ol> + * </p> + * + * <p> ... if you're happy for service information to be automatically derived as follows: + * <ul> + * <li><tt>ServiceName</tt> - from <tt>HttpServletRequest#getRequestURI()</tt></li> + * <li><tt>InstanceUUID</tt> - classloader-scope UUID.</li> + * </ul> + * </p> + * + * <p>... and if those defaults don't suit, then you can override using properties on + * {@link #getServiceDescriptor()}, or by injecting your own adapter using + * {@link #setServiceDescriptor(ServiceDescriptor)}, or by overriding + * a <tt>protected</tt> methods like{@link #setEnteringMDCs}.</p> + * + * <p>For everything else: + * <ul> + * <li>The underlying SLF4J {@link Logger} can be retrieved using {@link #unwrap}. + * Use this or create your own using the usual SLF4J factor.</li> + * <li>Set whatever MDCs you like.</li> + * <li>Log whatever else you like.</li> + * </ul> + * </p> + */ +public class ONAPLogAdapter { + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // + // Constants. + // + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + /** String constant for messages <tt>ENTERING</tt>, <tt>EXITING</tt>, etc. */ + private static final String EMPTY_MESSAGE = ""; + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // + // Fields. + // + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + /** Automatic UUID, overrideable per adapter or per invocation. */ + private static UUID sInstanceUUID = UUID.randomUUID(); + + /** Logger delegate. */ + private Logger mLogger; + + /** Overrideable descriptor for the service doing the logging. */ + private ServiceDescriptor mServiceDescriptor = new ServiceDescriptor(); + + /** Overrideable descriptor for the response returned by the service doing the logging. */ + private ResponseDescriptor mResponseDescriptor = new ResponseDescriptor(); + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // + // Constructors. + // + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Construct adapter. + * + * @param logger non-null logger. + */ + public ONAPLogAdapter(final Logger logger) { + this.mLogger = checkNotNull(logger); + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // + // Public methods. + // + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Get logger. + * + * @return unwrapped logger. + */ + public Logger unwrap() { + return this.mLogger; + } + + /** + * Report <tt>ENTERING</tt> marker. + * + * @param request non-null incoming request (wrapper). + * @return this. + */ + public ONAPLogAdapter entering(final RequestAdapter request) { + + checkNotNull(request); + + // Default the service name. + + this.setEnteringMDCs(request); + this.mLogger.info(ONAPLogConstants.Markers.ENTRY, EMPTY_MESSAGE); + + return this; + } + + /** + * Report <tt>ENTERING</tt> marker. + * + * @param request non-null incoming request. + * @return this. + */ + public ONAPLogAdapter entering(final HttpServletRequest request) { + return this.entering(new HttpServletRequestAdapter(checkNotNull(request))); + } + + /** + * Report <tt>EXITING</tt> marker. + * + * @return this. + */ + public ONAPLogAdapter exiting() { + try { + this.mResponseDescriptor.setMDCs(); + this.mLogger.info(ONAPLogConstants.Markers.EXIT, EMPTY_MESSAGE); + } + finally { + MDC.clear(); + } + return this; + } + + /** + * Report pending invocation with <tt>INVOKE</tt> marker. + * + * <p>If you call this variant, then YOU are assuming responsibility for + * setting the requisite ONAP headers.</p> + * + * @param sync whether synchronous. + * @return invocation ID to be passed with invocation. + */ + public UUID invoke(final ONAPLogConstants.InvocationMode sync) { + + final UUID invocationID = UUID.randomUUID(); + + // Derive SYNC/ASYNC marker. + + final Marker marker = (sync == null) ? ONAPLogConstants.Markers.INVOKE : sync.getMarker(); + + // Log INVOKE*, with the invocationID as the message body. + // (We didn't really want this kind of behavior in the standard, + // but is it worse than new, single-message MDC?) + + this.mLogger.info(marker, "{}", invocationID); + return invocationID; + } + + /** + * Report pending invocation with <tt>INVOKE</tt> marker, + * setting standard ONAP logging headers automatically. + * + * @param builder request builder, for setting headers. + * @param sync whether synchronous, nullable. + * @return invocation ID to be passed with invocation. + */ + public UUID invoke(final RequestBuilder builder, + final ONAPLogConstants.InvocationMode sync) { + + // Sync can be defaulted. Builder cannot. + + checkNotNull(builder); + + // Log INVOKE, and retain invocation ID for header + return. + + final UUID invocationID = this.invoke(sync); + + // Set standard HTTP headers on (southbound request) builder. + + builder.setHeader(ONAPLogConstants.Headers.REQUEST_ID, + defaultToEmpty(MDC.get(ONAPLogConstants.MDCs.REQUEST_ID))); + builder.setHeader(ONAPLogConstants.Headers.INVOCATION_ID, + defaultToEmpty(invocationID)); + builder.setHeader(ONAPLogConstants.Headers.PARTNER_NAME, + defaultToEmpty(MDC.get(ONAPLogConstants.MDCs.PARTNER_NAME))); + + return invocationID; + } + + /** + * Report vanilla <tt>INVOKE</tt> marker. + * + * @param builder builder for downstream requests, if you want the + * standard ONAP headers to be added automatically. + * @return invocation ID to be passed with invocation. + */ + public UUID invoke(final RequestBuilder builder) { + return this.invoke(builder, (ONAPLogConstants.InvocationMode)null); + } + + /** + * Get descriptor, for overriding service details. + * @return non-null descriptor. + */ + public ServiceDescriptor getServiceDescriptor() { + return checkNotNull(this.mServiceDescriptor); + } + + /** + * Override {@link ServiceDescriptor}. + * @param d non-null override. + * @return this. + */ + public ONAPLogAdapter setServiceDescriptor(final ServiceDescriptor d) { + this.mServiceDescriptor = checkNotNull(d); + return this; + } + + /** + * Get descriptor, for setting response details. + * @return non-null descriptor. + */ + public ResponseDescriptor getResponseDescriptor() { + return checkNotNull(this.mResponseDescriptor); + } + + /** + * Override {@link ResponseDescriptor}. + * @param d non-null override. + * @return this. + */ + public ONAPLogAdapter setResponseDescriptor(final ResponseDescriptor d) { + this.mResponseDescriptor = checkNotNull(d); + return this; + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // + // Protected methods. + // + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Set MDCs that persist for the duration of an invocation. + * + * <p>It would be better to roll this into {@link #entering}, like + * with {@link #exiting}. Then it would be easier to do, but it + * would mean more work. </p> + * + * @param request incoming HTTP request. + * @return this. + */ + protected ONAPLogAdapter setEnteringMDCs(final RequestAdapter<?> request) { + + // Extract MDC values from standard HTTP headers. + + final String requestID = defaultToUUID(request.getHeader(ONAPLogConstants.Headers.REQUEST_ID)); + final String invocationID = defaultToUUID(request.getHeader(ONAPLogConstants.Headers.INVOCATION_ID)); + final String partnerName = defaultToEmpty(request.getHeader(ONAPLogConstants.Headers.PARTNER_NAME)); + + // Set standard MDCs. Override this entire method if you want to set + // others, OR set them BEFORE or AFTER the invocation of #entering, + // depending on where you need them to appear, OR extend the + // ServiceDescriptor to add them. + + MDC.put(ONAPLogConstants.MDCs.INVOKE_TIMESTAMP, + ZonedDateTime.now(ZoneOffset.UTC) + .format(DateTimeFormatter.ISO_INSTANT)); + MDC.put(ONAPLogConstants.MDCs.REQUEST_ID, requestID); + MDC.put(ONAPLogConstants.MDCs.INVOCATION_ID, invocationID); + MDC.put(ONAPLogConstants.MDCs.PARTNER_NAME, partnerName); + MDC.put(ONAPLogConstants.MDCs.CLIENT_IP_ADDRESS, defaultToEmpty(request.getClientAddress())); + MDC.put(ONAPLogConstants.MDCs.SERVER_FQDN, defaultToEmpty(request.getServerAddress())); + + // Delegate to the service adapter, for service-related DMCs. + + this.mServiceDescriptor.setMDCs(); + + // Default the service name to the requestURI, in the event that + // no value has been provided. + + if (MDC.get(ONAPLogConstants.MDCs.SERVICE_NAME) == null || + MDC.get(ONAPLogConstants.MDCs.SERVICE_NAME).equalsIgnoreCase(EMPTY_MESSAGE)) { + MDC.put(ONAPLogConstants.MDCs.SERVICE_NAME, request.getRequestURI()); + } + + return this; + } + + /** + * Dependency-free nullcheck. + * + * @param in to be checked. + * @param <T> argument (and return) type. + * @return input arg. + */ + protected static <T> T checkNotNull(final T in) { + if (in == null) { + throw new NullPointerException(); + } + return in; + } + + /** + * Dependency-free string default. + * + * @param in to be filtered. + * @return input string or null. + */ + protected static String defaultToEmpty(final Object in) { + if (in == null) { + return ""; + } + return in.toString(); + } + + /** + * Dependency-free string default. + * + * @param in to be filtered. + * @return input string or null. + */ + protected static String defaultToUUID(final String in) { + if (in == null) { + return UUID.randomUUID().toString(); + } + return in; + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // + // Inner classes. + // + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Extensible descriptor for reporting service details. + * + * <p>In most cases extension isn't required. </p> + */ + public static class ServiceDescriptor { + + /** <tt>ServiceName</tt>. */ + protected String mName; + + /** <tt>InstanceUUID</tt>. */ + protected String mUUID = sInstanceUUID.toString(); + + /** + * Set name. + * @param name <tt>ServiceName</tt>. + * @return this. + */ + public ServiceDescriptor setServiceName(final String name) { + this.mName = name; + return this; + } + + /** + * Set name. + * @param uuid <tt>InstanceUUID</tt>. + * @return this. + */ + public ServiceDescriptor setServiceUUID(final String uuid) { + this.mUUID = uuid; + return this; + } + + /** + * Set MDCs. Once set they remain set until everything is cleared. + */ + protected void setMDCs() { + MDC.put(ONAPLogConstants.MDCs.SERVICE_NAME, defaultToEmpty(this.mName)); + MDC.put(ONAPLogConstants.MDCs.INSTANCE_UUID, defaultToEmpty(this.mUUID)); + } + } + + /** + * Response is different in that response MDCs are normally only + * reported once, for a single log message. (But there's no method + * for clearing them, because this is only expected to be called + * during <tt>#exiting</tt>.) + */ + public static class ResponseDescriptor { + + /** Response errorcode. */ + protected String mCode; + + /** Response description. */ + protected String mDescription; + + /** Response severity. */ + protected Level mSeverity; + + /** Response status, of {<tt>COMPLETED</tt>, <tt>ERROR</tt>}. */ + protected ONAPLogConstants.ResponseStatus mStatus; + + /** + * Setter. + * + * @param code response (error) code. + * @return this. + */ + public ResponseDescriptor setResponseCode(final String code) { + this.mCode = code; + return this; + } + + /** + * Setter. + * + * @param description response description. + * @return this. + */ + public ResponseDescriptor setResponseDescription(final String description) { + this.mDescription = description; + return this; + } + + /** + * Setter. + * + * @param severity response outcome severity. + * @return this. + */ + public ResponseDescriptor setResponseSeverity(final Level severity) { + this.mSeverity = severity; + return this; + } + + /** + * Setter. + * + * @param status response overall status. + * @return this. + */ + public ResponseDescriptor setResponseStatus(final ONAPLogConstants.ResponseStatus status) { + this.mStatus = status; + return this; + } + + /** + * Overrideable method to set MDCs based on property values. + */ + protected void setMDCs() { + MDC.put(ONAPLogConstants.MDCs.RESPONSE_CODE, defaultToEmpty(this.mCode)); + MDC.put(ONAPLogConstants.MDCs.RESPONSE_DESCRIPTION, defaultToEmpty(this.mDescription)); + MDC.put(ONAPLogConstants.MDCs.RESPONSE_SEVERITY, defaultToEmpty(this.mSeverity)); + MDC.put(ONAPLogConstants.MDCs.RESPONSE_STATUS_CODE, defaultToEmpty(this.mStatus)); + } + } + + /** + * Adapter for reading information from an incoming HTTP request. + * + * <p>Incoming is generally easy, because in most cases you'll be able to + * get your hands on the <tt>HttpServletRequest</tt>.</p> + * + * <p>Perhaps should be generalized to refer to constants instead of + * requiring the implementation of specific methods.</p> + * + * @param <T> type, for chaining. + */ + public interface RequestAdapter<T extends RequestAdapter> { + + /** + * Get header by name. + * @param name header name. + * @return header value, or null. + */ + String getHeader(String name); + + /** + * Get client address. + * @return address, if available. + */ + String getClientAddress(); + + /** + * Get server address. + * @return address, if available. + */ + String getServerAddress(); + + /** + * Get default service name, from service URI. + * @return service name default. + */ + String getRequestURI(); + } + + /** + * Default {@link RequestBuilder} impl for {@link HttpServletRequest}, which + * will should available for most incoming REST requests. + */ + public static class HttpServletRequestAdapter implements RequestAdapter<HttpServletRequestAdapter> { + + /** Wrapped HTTP request. */ + private final HttpServletRequest mRequest; + + /** + * Construct adapter for HTTP request. + * @param request to be wrapped; + */ + public HttpServletRequestAdapter(final HttpServletRequest request) { + this.mRequest = checkNotNull(request); + } + + /** + * {@inheritDoc} + */ + @Override + public String getHeader(final String name) { + return this.mRequest.getHeader(name); + } + + /** + * {@inheritDoc} + */ + @Override + public String getClientAddress() { + return this.mRequest.getRemoteAddr(); + } + + /** + * {@inheritDoc} + */ + @Override + public String getServerAddress() { + return this.mRequest.getServerName(); + } + + /** + * {@inheritDoc} + */ + @Override + public String getRequestURI() { + return this.mRequest.getRequestURI(); + } + } + + /** + * Header builder, which (unlike {@link RequestAdapter} will tend to + * vary a lot from caller to caller, since they each get to choose their + * own REST (or HTTP, or whatever) client APIs. + * + * <p>No default implementation, because there's no HTTP client that's + * sufficiently ubiquitous to warrant incurring a mandatory dependency.</p> + * + * @param <T> type, for chaining. + */ + public interface RequestBuilder<T extends RequestBuilder> { + + /** + * Set HTTP header. + * @param name header name. + * @param value header value. + * @return this. + */ + T setHeader(String name, String value); + } +} diff --git a/aai-els-onap-logging/src/main/java/org/onap/logging/ref/slf4j/ONAPLogConstants.java b/aai-els-onap-logging/src/main/java/org/onap/logging/ref/slf4j/ONAPLogConstants.java new file mode 100644 index 00000000..77ca084d --- /dev/null +++ b/aai-els-onap-logging/src/main/java/org/onap/logging/ref/slf4j/ONAPLogConstants.java @@ -0,0 +1,289 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.logging + * ================================================================================ + * Copyright © 2018 Amdocs + * All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.onap.logging.ref.slf4j; + +import org.slf4j.Marker; +import org.slf4j.MarkerFactory; + +/** + * Constants for standard ONAP headers, MDCs, etc. + * + * <p>See <tt>package-info.java</tt>.</p> + */ +public final class ONAPLogConstants { + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // + // Constructors. + // + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Hide and forbid construction. + */ + private ONAPLogConstants() { + throw new UnsupportedOperationException(); + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // + // Inner classes. + // + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Marker constants. + */ + public static final class Markers { + + /** Marker reporting invocation. */ + public static final Marker INVOKE = MarkerFactory.getMarker("INVOKE"); + + /** Marker reporting invocation return. */ + public static final Marker INVOKE_RETURN = MarkerFactory.getMarker("INVOKE_RETURN"); + + /** Marker reporting synchronous invocation. */ + public static final Marker INVOKE_SYNCHRONOUS = build("INVOKE", "SYNCHRONOUS"); + + /** Marker reporting asynchronous invocation. */ + public static final Marker INVOKE_ASYNCHRONOUS = build("INVOKE", "ASYNCHRONOUS"); + + /** Marker reporting entry into a component. */ + public static final Marker ENTRY = MarkerFactory.getMarker("ENTRY"); + + /** Marker reporting exit from a component. */ + public static final Marker EXIT = MarkerFactory.getMarker("EXIT"); + + /** + * Build nested, detached marker. + * @param m1 top token. + * @param m2 sub-token. + * @return detached Marker. + */ + private static Marker build(final String m1, final String m2) { + final Marker marker = MarkerFactory.getDetachedMarker(m1); + marker.add(MarkerFactory.getDetachedMarker(m2)); + return marker; + } + + /** + * Hide and forbid construction. + */ + private Markers() { + throw new UnsupportedOperationException(); + } + } + + /** + * MDC name constants. + */ + public static final class MDCs { + + // Tracing. //////////////////////////////////////////////////////////// + + /** MDC correlating messages for an invocation. */ + public static final String INVOCATION_ID = "InvocationID"; + + /** MDC correlating messages for a logical transaction. */ + public static final String REQUEST_ID = "RequestID"; + + /** MDC recording calling partner name. */ + public static final String PARTNER_NAME = "PartnerName"; + + /** MDC recording current service. */ + public static final String SERVICE_NAME = "ServiceName"; + + /** MDC recording target service. */ + public static final String TARGET_SERVICE_NAME = "TargetServiceName"; + + /** MDC recording target entity. */ + public static final String TARGET_ENTITY = "TargetEntity"; + + /** MDC recording target element. */ + public static final String TARGET_ELEMENT = "TargetElement"; + + /** MDC recording current service instance id. */ + public static final String SERVICE_INSTANCE_ID = "ServiceInstanceID"; + + /** MDC recording current instance id. */ + public static final String INSTANCE_UUID = "InstanceID"; + + // Network. //////////////////////////////////////////////////////////// + + /** MDC recording caller address. */ + public static final String CLIENT_IP_ADDRESS = "ClientIPAddress"; + + /** MDC recording server IP address. */ + public static final String SERVER_IP_ADDRESS = "ServerIPAddress"; + + /** MDC recording server FQDN. */ + public static final String SERVER_FQDN = "ServerFQDN"; + + /** MDC recording virtual server name. */ + public static final String VIRTUAL_SERVER_NAME = "VirtualServerName"; + + /** MDC recording context name. */ + public static final String CONTEXT_NAME = "ContextName"; + + /** + * MDC recording timestamp at the start of the current request, + * with the same scope as {@link #REQUEST_ID}. + * + * <p>Open issues: + * <ul> + * <ul>Easily confused with {@link #INVOKE_TIMESTAMP}.</ul> + * <ul>No mechanism for propagation between components, e.g. via HTTP headers.</ul> + * <ul>Whatever mechanism we define, it's going to be costly.</ul> + * </ul> + * </p> + * */ + public static final String ENTRY_TIMESTAMP = "EntryTimestamp"; + + /** MDC recording timestamp at the start of the current invocation. */ + public static final String INVOKE_TIMESTAMP = "InvokeTimestamp"; + + /** MDC recording elapsed time. */ + public static final String ELAPSED_TIME = "ElapsedTime"; + + /** MDC recording log timestamp. */ + public static final String LOG_TIMESTAMP = "LogTimestamp"; + + // Outcomes. /////////////////////////////////////////////////////////// + + /** MDC reporting outcome code. */ + public static final String RESPONSE_CODE = "ResponseCode"; + + /** MDC reporting outcome description. */ + public static final String RESPONSE_DESCRIPTION = "ResponseDesc"; + + /** MDC reporting severity */ + public static final String RESPONSE_SEVERITY = "Severity"; + + /** MDC reporting response status code */ + public static final String RESPONSE_STATUS_CODE = "StatusCode"; + + /** MDC recording error code. */ + public static final String ERROR_CODE = "ErrorCode"; + + /** MDC recording error description. */ + public static final String ERROR_DESC = "ErrorDesc"; + + // Unsorted. /////////////////////////////////////////////////////////// + + /** + * Hide and forbid construction. + */ + private MDCs() { + throw new UnsupportedOperationException(); + } + } + + /** + * Header name constants. + */ + public static final class Headers { + + /** HTTP <tt>X-ONAP-RequestID</tt> header. */ + public static final String REQUEST_ID = "X-ONAP-RequestID"; + + /** HTTP <tt>X-ONAP-InvocationID</tt> header. */ + public static final String INVOCATION_ID = "X-ONAP-InvocationID"; + + /** HTTP <tt>X-ONAP-PartnerName</tt> header. */ + public static final String PARTNER_NAME = "X-ONAP-PartnerName"; + + /** + * Hide and forbid construction. + */ + private Headers() { + throw new UnsupportedOperationException(); + } + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // + // Enums. + // + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Response success or not, for setting <tt>StatusCode</tt>. + */ + public enum ResponseStatus { + + /** Success. */ + COMPLETE, + + /** Not. */ + ERROR, + + /** In Progress. */ + INPROGRESS + } + + /** + * Synchronous or asynchronous execution, for setting invocation marker. + */ + public enum InvocationMode { + + /** Synchronous, blocking. */ + SYNCHRONOUS("SYNCHRONOUS", Markers.INVOKE_SYNCHRONOUS), + + /** Asynchronous, non-blocking. */ + ASYNCHRONOUS("ASYNCHRONOUS", Markers.INVOKE_ASYNCHRONOUS); + + /** Enum value. */ + private String mString; + + /** Corresponding marker. */ + private Marker mMarker; + + /** + * Construct enum. + * + * @param s enum value. + * @param m corresponding Marker. + */ + InvocationMode(final String s, final Marker m) { + this.mString = s; + this.mMarker = m; + } + + /** + * Get Marker for enum. + * + * @return Marker. + */ + public Marker getMarker() { + return this.mMarker; + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return this.mString; + } + } + +} diff --git a/aai-els-onap-logging/src/main/java/org/onap/logging/ref/slf4j/package-info.java b/aai-els-onap-logging/src/main/java/org/onap/logging/ref/slf4j/package-info.java new file mode 100644 index 00000000..d9a62472 --- /dev/null +++ b/aai-els-onap-logging/src/main/java/org/onap/logging/ref/slf4j/package-info.java @@ -0,0 +1,32 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.logging + * ================================================================================ + * Copyright © 2018 Amdocs + * All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.onap.logging.ref.slf4j; + +/** + * <p>Code in here has potential application outside this reference + * example, and accordingly: + * <ul> + * <li>Packaged in <tt>common</tt>.</li> + * <li>Has minimal dependencies.</li> + * </ul> + * </p> + */
\ No newline at end of file |