diff options
author | Dan Timoney <dtimoney@att.com> | 2024-09-03 15:51:28 -0400 |
---|---|---|
committer | Dan Timoney <dtimoney@att.com> | 2024-09-03 16:21:30 -0400 |
commit | 32114f72f94d00e0fc01b9fe686e091b56a1ff08 (patch) | |
tree | 753c77cdc77f518d064659dadbe728dc17948e90 /services/src/main/java/org | |
parent | 48cfbaa6b0e5041bc5d63642c817c7fc4795d64f (diff) |
Jakarta support for spring logging filters
Ported spring logging filters from unmaintained logging-analytics
project to ccsdk and updated to support jakarta.
Issue-ID: CCSDK-4053
Change-Id: I8343c744d88588897804dff9f6e58868bf837681
Signed-off-by: Dan Timoney <dtimoney@att.com>
Diffstat (limited to 'services/src/main/java/org')
8 files changed, 504 insertions, 0 deletions
diff --git a/services/src/main/java/org/onap/ccsdk/apps/filters/AbstractServletFilter.java b/services/src/main/java/org/onap/ccsdk/apps/filters/AbstractServletFilter.java new file mode 100644 index 00000000..992345cc --- /dev/null +++ b/services/src/main/java/org/onap/ccsdk/apps/filters/AbstractServletFilter.java @@ -0,0 +1,58 @@ +/*- + * ============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.ccsdk.apps.filters; + +import java.util.Enumeration; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.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/services/src/main/java/org/onap/ccsdk/apps/filters/Constants.java b/services/src/main/java/org/onap/ccsdk/apps/filters/Constants.java new file mode 100644 index 00000000..efbfe90e --- /dev/null +++ b/services/src/main/java/org/onap/ccsdk/apps/filters/Constants.java @@ -0,0 +1,45 @@ +/*- + * ============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.ccsdk.apps.filters; + +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 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/services/src/main/java/org/onap/ccsdk/apps/filters/spring/LoggingInterceptor.java b/services/src/main/java/org/onap/ccsdk/apps/filters/spring/LoggingInterceptor.java new file mode 100644 index 00000000..3f89ee14 --- /dev/null +++ b/services/src/main/java/org/onap/ccsdk/apps/filters/spring/LoggingInterceptor.java @@ -0,0 +1,68 @@ +/*- + * ============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.ccsdk.apps.filters.spring; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import javax.ws.rs.core.Context; +import javax.ws.rs.ext.Providers; +import org.onap.ccsdk.apps.filters.AbstractAuditLogFilter; +import org.onap.ccsdk.apps.filters.SimpleServletHeadersMap; +import org.onap.logging.filter.base.SimpleMap; +import org.onap.logging.ref.slf4j.ONAPLogConstants; +import org.slf4j.MDC; +import org.springframework.stereotype.Component; +import org.springframework.web.servlet.HandlerInterceptor; +import org.springframework.web.servlet.ModelAndView; + +@Component +public class LoggingInterceptor extends AbstractAuditLogFilter<HttpServletRequest, HttpServletResponse> + implements HandlerInterceptor { + + @Context + private Providers providers; + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) + throws Exception { + SimpleMap headers = new SimpleServletHeadersMap(request); + pre(headers, request, request); + return true; + } + + @Override + public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, + ModelAndView modelAndView) throws Exception { + post(response); + } + + @Override + protected int getResponseCode(HttpServletResponse response) { + return response.getStatus(); + } + + @Override + protected void setServiceName(HttpServletRequest request) { + MDC.put(ONAPLogConstants.MDCs.SERVICE_NAME, request.getRequestURI()); + } + +} diff --git a/services/src/main/java/org/onap/ccsdk/apps/filters/spring/MDCTaskDecorator.java b/services/src/main/java/org/onap/ccsdk/apps/filters/spring/MDCTaskDecorator.java new file mode 100644 index 00000000..6969c3ec --- /dev/null +++ b/services/src/main/java/org/onap/ccsdk/apps/filters/spring/MDCTaskDecorator.java @@ -0,0 +1,43 @@ +/*- + * ============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.ccsdk.apps.filters.spring; + +import java.util.Map; +import org.slf4j.MDC; +import org.springframework.core.task.TaskDecorator; + +public class MDCTaskDecorator implements TaskDecorator { + + @Override + public Runnable decorate(Runnable runnable) { + Map<String, String> contextMap = MDC.getCopyOfContextMap(); + return () -> { + try { + if (contextMap != null) { + MDC.setContextMap(contextMap); + runnable.run(); + } + } finally { + MDC.clear(); + } + }; + } +} diff --git a/services/src/main/java/org/onap/ccsdk/apps/filters/spring/SpringClientFilter.java b/services/src/main/java/org/onap/ccsdk/apps/filters/spring/SpringClientFilter.java new file mode 100644 index 00000000..42002fef --- /dev/null +++ b/services/src/main/java/org/onap/ccsdk/apps/filters/spring/SpringClientFilter.java @@ -0,0 +1,99 @@ +/*- + * ============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.ccsdk.apps.filters.spring; + +import java.io.IOException; +import java.util.List; +import org.onap.logging.filter.base.AbstractMetricLogFilter; +import org.onap.logging.filter.base.Constants; +import org.onap.logging.ref.slf4j.ONAPLogConstants; +import org.slf4j.MDC; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpRequest; +import org.springframework.http.client.ClientHttpRequestExecution; +import org.springframework.http.client.ClientHttpRequestInterceptor; +import org.springframework.http.client.ClientHttpResponse; + +public class SpringClientFilter extends AbstractMetricLogFilter<HttpRequest, ClientHttpResponse, HttpHeaders> + implements ClientHttpRequestInterceptor { + + public SpringClientFilter() { + + } + + @Override + public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) + throws IOException { + pre(request, request.getHeaders()); + ClientHttpResponse response = execution.execute(request, body); + post(request, response); + return response; + } + + @Override + protected void addHeader(HttpHeaders requestHeaders, String headerName, String headerValue) { + requestHeaders.add(headerName, headerValue); + } + + @Override + protected String getTargetServiceName(HttpRequest request) { + return request.getURI().toString(); + } + + @Override + protected int getHttpStatusCode(ClientHttpResponse response) { + try { + return response.getStatusCode().value(); + } catch (IOException e) { + // TODO figure out the right thing to do here + return 500; + } + } + + @Override + protected String getResponseCode(ClientHttpResponse response) { + try { + return response.getStatusCode().toString(); + } catch (IOException e) { + return "500"; + } + } + + @Override + protected String getTargetEntity(HttpRequest clientRequest) { + HttpHeaders headers = clientRequest.getHeaders(); + String headerTargetEntity = null; + List<String> headerTargetEntityList = headers.get(Constants.HttpHeaders.TARGET_ENTITY_HEADER); + if (headerTargetEntityList != null && !headerTargetEntityList.isEmpty()) + headerTargetEntity = headerTargetEntityList.get(0); + String targetEntity = MDC.get(ONAPLogConstants.MDCs.TARGET_ENTITY); + if (targetEntity != null && !targetEntity.isEmpty()) { + return targetEntity; + } else if (headerTargetEntity != null && !headerTargetEntity.isEmpty()) { + targetEntity = headerTargetEntity; + } else { + targetEntity = Constants.DefaultValues.UNKNOWN_TARGET_ENTITY; + logger.warn("Could not Target Entity: {}", clientRequest.getURI()); + } + return targetEntity; + } + +} diff --git a/services/src/main/java/org/onap/ccsdk/apps/filters/spring/SpringClientPayloadFilter.java b/services/src/main/java/org/onap/ccsdk/apps/filters/spring/SpringClientPayloadFilter.java new file mode 100644 index 00000000..db14a7e0 --- /dev/null +++ b/services/src/main/java/org/onap/ccsdk/apps/filters/spring/SpringClientPayloadFilter.java @@ -0,0 +1,69 @@ +/*- + * ============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.ccsdk.apps.filters.spring; + +import java.io.IOException; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpRequest; +import org.springframework.http.client.ClientHttpRequestExecution; +import org.springframework.http.client.ClientHttpRequestInterceptor; +import org.springframework.http.client.ClientHttpResponse; +import org.springframework.util.StreamUtils; + +public class SpringClientPayloadFilter implements ClientHttpRequestInterceptor { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Override + public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) + throws IOException { + logRequest(request, body); + ClientHttpResponse response = execution.execute(request, body); + logResponse(response); + return response; + } + + protected void logRequest(HttpRequest request, byte[] body) throws IOException { + if (logger.isDebugEnabled()) { + logger.debug("===========================request begin================================================"); + logger.debug("URI : {}", request.getURI()); + logger.debug("Method : {}", request.getMethod()); + logger.debug("Headers : {}", request.getHeaders()); + logger.debug("Request body: {}", new String(body, StandardCharsets.UTF_8)); + logger.debug("==========================request end================================================"); + } + } + + protected void logResponse(ClientHttpResponse response) throws IOException { + if (logger.isDebugEnabled()) { + logger.debug("============================response begin=========================================="); + logger.debug("Status code : {}", response.getStatusCode()); + logger.debug("Status text : {}", response.getStatusText()); + logger.debug("Headers : {}", response.getHeaders()); + logger.debug("Response body: {}", StreamUtils.copyToString(response.getBody(), Charset.defaultCharset())); + logger.debug("=======================response end================================================="); + } + } + +} diff --git a/services/src/main/java/org/onap/ccsdk/apps/filters/spring/SpringScheduledTasksMDCSetupAspect.java b/services/src/main/java/org/onap/ccsdk/apps/filters/spring/SpringScheduledTasksMDCSetupAspect.java new file mode 100644 index 00000000..7e8c7494 --- /dev/null +++ b/services/src/main/java/org/onap/ccsdk/apps/filters/spring/SpringScheduledTasksMDCSetupAspect.java @@ -0,0 +1,49 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - Logging + * ================================================================================ + * Copyright (C) 2020 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.ccsdk.apps.filters.spring; + +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.onap.logging.filter.base.AbstractMDCSetupAspect; +import org.onap.logging.filter.base.ScheduledTaskException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +@Aspect +@Component +public class SpringScheduledTasksMDCSetupAspect extends AbstractMDCSetupAspect { + + protected static Logger logger = LoggerFactory.getLogger(SpringScheduledTasksMDCSetupAspect.class); + + @Around("@annotation(org.onap.logging.filter.base.ScheduledLogging)") + public void logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable { + setupMDC(joinPoint.getSignature().getName()); + try { + joinPoint.proceed(); + } catch (ScheduledTaskException e) { + errorMDCSetup(e.getErrorCode(), e.getMessage()); + logger.error("ScheduledTaskException: ", e); + } + exitAndClearMDC(); + } +} diff --git a/services/src/main/java/org/onap/ccsdk/apps/filters/spring/StatusLoggingInterceptor.java b/services/src/main/java/org/onap/ccsdk/apps/filters/spring/StatusLoggingInterceptor.java new file mode 100644 index 00000000..931b2dd8 --- /dev/null +++ b/services/src/main/java/org/onap/ccsdk/apps/filters/spring/StatusLoggingInterceptor.java @@ -0,0 +1,73 @@ +/*- + * ============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.ccsdk.apps.filters.spring; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.Response; +import javax.ws.rs.ext.Providers; +import org.onap.ccsdk.apps.filters.AbstractServletFilter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; +import org.springframework.web.servlet.HandlerInterceptor; +import org.springframework.web.servlet.ModelAndView; + +@Component +public class StatusLoggingInterceptor extends AbstractServletFilter implements HandlerInterceptor { + + private static final Logger logger = LoggerFactory.getLogger(StatusLoggingInterceptor.class); + + @Context + private Providers providers; + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) + throws Exception { + if (logger.isDebugEnabled()) { + logRequestInformation(request); + } + return true; + } + + protected void logRequestInformation(HttpServletRequest request) { + logger.debug("===========================request begin================================================"); + logger.debug("URI : {}", request.getRequestURI()); + logger.debug("Method : {}", request.getMethod()); + logger.debug("Headers : {}", getSecureRequestHeaders(request)); + logger.debug("===========================request end=================================================="); + } + + // TODO previously no response information was being logged, I followed the format in SpringClientPayloadFilter + @Override + public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, + ModelAndView modelAndView) throws Exception { + if (logger.isDebugEnabled()) { + logger.debug("============================response begin=========================================="); + logger.debug("Status code : {}", response.getStatus()); + logger.debug("Status text : {}", Response.Status.fromStatusCode(response.getStatus())); + logger.debug("Headers : {}", formatResponseHeaders(response)); + logger.debug("============================response end============================================"); + } + } +} |