You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@fineract.apache.org by ar...@apache.org on 2022/07/13 19:30:01 UTC

[fineract] branch develop updated (1db8ef46f -> 4f832f948)

This is an automated email from the ASF dual-hosted git repository.

arnold pushed a change to branch develop
in repository https://gitbox.apache.org/repos/asf/fineract.git


    from 1db8ef46f Date to LocalDate (scheduler excluded due to quartz)
     new 8a55d5807 FINERACT-1656 Correlation ID propagation and configuration
     new 4f832f948 Correlation ID support implementation

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../commands/provider/CommandHandlerProvider.java  |   2 +-
 .../core/config/FineractProperties.java            |  10 ++
 .../core/filters/CorrelationHeaderFilter.java      |  84 +++++++++++++
 ...ikariDataSourceFactory.java => MDCWrapper.java} |  14 ++-
 .../filter/FineractInstanceModeApiFilter.java      |   2 -
 .../security/utils/LogParameterEscapeUtil.java     |   4 +
 .../src/main/resources/application.properties      |   6 +
 .../src/main/resources/logback-spring.xml          |   1 +
 .../core/filters/CorrelationHeaderFilterTest.java  | 131 +++++++++++++++++++++
 9 files changed, 246 insertions(+), 8 deletions(-)
 create mode 100644 fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/filters/CorrelationHeaderFilter.java
 copy fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/{HikariDataSourceFactory.java => MDCWrapper.java} (80%)
 create mode 100644 fineract-provider/src/test/java/org/apache/fineract/infrastructure/core/filters/CorrelationHeaderFilterTest.java


[fineract] 02/02: Correlation ID support implementation

Posted by ar...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

arnold pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/fineract.git

commit 4f832f94810d8b5aae321390f4074e6007c8d7db
Author: Arnold Galovics <ga...@gmail.com>
AuthorDate: Wed Jul 13 17:55:04 2022 +0200

    Correlation ID support implementation
---
 docker-compose-postgresql.yml                      |   3 -
 docker-compose.yml                                 |   4 -
 .../commands/provider/CommandHandlerProvider.java  |   2 +-
 .../core/config/CorrelationIdConfig.java           |  50 --------
 .../core/filters/CorrelationHeaderFilter.java      |  45 ++++---
 .../service/{MdcAdapter.java => MDCWrapper.java}   |  28 +----
 .../filter/FineractInstanceModeApiFilter.java      |   2 -
 .../src/main/resources/application.properties      |   6 +-
 .../core/filters/CorrelationHeaderFilterTest.java  | 131 +++++++++++++++++++++
 .../FineractCorrelationIdApiFilterTest.java        |  80 -------------
 .../src/test/resources/application-test.properties |   3 -
 fineract-war/setenv.sh                             |   2 -
 12 files changed, 164 insertions(+), 192 deletions(-)

diff --git a/docker-compose-postgresql.yml b/docker-compose-postgresql.yml
index 217d77f17..f5da1f263 100644
--- a/docker-compose-postgresql.yml
+++ b/docker-compose-postgresql.yml
@@ -94,7 +94,4 @@ services:
       - FINERACT_DEFAULT_TENANTDB_IDENTIFIER=default
       - FINERACT_DEFAULT_TENANTDB_NAME=fineract_default
       - FINERACT_DEFAULT_TENANTDB_DESCRIPTION=Default Demo Tenant
-      - FINERACT_LOGGING_HTTP_CORRELATION_ID_ENABLED=false
-      - FINERACT_LOGGING_HTTP_CORRELATION_ID_HEADER_NAME=X-Correlation-ID
-      - CONSOLE_LOG_PATTERN=%d{yyyy-MM-dd HH:mm:ss.SSS} %thread %replace([%X{correlationId}]){'\[\]', ''} [%-5level] %class{0} - %msg%n
       - JAVA_TOOL_OPTIONS="-Xmx1G"
diff --git a/docker-compose.yml b/docker-compose.yml
index 398e0b0d2..08e0cc6b5 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -90,8 +90,4 @@ services:
       - FINERACT_DEFAULT_TENANTDB_IDENTIFIER=default
       - FINERACT_DEFAULT_TENANTDB_NAME=fineract_default
       - FINERACT_DEFAULT_TENANTDB_DESCRIPTION=Default Demo Tenant
-      - FINERACT_LOGGING_HTTP_CORRELATION_ID_ENABLED=false
-      - FINERACT_LOGGING_HTTP_CORRELATION_ID_HEADER_NAME=X-Correlation-ID
-      - CONSOLE_LOG_PATTERN=%d{yyyy-MM-dd HH:mm:ss.SSS} %thread %replace([%X{correlationId}]){'\[\]', ''} [%-5level] %class{0} - %msg%n
-      - FINERACT_LOGGING_LEVEL=warn
       - JAVA_TOOL_OPTIONS="-Xmx1G"
