Skip to content

FINERACT-1656: Correlation ID propagation and configuration#2389

Closed
IOhacker wants to merge 26 commits intoapache:developfrom
IOhacker:PERF-483
Closed

FINERACT-1656: Correlation ID propagation and configuration#2389
IOhacker wants to merge 26 commits intoapache:developfrom
IOhacker:PERF-483

Conversation

@IOhacker
Copy link
Contributor

@IOhacker IOhacker commented Jun 29, 2022

Description

Description

The goal of this story is to provide a way for external systems to pass a correlation ID as a request header to Fineract APIs so that a full trace of request path can be looked at later on in a log aggregator (Kibana/Splunk/etc).

Acceptance criteria:

The correlation ID is taken from an HTTP request header
The HTTP request header’s name is configurable via a Spring property and an environment variable
The default HTTP request header’s name is X-Correlation-ID
If a correlation ID is provided, it’s inserted into the MDC context
If a correlation ID is present in the MDC context, it’s included in the log pattern
The correlation ID propagation can be enabled and disabled via a Spring property and an environment variable
Note:

The 2 properties could be called:

fineract.logging.http.correlation-id.enabled=true/false
fineract.logging.http.correlation-id.header-name=something

Jira:
https://issues.apache.org/jira/browse/FINERACT-1656

Checklist

Please make sure these boxes are checked before submitting your pull request - thanks!

  • Write the commit message as per https://github.com/apache/fineract/#pull-requests

  • Acknowledge that we will not review PRs that are not passing the build ("green") - it is your responsibility to get a proposed PR to pass the build, not primarily the project's maintainers.

  • Create/update unit or integration tests for verifying the changes made.

  • Follow coding conventions at https://cwiki.apache.org/confluence/display/FINERACT/Coding+Conventions.

  • Add required Swagger annotation and update API documentation at fineract-provider/src/main/resources/static/legacy-docs/apiLive.htm with details of any API changes

  • Submission is not a "code dump". (Large changes can be made "in repository" via a branch. Ask on the developer mailing list for guidance, if required.)

FYI our guidelines for code reviews are at https://cwiki.apache.org/confluence/display/FINERACT/Code+Review+Guide.

Copy link
Contributor

@galovics galovics left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couple of changes needed but overall it's getting there.

@IOhacker please also add new unit test cases to verify the filter functionality.

@IOhacker
Copy link
Contributor Author

@galovics I am working on the Tests, ASAP I will send them


private String CORRELATION_ID_HEADER;

@Autowired
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not using the FineractProperties here? That way you can get rid of the explicit constructor and switch it over to Lombok generating the constructor plus you are not hardcoding the environment key.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@IOhacker do you mind sharing how you tried the FineractProperties and where you got stuck with it? Thanks.

final HttpServletRequest httpServletRequest = (HttpServletRequest) request;
currentCorrId = httpServletRequest.getHeader( CORRELATION_ID_HEADER);
log.debug("Found correlationId in Header : {}", currentCorrId.replaceAll("[\r\n]","") );
MDC.put("correlationId", currentCorrId);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now, "correlationId" could be a constant to get rid of the "magic string" approach.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

- 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 [%X{correlationId}] [%-5level] %class{0} - %msg%n
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why don't we override the default bundled log pattern in Fineract within the application.properties?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Working on that

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now the pattern is in the application.properties


}

public static FineractProperties.FineractCorrelationProperties createCorrelationProps(boolean enabled, String headerName) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's move this into the test class. No need to be present as a separate class. At least for now.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

final class MutableHttpServletRequest extends HttpServletRequestWrapper {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not simple mocking the HttpServletRequest?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

// when
underTest.doFilterInternal(mutableRequest, response, filterChain);
// then
verify(filterChain).doFilter(mutableRequest, response);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice job overall, I'm just missing one tiny piece from the tests, to verify that the MDC context has been enhanced with the correlation ID.
I know probably you were stuck there because MDC is available from a static context but what you can do is to create an MDCService in the production code which is a Spring bean and autowire it into the Filter and then use the MDCService to write into the MDC context.
This way you extracted the static MDC writing logic into a separate component that can be easily mocked out in the test.
What do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking about another approach, let me share it

@awasum
Copy link
Contributor

awasum commented Jul 1, 2022

Hi All,

Is PERF-483 an external issue number can we try to recreate the issue on Fineract JIRA and use the issue number here so things are a bit transparent in this Open Source Project?

@IOhacker IOhacker changed the title PERF-483 Correlation ID propagation and configuration FINERACT-1656: Correlation ID propagation and configuration Jul 2, 2022

private String CORRELATION_ID_HEADER;

@Autowired
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@IOhacker do you mind sharing how you tried the FineractProperties and where you got stuck with it? Thanks.

import org.slf4j.MDC;
import org.slf4j.spi.MDCAdapter;

public class MdcAdapter implements MDCAdapter {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand the concept but this is most definitely not going to work. On one hand the adapter is not used by anything and on the other, you're calling the MDC inside the adapter which'll end up in a recursion even if it's configured for SLF4J. The approach I suggested before would work.

@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
@ContextConfiguration(classes = { Configuration.class })
@WebMvcTest
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like we're overthinking this. The Filter test could be as simple as a plain unit test. We don't need WebMvc because we're not trying to verify a whole set of filters and controllers but only a single method in a class.
That'd simplify a lot of things, could you please double-check?

@galovics
Copy link
Contributor

Closing in favor of #2427

@galovics galovics closed this Jul 13, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants