- This enhancment is to signicantly improve the traceability and debugging capabilities for specific request flowing through our system.
- Create new class MdcServletFilter.java and added the dofilter to handle Mapped Diagnostic Context setup for capture and link requestID and clientID.
- Added testcases MdcServletFilterSpec.groovy for above changes.
Issue-ID: CPS-2796
Change-Id: I56c34400dc73c71b936a51260efd060505baabdc
Signed-off-by: GM001016278 <gourav.malviya@techmahindra.com>
--- /dev/null
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2025 TechMahindra Ltd.
+ * ================================================================================
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.cps.logging;
+
+import jakarta.servlet.Filter;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.ServletResponse;
+import jakarta.servlet.http.HttpServletRequest;
+import java.io.IOException;
+import org.slf4j.MDC;
+import org.springframework.stereotype.Component;
+
+@Component
+public class MdcServletFilter implements Filter {
+
+ private static final String REQUEST_ID_HEADER = "X-CPS-Request-Id";
+ private static final String CLIENT_ID_HEADER = "X-CPS-Client-Id";
+
+ @Override
+ public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse,
+ final FilterChain filterChain) throws IOException, ServletException {
+ final HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
+ putToMdc(REQUEST_ID_HEADER, httpServletRequest);
+ putToMdc(CLIENT_ID_HEADER, httpServletRequest);
+ try {
+ filterChain.doFilter(servletRequest, servletResponse);
+ } finally {
+ MDC.remove(REQUEST_ID_HEADER);
+ MDC.remove(CLIENT_ID_HEADER);
+ }
+ }
+
+ private void putToMdc(final String header, final HttpServletRequest httpServletRequest) {
+ final String value = httpServletRequest.getHeader(header);
+ MDC.put(header, value);
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2025 TechMahindra Ltd.
+ * ================================================================================
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.cps.logging
+
+import jakarta.servlet.FilterChain
+import jakarta.servlet.ServletResponse
+import jakarta.servlet.http.HttpServletRequest
+import org.slf4j.MDC
+import spock.lang.Specification
+
+class MdcServletFilterSpec extends Specification {
+ def mockFilterChain = Mock(FilterChain)
+ def mockHttpServletRequest = Mock(HttpServletRequest)
+ def mockServletResponse = Mock(ServletResponse)
+
+ def objectUnderTest = new MdcServletFilter()
+
+ def 'Filter chain and Mapped Diagnostic Context (MDC).'() {
+ given:'the mocked request returns a value for any header'
+ mockHttpServletRequest.getHeader(_) >> { args -> { args[0]+' TEST VALUE'} }
+ when: 'HTTP request is filtered'
+ objectUnderTest.doFilter(mockHttpServletRequest, mockServletResponse, mockFilterChain)
+ then: 'the filter chain is called once MDC only has the expected headers at that moment in time'
+ 1 * mockFilterChain.doFilter(mockHttpServletRequest, mockServletResponse) >> {
+ assert MDC.get('X-CPS-Request-Id') == 'X-CPS-Request-Id TEST VALUE'
+ assert MDC.get('X-CPS-Client-Id') == 'X-CPS-Client-Id TEST VALUE'
+ assert MDC.get('Other Header') == null
+ }
+ and: 'MDC is cleaned up after filter chain execution'
+ assert MDC.get('X-CPS-Request-Id') == null
+ assert MDC.get('X-CPS-Client-Id') == null
+ }
+}
\ No newline at end of file
<!--
============LICENSE_START=======================================================
Copyright (C) 2021-2025 OpenInfra Foundation Europe. All rights reserved.
+ Modifications Copyright (C) 2025 TechMahindra Ltd.
================================================================================
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
"logTypeName": "",
"logLevel": "%level",
"traceId": "%X{traceId:-}",
+ "requestId": "%X{X-CPS-Request-Id:-}",
+ "clientId": "%X{X-CPS-Client-Id:-}",
"statusCode": "",
"principalId": "${username:-}",
"serviceName": "${springAppName:-}",