diff --git a/fineract-provider/src/main/java/org/apache/fineract/commands/provider/CommandHandlerProvider.java b/fineract-provider/src/main/java/org/apache/fineract/commands/provider/CommandHandlerProvider.java
index 31a54fde0..cdefacc81 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/commands/provider/CommandHandlerProvider.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/commands/provider/CommandHandlerProvider.java
@@ -81,7 +81,7 @@ public class CommandHandlerProvider implements ApplicationContextAware {
             final String[] commandHandlerBeans = this.applicationContext.getBeanNamesForAnnotation(CommandType.class);
             if (ArrayUtils.isNotEmpty(commandHandlerBeans)) {
                 for (final String commandHandlerName : commandHandlerBeans) {
-                    log.info("Register command handler '{}' ...", commandHandlerName);
+                    log.debug("Register command handler '{}' ...", commandHandlerName);
                     final CommandType commandType = this.applicationContext.findAnnotationOnBean(commandHandlerName, CommandType.class);
                     try {
                         this.registeredHandlers.put(commandType.entity() + "|" + commandType.action(), commandHandlerName);
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/CorrelationIdConfig.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/CorrelationIdConfig.java
deleted file mode 100644
index d1ef8f354..000000000
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/CorrelationIdConfig.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.fineract.infrastructure.core.config;
-
-import java.util.Arrays;
-import org.apache.fineract.infrastructure.core.filters.CorrelationHeaderFilter;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.boot.web.servlet.FilterRegistrationBean;
-import org.springframework.context.EnvironmentAware;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.core.env.Environment;
-
-@Configuration
-@ConditionalOnProperty("fineract.logging.http.correlation-id.enabled")
-public class CorrelationIdConfig implements EnvironmentAware {
-
-    private Environment environment;
-
-    @Override
-    public void setEnvironment(Environment environment) {
-        this.environment = environment;
-    }
-
-    @Bean
-    public FilterRegistrationBean<CorrelationHeaderFilter> correlationHeaderFilter() {
-        FilterRegistrationBean<CorrelationHeaderFilter> filterRegBean = new FilterRegistrationBean<CorrelationHeaderFilter>();
-        filterRegBean.setFilter(new CorrelationHeaderFilter(environment));
-        filterRegBean.setUrlPatterns(Arrays.asList("/*"));
-        return filterRegBean;
-    }
-
-}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/filters/CorrelationHeaderFilter.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/filters/CorrelationHeaderFilter.java
index 495f872a1..9842ce1f6 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/filters/CorrelationHeaderFilter.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/filters/CorrelationHeaderFilter.java
@@ -26,44 +26,51 @@ import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.fineract.infrastructure.core.config.FineractProperties;
+import org.apache.fineract.infrastructure.core.service.MDCWrapper;
 import org.apache.fineract.infrastructure.security.utils.LogParameterEscapeUtil;
-import org.slf4j.MDC;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.core.env.Environment;
+import org.springframework.stereotype.Component;
 import org.springframework.web.filter.OncePerRequestFilter;
 
 @RequiredArgsConstructor
 @Slf4j
+@Component
 public class CorrelationHeaderFilter extends OncePerRequestFilter {
 
-    private String correlationIdHeader;
+    public static final String CORRELATION_ID_KEY = "correlationId";
 
-    public static final String correlationIdKey = "correlationId";
-
-    @Autowired
-    public CorrelationHeaderFilter(Environment env) {
-        correlationIdHeader = env.getRequiredProperty("fineract.logging.http.correlation-id.header-name");
-    }
+    private final FineractProperties fineractProperties;
+    private final MDCWrapper mdcWrapper;
 
     @Override
     protected void doFilterInternal(final HttpServletRequest request, final HttpServletResponse response, final FilterChain filterChain)
             throws IOException, ServletException {
+        FineractProperties.FineractCorrelationProperties correlationProperties = fineractProperties.getCorrelation();
+        if (correlationProperties.isEnabled()) {
+            handleCorrelations(request, response, filterChain, correlationProperties);
+        } else {
+            filterChain.doFilter(request, response);
+        }
 
+    }
+
+    private void handleCorrelations(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain,
+            FineractProperties.FineractCorrelationProperties correlationProperties) throws IOException, ServletException {
         try {
-            final HttpServletRequest httpServletRequest = (HttpServletRequest) request;
-            String currentCorrId = httpServletRequest.getHeader(correlationIdHeader);
-            log.debug("Found correlationId in Header : {}", LogParameterEscapeUtil.escapeLogMDCParameter(currentCorrId));
-            MDC.put(correlationIdKey, currentCorrId);
+            String correlationHeaderName = correlationProperties.getHeaderName();
+            String correlationId = request.getHeader(correlationHeaderName);
+            if (StringUtils.isNotBlank(correlationId)) {
+                String escapedCorrelationId = LogParameterEscapeUtil.escapeLogMDCParameter(correlationId);
+                log.debug("Found correlationId in header : {}", escapedCorrelationId);
+                mdcWrapper.put(CORRELATION_ID_KEY, escapedCorrelationId);
+            }
             filterChain.doFilter(request, response);
         } finally {
-            MDC.remove(correlationIdKey);
+            mdcWrapper.remove(CORRELATION_ID_KEY);
         }
     }
 
-    public static String getCurrentValue() {
-        return MDC.get(correlationIdKey);
-    }
-
     @Override
     protected boolean isAsyncDispatch(final HttpServletRequest request) {
         return false;
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/MdcAdapter.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/MDCWrapper.java
similarity index 66%
rename from fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/MdcAdapter.java
rename to fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/MDCWrapper.java
index 241aefdac..71ebe872e 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/MdcAdapter.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/MDCWrapper.java
@@ -19,39 +19,17 @@
 
 package org.apache.fineract.infrastructure.core.service;
 
-import java.util.Map;
 import org.slf4j.MDC;
-import org.slf4j.spi.MDCAdapter;
+import org.springframework.stereotype.Component;
 
-public class MdcAdapter implements MDCAdapter {
+@Component
+public class MDCWrapper {
 
-    @Override
     public void put(String key, String val) {
         MDC.put(key, val);
     }
 
-    @Override
-    public String get(String key) {
-        return MDC.get(key);
-    }
-
-    @Override
     public void remove(String key) {
         MDC.remove(key);
     }
-
-    @Override
-    public void clear() {
-        MDC.clear();
-    }
-
-    @Override
-    public Map<String, String> getCopyOfContextMap() {
-        return MDC.getCopyOfContextMap();
-    }
-
-    @Override
-    public void setContextMap(Map<String, String> map) {
-        MDC.setContextMap(map);
-    }
 }
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/instancemode/filter/FineractInstanceModeApiFilter.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/instancemode/filter/FineractInstanceModeApiFilter.java
index 9e6dfb992..4266de6b5 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/instancemode/filter/FineractInstanceModeApiFilter.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/instancemode/filter/FineractInstanceModeApiFilter.java
@@ -29,7 +29,6 @@ import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import javax.ws.rs.HttpMethod;
-import javax.ws.rs.ext.Provider;
 import lombok.Getter;
 import lombok.RequiredArgsConstructor;
 import org.apache.fineract.infrastructure.core.config.FineractProperties;
@@ -38,7 +37,6 @@ import org.apache.http.HttpStatus;
 import org.springframework.stereotype.Component;
 import org.springframework.web.filter.OncePerRequestFilter;
 
-@Provider
 @Component
 @RequiredArgsConstructor
 public class FineractInstanceModeApiFilter extends OncePerRequestFilter {
diff --git a/fineract-provider/src/main/resources/application.properties b/fineract-provider/src/main/resources/application.properties
index 3bf753e0a..fa64cf072 100644
--- a/fineract-provider/src/main/resources/application.properties
+++ b/fineract-provider/src/main/resources/application.properties
@@ -40,11 +40,11 @@ fineract.mode.write-enabled=${FINERACT_MODE_WRITE_ENABLED:true}
 fineract.mode.batch-worker-enabled=${FINERACT_MODE_BATCH_WORKER_ENABLED:true}
 fineract.mode.batch-manager-enabled=${FINERACT_MODE_BATCH_MANAGER_ENABLED:true}
 
-fineract.logging.http.correlation-id.enabled=${FINERACT_LOGGING_HTTP_CORRELATION_ID_ENABLED:false}
-fineract.logging.http.correlation-id.header-name=${FINERACT_LOGGING_HTTP_CORRELATION_ID_HEADER_NAME:X-Correlation-ID}
+fineract.correlation.enabled=${FINERACT_LOGGING_HTTP_CORRELATION_ID_ENABLED:false}
+fineract.correlation.header-name=${FINERACT_LOGGING_HTTP_CORRELATION_ID_HEADER_NAME:X-Correlation-ID}
 
 # Logging pattern for the console
-logging.pattern.console=${CONSOLE_LOG_PATTERN:%d{yyyy-MM-dd HH\:mm\:ss.SSS} %thread %replace([%X{correlationId}]){'\\[\\]', ''} [%-5level] %class{0} - %msg%n}
+logging.pattern.console=${CONSOLE_LOG_PATTERN:%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(%replace([%X{correlationId}]){'\\[\\]', ''}) %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:%wEx}}
 
 management.health.jms.enabled=false
 
diff --git a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/core/filters/CorrelationHeaderFilterTest.java b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/core/filters/CorrelationHeaderFilterTest.java
new file mode 100644
index 000000000..a32e29a42
--- /dev/null
+++ b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/core/filters/CorrelationHeaderFilterTest.java
@@ -0,0 +1,131 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.fineract.infrastructure.core.filters;
+
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.BDDMockito.given;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoInteractions;
+
+import java.util.UUID;
+import javax.servlet.FilterChain;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.apache.fineract.infrastructure.core.config.FineractProperties;
+import org.apache.fineract.infrastructure.core.service.MDCWrapper;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.mockito.junit.jupiter.MockitoSettings;
+import org.mockito.quality.Strictness;
+
+@ExtendWith(MockitoExtension.class)
+@MockitoSettings(strictness = Strictness.LENIENT)
+class CorrelationHeaderFilterTest {
+
+    private static final String CORRELATION_ID_HEADER_NAME = "X-CORR-ID";
+
+    @Mock
+    private HttpServletRequest request;
+
+    @Mock
+    private HttpServletResponse response;
+
+    @Mock
+    private FilterChain filterChain;
+
+    @Mock
+    private MDCWrapper mdcWrapper;
+
+    private FineractProperties fineractProperties;
+
+    private CorrelationHeaderFilter underTest;
+
+    @BeforeEach
+    void setUp() {
+        fineractProperties = new FineractProperties();
+        FineractProperties.FineractCorrelationProperties correlationProps = new FineractProperties.FineractCorrelationProperties();
+        correlationProps.setHeaderName(CORRELATION_ID_HEADER_NAME);
+        correlationProps.setEnabled(true);
+        fineractProperties.setCorrelation(correlationProps);
+        underTest = new CorrelationHeaderFilter(fineractProperties, mdcWrapper);
+    }
+
+    @Test
+    public void testDoFilterInternalShouldPutCorrelationIdIntoMDCIfHeaderIsPresentAndEnabled() throws Exception {
+        // given
+        String correlationId = UUID.randomUUID().toString();
+        given(request.getHeader(fineractProperties.getCorrelation().getHeaderName())).willReturn(correlationId);
+
+        // when
+        underTest.doFilterInternal(request, response, filterChain);
+
+        // then
+        verify(mdcWrapper).put(CorrelationHeaderFilter.CORRELATION_ID_KEY, correlationId);
+        verify(mdcWrapper).remove(CorrelationHeaderFilter.CORRELATION_ID_KEY);
+        verify(filterChain).doFilter(request, response);
+    }
+
+    @Test
+    public void testDoFilterInternalShouldNotPutCorrelationIdIntoMDCIfHeaderIsNotPresentAndEnabled() throws Exception {
+        // given
+        given(request.getHeader(fineractProperties.getCorrelation().getHeaderName())).willReturn(null);
+
+        // when
+        underTest.doFilterInternal(request, response, filterChain);
+
+        // then
+        verify(mdcWrapper, never()).put(anyString(), anyString());
+        verify(mdcWrapper).remove(CorrelationHeaderFilter.CORRELATION_ID_KEY);
+        verify(filterChain).doFilter(request, response);
+    }
+
+    @Test
+    public void testDoFilterInternalShouldNotPutCorrelationIdIntoMDCIfHeaderIsPresentButWhitespacesAndEnabled() throws Exception {
+        // given
+        given(request.getHeader(fineractProperties.getCorrelation().getHeaderName())).willReturn("    ");
+
+        // when
+        underTest.doFilterInternal(request, response, filterChain);
+
+        // then
+        verify(mdcWrapper, never()).put(anyString(), anyString());
+        verify(mdcWrapper).remove(CorrelationHeaderFilter.CORRELATION_ID_KEY);
+        verify(filterChain).doFilter(request, response);
+    }
+
+    @Test
+    public void testDoFilterInternalShouldNotPutCorrelationIdIntoMDCIfHeaderIsPresentAndDisabled() throws Exception {
+        // given
+        fineractProperties.getCorrelation().setEnabled(false);
+        String correlationId = UUID.randomUUID().toString();
+        given(request.getHeader(fineractProperties.getCorrelation().getHeaderName())).willReturn(correlationId);
+
+        // when
+        underTest.doFilterInternal(request, response, filterChain);
+
+        // then
+        verifyNoInteractions(mdcWrapper);
+        verify(filterChain).doFilter(request, response);
+    }
+}
diff --git a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/core/filters/FineractCorrelationIdApiFilterTest.java b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/core/filters/FineractCorrelationIdApiFilterTest.java
deleted file mode 100644
index b042b5928..000000000
--- a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/core/filters/FineractCorrelationIdApiFilterTest.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.fineract.infrastructure.core.filters;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.verify;
-import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
-import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
-import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
-
-import java.util.UUID;
-import org.apache.fineract.infrastructure.core.service.MdcAdapter;
-import org.junit.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
-import org.junit.jupiter.params.ParameterizedTest;
-import org.junit.jupiter.params.provider.ValueSource;
-import org.mockito.junit.jupiter.MockitoExtension;
-import org.mockito.junit.jupiter.MockitoSettings;
-import org.mockito.quality.Strictness;
-import org.slf4j.MDC;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
-import org.springframework.boot.test.mock.mockito.SpyBean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.test.context.ContextConfiguration;
-import org.springframework.test.web.servlet.MockMvc;
-
-@ExtendWith(MockitoExtension.class)
-@MockitoSettings(strictness = Strictness.LENIENT)
-@ContextConfiguration(classes = { Configuration.class })
-@WebMvcTest
-class FineractCorrelationIdApiFilterTest {
-
-    @SpyBean
-    private MdcAdapter mdc;
-
-    @Autowired
-    private MockMvc mockMvc;
-
-    @ParameterizedTest
-    @ValueSource(strings = { "/fineract-provider/api/v1/loans", "/fineract-provider/api/v1/loans" })
-    void shouldGet200IfXCorrelationIdHeaderIsPresentAndRequestIsForV1Path(String url) throws Exception {
-        String correlationId = UUID.randomUUID().toString();
-        mockMvc.perform(get(url).header(CorrelationHeaderFilter.correlationIdKey, correlationId)).andExpect(status().isOk())
-                .andExpect(header().string(CorrelationHeaderFilter.correlationIdKey, correlationId));
-
-        verify(mdc).remove(CorrelationHeaderFilter.correlationIdKey);
-    }
-
-    @ParameterizedTest
-    @ValueSource(strings = { "/fineract-provider/api/v1/loans", "/fineract-provider/api/v1/loans" })
-    void shouldGet400IfXCorrelationIdHeaderIsNotPresentAndRequestIsForV1Path(String url) throws Exception {
-        mockMvc.perform(get(url)).andExpect(status().isBadRequest())
-                .andExpect(header().doesNotExist(CorrelationHeaderFilter.correlationIdKey));
-    }
-
-    @Test
-    void shouldReturnCurrentCorrelationIdFromMDC() {
-        MDC.put(CorrelationHeaderFilter.correlationIdKey, "1");
-        assertThat(CorrelationHeaderFilter.getCurrentValue()).isEqualTo("1");
-    }
-
-}
diff --git a/fineract-provider/src/test/resources/application-test.properties b/fineract-provider/src/test/resources/application-test.properties
index 54deaac7d..58981db96 100644
--- a/fineract-provider/src/test/resources/application-test.properties
+++ b/fineract-provider/src/test/resources/application-test.properties
@@ -37,9 +37,6 @@ fineract.mode.read-enabled=true
 fineract.mode.write-enabled=true
 fineract.mode.batch-enabled=true
 
-fineract.logging.http.correlation-id.enabled=false
-fineract.logging.http.correlation-id.header-name=X-Correlation-ID
-
 management.health.jms.enabled=false
 
 # FINERACT 1296
diff --git a/fineract-war/setenv.sh b/fineract-war/setenv.sh
index 531936710..5d69b5aba 100644
--- a/fineract-war/setenv.sh
+++ b/fineract-war/setenv.sh
@@ -53,5 +53,3 @@ export FINERACT_DEFAULT_TENANTDB_TIMEZONE="Asia/Kolkata"
 export FINERACT_DEFAULT_TENANTDB_IDENTIFIER="default"
 export FINERACT_DEFAULT_TENANTDB_NAME="fineract_default"
 export FINERACT_DEFAULT_TENANTDB_DESCRIPTION="Default Demo Tenant"
-export FINERACT_LOGGING_HTTP_CORRELATION_ID_ENABLED="false"
-export FINERACT_LOGGING_HTTP_CORRELATION_ID_HEADER_NAME="X-Correlation-ID"


[fineract] 01/02: FINERACT-1656 Correlation ID propagation and configuration

Posted by ar...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

arnold pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/fineract.git

commit 8a55d5807ac0c1e73a28e020836bee9872fb9406
Author: Vic Romero <vi...@fintecheando.mx>
AuthorDate: Wed Jun 29 03:53:36 2022 -0500

    FINERACT-1656 Correlation ID propagation and configuration
---
 docker-compose-postgresql.yml                      |  3 +
 docker-compose.yml                                 |  4 ++
 .../core/config/CorrelationIdConfig.java           | 50 ++++++++++++++
 .../core/config/FineractProperties.java            | 10 +++
 .../core/filters/CorrelationHeaderFilter.java      | 77 +++++++++++++++++++++
 .../service/MdcAdapter.java}                       | 39 +++++++++--
 .../security/utils/LogParameterEscapeUtil.java     |  4 ++
 .../src/main/resources/application.properties      |  6 ++
 .../src/main/resources/logback-spring.xml          |  1 +
 .../FineractCorrelationIdApiFilterTest.java        | 80 ++++++++++++++++++++++
 .../src/test/resources/application-test.properties |  3 +
 fineract-war/setenv.sh                             |  2 +
 12 files changed, 274 insertions(+), 5 deletions(-)

diff --git a/docker-compose-postgresql.yml b/docker-compose-postgresql.yml
index f5da1f263..217d77f17 100644
--- a/docker-compose-postgresql.yml
+++ b/docker-compose-postgresql.yml
@@ -94,4 +94,7 @@ services:
       - FINERACT_DEFAULT_TENANTDB_IDENTIFIER=default
       - FINERACT_DEFAULT_TENANTDB_NAME=fineract_default
       - FINERACT_DEFAULT_TENANTDB_DESCRIPTION=Default Demo Tenant
+      - FINERACT_LOGGING_HTTP_CORRELATION_ID_ENABLED=false
+      - FINERACT_LOGGING_HTTP_CORRELATION_ID_HEADER_NAME=X-Correlation-ID
+      - CONSOLE_LOG_PATTERN=%d{yyyy-MM-dd HH:mm:ss.SSS} %thread %replace([%X{correlationId}]){'\[\]', ''} [%-5level] %class{0} - %msg%n
       - JAVA_TOOL_OPTIONS="-Xmx1G"
diff --git a/docker-compose.yml b/docker-compose.yml
index 08e0cc6b5..398e0b0d2 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -90,4 +90,8 @@ services:
       - FINERACT_DEFAULT_TENANTDB_IDENTIFIER=default
       - FINERACT_DEFAULT_TENANTDB_NAME=fineract_default
       - FINERACT_DEFAULT_TENANTDB_DESCRIPTION=Default Demo Tenant
+      - FINERACT_LOGGING_HTTP_CORRELATION_ID_ENABLED=false
+      - FINERACT_LOGGING_HTTP_CORRELATION_ID_HEADER_NAME=X-Correlation-ID
+      - CONSOLE_LOG_PATTERN=%d{yyyy-MM-dd HH:mm:ss.SSS} %thread %replace([%X{correlationId}]){'\[\]', ''} [%-5level] %class{0} - %msg%n
+      - FINERACT_LOGGING_LEVEL=warn
       - JAVA_TOOL_OPTIONS="-Xmx1G"
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/CorrelationIdConfig.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/CorrelationIdConfig.java
new file mode 100644
index 000000000..d1ef8f354
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/CorrelationIdConfig.java
@@ -0,0 +1,50 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.fineract.infrastructure.core.config;
+
+import java.util.Arrays;
+import org.apache.fineract.infrastructure.core.filters.CorrelationHeaderFilter;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
+import org.springframework.context.EnvironmentAware;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.env.Environment;
+
+@Configuration
+@ConditionalOnProperty("fineract.logging.http.correlation-id.enabled")
+public class CorrelationIdConfig implements EnvironmentAware {
+
+    private Environment environment;
+
+    @Override
+    public void setEnvironment(Environment environment) {
+        this.environment = environment;
+    }
+
+    @Bean
+    public FilterRegistrationBean<CorrelationHeaderFilter> correlationHeaderFilter() {
+        FilterRegistrationBean<CorrelationHeaderFilter> filterRegBean = new FilterRegistrationBean<CorrelationHeaderFilter>();
+        filterRegBean.setFilter(new CorrelationHeaderFilter(environment));
+        filterRegBean.setUrlPatterns(Arrays.asList("/*"));
+        return filterRegBean;
+    }
+
+}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/FineractProperties.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/FineractProperties.java
index 10c447990..fb888cb89 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/FineractProperties.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/FineractProperties.java
@@ -34,6 +34,8 @@ public class FineractProperties {
 
     private FineractModeProperties mode;
 
+    private FineractCorrelationProperties correlation;
+
     @Getter
     @Setter
     public static class FineractTenantProperties {
@@ -62,4 +64,12 @@ public class FineractProperties {
             return readEnabled && !writeEnabled && !batchWorkerEnabled && !batchManagerEnabled;
         }
     }
+
+    @Getter
+    @Setter
+    public static class FineractCorrelationProperties {
+
+        private boolean enabled;
+        private String headerName;
+    }
 }
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/filters/CorrelationHeaderFilter.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/filters/CorrelationHeaderFilter.java
new file mode 100644
index 000000000..495f872a1
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/filters/CorrelationHeaderFilter.java
@@ -0,0 +1,77 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.fineract.infrastructure.core.filters;
+
+import java.io.IOException;
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.fineract.infrastructure.security.utils.LogParameterEscapeUtil;
+import org.slf4j.MDC;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.env.Environment;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+@RequiredArgsConstructor
+@Slf4j
+public class CorrelationHeaderFilter extends OncePerRequestFilter {
+
+    private String correlationIdHeader;
+
+    public static final String correlationIdKey = "correlationId";
+
+    @Autowired
+    public CorrelationHeaderFilter(Environment env) {
+        correlationIdHeader = env.getRequiredProperty("fineract.logging.http.correlation-id.header-name");
+    }
+
+    @Override
+    protected void doFilterInternal(final HttpServletRequest request, final HttpServletResponse response, final FilterChain filterChain)
+            throws IOException, ServletException {
+
+        try {
+            final HttpServletRequest httpServletRequest = (HttpServletRequest) request;
+            String currentCorrId = httpServletRequest.getHeader(correlationIdHeader);
+            log.debug("Found correlationId in Header : {}", LogParameterEscapeUtil.escapeLogMDCParameter(currentCorrId));
+            MDC.put(correlationIdKey, currentCorrId);
+            filterChain.doFilter(request, response);
+        } finally {
+            MDC.remove(correlationIdKey);
+        }
+    }
+
+    public static String getCurrentValue() {
+        return MDC.get(correlationIdKey);
+    }
+
+    @Override
+    protected boolean isAsyncDispatch(final HttpServletRequest request) {
+        return false;
+    }
+
+    @Override
+    protected boolean shouldNotFilterErrorDispatch() {
+        return false;
+    }
+
+}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/utils/LogParameterEscapeUtil.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/MdcAdapter.java
similarity index 52%
copy from fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/utils/LogParameterEscapeUtil.java
copy to fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/MdcAdapter.java
index 1e249f4f8..241aefdac 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/utils/LogParameterEscapeUtil.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/MdcAdapter.java
@@ -16,13 +16,42 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.fineract.infrastructure.security.utils;
 
-public final class LogParameterEscapeUtil {
+package org.apache.fineract.infrastructure.core.service;
 
-    private LogParameterEscapeUtil() {}
+import java.util.Map;
+import org.slf4j.MDC;
+import org.slf4j.spi.MDCAdapter;
 
-    public static String escapeLogParameter(String logParameter) {
-        return logParameter.replaceAll("[\n\r\t]", "_");
+public class MdcAdapter implements MDCAdapter {
+
+    @Override
+    public void put(String key, String val) {
+        MDC.put(key, val);
+    }
+
+    @Override
+    public String get(String key) {
+        return MDC.get(key);
+    }
+
+    @Override
+    public void remove(String key) {
+        MDC.remove(key);
+    }
+
+    @Override
+    public void clear() {
+        MDC.clear();
+    }
+
+    @Override
+    public Map<String, String> getCopyOfContextMap() {
+        return MDC.getCopyOfContextMap();
+    }
+
+    @Override
+    public void setContextMap(Map<String, String> map) {
+        MDC.setContextMap(map);
     }
 }
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/utils/LogParameterEscapeUtil.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/utils/LogParameterEscapeUtil.java
index 1e249f4f8..8eb145f80 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/utils/LogParameterEscapeUtil.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/utils/LogParameterEscapeUtil.java
@@ -25,4 +25,8 @@ public final class LogParameterEscapeUtil {
     public static String escapeLogParameter(String logParameter) {
         return logParameter.replaceAll("[\n\r\t]", "_");
     }
+
+    public static String escapeLogMDCParameter(String logParameter) {
+        return logParameter.replaceAll("[\r\n]", "");
+    }
 }
diff --git a/fineract-provider/src/main/resources/application.properties b/fineract-provider/src/main/resources/application.properties
index e939a8642..3bf753e0a 100644
--- a/fineract-provider/src/main/resources/application.properties
+++ b/fineract-provider/src/main/resources/application.properties
@@ -40,6 +40,12 @@ fineract.mode.write-enabled=${FINERACT_MODE_WRITE_ENABLED:true}
 fineract.mode.batch-worker-enabled=${FINERACT_MODE_BATCH_WORKER_ENABLED:true}
 fineract.mode.batch-manager-enabled=${FINERACT_MODE_BATCH_MANAGER_ENABLED:true}
 
+fineract.logging.http.correlation-id.enabled=${FINERACT_LOGGING_HTTP_CORRELATION_ID_ENABLED:false}
+fineract.logging.http.correlation-id.header-name=${FINERACT_LOGGING_HTTP_CORRELATION_ID_HEADER_NAME:X-Correlation-ID}
+
+# Logging pattern for the console
+logging.pattern.console=${CONSOLE_LOG_PATTERN:%d{yyyy-MM-dd HH\:mm\:ss.SSS} %thread %replace([%X{correlationId}]){'\\[\\]', ''} [%-5level] %class{0} - %msg%n}
+
 management.health.jms.enabled=false
 
 # FINERACT 1296
diff --git a/fineract-provider/src/main/resources/logback-spring.xml b/fineract-provider/src/main/resources/logback-spring.xml
index a24143495..8ede0e3e3 100644
--- a/fineract-provider/src/main/resources/logback-spring.xml
+++ b/fineract-provider/src/main/resources/logback-spring.xml
@@ -39,5 +39,6 @@
     <!-- But these three INFO are still handy ;-) just to see when it's up and running -->
     <logger name="org.springframework.boot.web.embedded.tomcat.TomcatWebServer" level="info" />
     <logger name="org.apache.fineract.ServerApplication" level="info" />
+    <logger name="org.apache.fineract" level="${FINERACT_LOGGING_LEVEL:-INFO}" />
     <logger name="liquibase" level="info" />
 </configuration>
diff --git a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/core/filters/FineractCorrelationIdApiFilterTest.java b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/core/filters/FineractCorrelationIdApiFilterTest.java
new file mode 100644
index 000000000..b042b5928
--- /dev/null
+++ b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/core/filters/FineractCorrelationIdApiFilterTest.java
@@ -0,0 +1,80 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.fineract.infrastructure.core.filters;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.verify;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+import java.util.UUID;
+import org.apache.fineract.infrastructure.core.service.MdcAdapter;
+import org.junit.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.mockito.junit.jupiter.MockitoSettings;
+import org.mockito.quality.Strictness;
+import org.slf4j.MDC;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
+import org.springframework.boot.test.mock.mockito.SpyBean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.web.servlet.MockMvc;
+
+@ExtendWith(MockitoExtension.class)
+@MockitoSettings(strictness = Strictness.LENIENT)
+@ContextConfiguration(classes = { Configuration.class })
+@WebMvcTest
+class FineractCorrelationIdApiFilterTest {
+
+    @SpyBean
+    private MdcAdapter mdc;
+
+    @Autowired
+    private MockMvc mockMvc;
+
+    @ParameterizedTest
+    @ValueSource(strings = { "/fineract-provider/api/v1/loans", "/fineract-provider/api/v1/loans" })
+    void shouldGet200IfXCorrelationIdHeaderIsPresentAndRequestIsForV1Path(String url) throws Exception {
+        String correlationId = UUID.randomUUID().toString();
+        mockMvc.perform(get(url).header(CorrelationHeaderFilter.correlationIdKey, correlationId)).andExpect(status().isOk())
+                .andExpect(header().string(CorrelationHeaderFilter.correlationIdKey, correlationId));
+
+        verify(mdc).remove(CorrelationHeaderFilter.correlationIdKey);
+    }
+
+    @ParameterizedTest
+    @ValueSource(strings = { "/fineract-provider/api/v1/loans", "/fineract-provider/api/v1/loans" })
+    void shouldGet400IfXCorrelationIdHeaderIsNotPresentAndRequestIsForV1Path(String url) throws Exception {
+        mockMvc.perform(get(url)).andExpect(status().isBadRequest())
+                .andExpect(header().doesNotExist(CorrelationHeaderFilter.correlationIdKey));
+    }
+
+    @Test
+    void shouldReturnCurrentCorrelationIdFromMDC() {
+        MDC.put(CorrelationHeaderFilter.correlationIdKey, "1");
+        assertThat(CorrelationHeaderFilter.getCurrentValue()).isEqualTo("1");
+    }
+
+}
diff --git a/fineract-provider/src/test/resources/application-test.properties b/fineract-provider/src/test/resources/application-test.properties
index 58981db96..54deaac7d 100644
--- a/fineract-provider/src/test/resources/application-test.properties
+++ b/fineract-provider/src/test/resources/application-test.properties
@@ -37,6 +37,9 @@ fineract.mode.read-enabled=true
 fineract.mode.write-enabled=true
 fineract.mode.batch-enabled=true
 
+fineract.logging.http.correlation-id.enabled=false
+fineract.logging.http.correlation-id.header-name=X-Correlation-ID
+
 management.health.jms.enabled=false
 
 # FINERACT 1296
diff --git a/fineract-war/setenv.sh b/fineract-war/setenv.sh
index 5d69b5aba..531936710 100644
--- a/fineract-war/setenv.sh
+++ b/fineract-war/setenv.sh
@@ -53,3 +53,5 @@ export FINERACT_DEFAULT_TENANTDB_TIMEZONE="Asia/Kolkata"
 export FINERACT_DEFAULT_TENANTDB_IDENTIFIER="default"
 export FINERACT_DEFAULT_TENANTDB_NAME="fineract_default"
 export FINERACT_DEFAULT_TENANTDB_DESCRIPTION="Default Demo Tenant"
+export FINERACT_LOGGING_HTTP_CORRELATION_ID_ENABLED="false"
+export FINERACT_LOGGING_HTTP_CORRELATION_ID_HEADER_NAME="X-Correlation-ID"