Skip to content

Commit 5440a50

Browse files
authored
Merge pull request #10 from companieshouse/lp-170-add-logging-intereptor
LP-170 Add Logging Interceptor to log all requests to the api
2 parents 719f4dc + 2547714 commit 5440a50

File tree

7 files changed

+154
-3
lines changed

7 files changed

+154
-3
lines changed

pom.xml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
<spring-boot-dependencies.version>3.3.4</spring-boot-dependencies.version>
2323
<spring-boot-maven-plugin.version>3.3.4</spring-boot-maven-plugin.version>
2424
<structured-logging.version>3.0.20</structured-logging.version>
25+
<log4j.version>2.24.1</log4j.version>
2526
<jib-maven-plugin.version>3.4.2</jib-maven-plugin.version>
2627
</properties>
2728

@@ -36,6 +37,13 @@
3637

3738
<dependencyManagement>
3839
<dependencies>
40+
<dependency>
41+
<groupId>org.apache.logging.log4j</groupId>
42+
<artifactId>log4j-bom</artifactId>
43+
<version>${log4j.version}</version>
44+
<scope>import</scope>
45+
<type>pom</type>
46+
</dependency>
3947
<dependency>
4048
<groupId>org.springframework.boot</groupId>
4149
<artifactId>spring-boot-dependencies</artifactId>
@@ -60,7 +68,6 @@
6068
<version>${structured-logging.version}</version>
6169
</dependency>
6270

63-
6471
<!-- Test dependencies -->
6572
<dependency>
6673
<groupId>org.springframework.boot</groupId>
@@ -74,6 +81,7 @@
7481
<scope>test</scope>
7582
</dependency>
7683
</dependencies>
84+
7785
<build>
7886
<plugins>
7987
<plugin>
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package uk.gov.companieshouse.limitedpartnershipsapi.config;
2+
3+
import org.springframework.context.annotation.Configuration;
4+
import org.springframework.lang.NonNull;
5+
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
6+
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
7+
import uk.gov.companieshouse.limitedpartnershipsapi.interceptor.LoggingInterceptor;
8+
9+
10+
@Configuration
11+
public class InterceptorConfig implements WebMvcConfigurer {
12+
13+
private final LoggingInterceptor loggingInterceptor;
14+
15+
public InterceptorConfig(LoggingInterceptor loggingInterceptor) {
16+
this.loggingInterceptor = loggingInterceptor;
17+
}
18+
19+
/**
20+
* Set up the interceptors to run against endpoints when the endpoints are called
21+
* Interceptors are executed in the order they are added to the registry
22+
* @param registry The spring interceptor registry
23+
*/
24+
@Override
25+
public void addInterceptors(@NonNull InterceptorRegistry registry) {
26+
registry.addInterceptor(loggingInterceptor);
27+
}
28+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package uk.gov.companieshouse.limitedpartnershipsapi.interceptor;
2+
3+
import jakarta.servlet.http.HttpServletRequest;
4+
import jakarta.servlet.http.HttpServletResponse;
5+
import org.springframework.lang.NonNull;
6+
import org.springframework.stereotype.Component;
7+
import org.springframework.web.servlet.HandlerInterceptor;
8+
import org.springframework.web.servlet.HandlerMapping;
9+
import uk.gov.companieshouse.limitedpartnershipsapi.utils.ApiLogger;
10+
11+
import static uk.gov.companieshouse.limitedpartnershipsapi.utils.Constants.ERIC_REQUEST_ID_KEY;
12+
13+
14+
@Component
15+
public class LoggingInterceptor implements HandlerInterceptor {
16+
17+
private static final String START_TIME_KEY = "start-time";
18+
19+
@Override
20+
public boolean preHandle(HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull Object handler) {
21+
Long startTime = System.currentTimeMillis();
22+
request.setAttribute(START_TIME_KEY, startTime);
23+
24+
ApiLogger.infoContext(getRequestId(request), String.format("Start of request. Method: %s Path: %s",
25+
getRequestMethod(request), getRequestPath(request)), null);
26+
return true;
27+
}
28+
29+
@Override
30+
public void afterCompletion(HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull Object handler, Exception ex) {
31+
Long startTime = (Long) request.getAttribute(START_TIME_KEY);
32+
33+
if (startTime == null) {
34+
ApiLogger.infoContext(getRequestId(request), "Start time not found in request attributes.", null);
35+
} else {
36+
long responseTime = System.currentTimeMillis() - startTime;
37+
ApiLogger.infoContext(getRequestId(request), String.format("End of request. Method: %s Path: %s Duration: %sms Status: %s",
38+
getRequestMethod(request), getRequestPath(request), responseTime, response.getStatus()), null);
39+
}
40+
}
41+
42+
private String getRequestPath(HttpServletRequest request) {
43+
return (String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
44+
}
45+
46+
private String getRequestMethod(HttpServletRequest request) {
47+
return request.getMethod();
48+
}
49+
50+
private String getRequestId(HttpServletRequest request) {
51+
return request.getHeader(ERIC_REQUEST_ID_KEY);
52+
}
53+
}

src/main/java/uk/gov/companieshouse/limitedpartnershipsapi/utils/ApiLogger.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99

1010
public class ApiLogger {
1111

12+
private ApiLogger() {}
13+
1214
private static final Logger LOGGER =
1315
LoggerFactory.getLogger(LimitedPartnershipsApiApplication.APP_NAMESPACE);
1416

@@ -32,6 +34,10 @@ public static void infoContext(String context, String message) {
3234
LOGGER.infoContext(context, message, null);
3335
}
3436

37+
public static void infoContext(String context, String message, Map<String, Object> dataMap) {
38+
LOGGER.infoContext(context, message, cloneMapData(dataMap));
39+
}
40+
3541
public static void errorContext(String context, Exception e) {
3642
LOGGER.errorContext(context, e, null);
3743
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package uk.gov.companieshouse.limitedpartnershipsapi.utils;
2+
3+
public class Constants {
4+
5+
private Constants() { }
6+
7+
// Request header names
8+
public static final String ERIC_REQUEST_ID_KEY = "X-Request-Id";
9+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package uk.gov.companieshouse.limitedpartnershipsapi.config;
2+
3+
import org.junit.jupiter.api.Test;
4+
import org.junit.jupiter.api.extension.ExtendWith;
5+
import org.mockito.InOrder;
6+
import org.mockito.InjectMocks;
7+
import org.mockito.Mock;
8+
import org.mockito.junit.jupiter.MockitoExtension;
9+
import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
10+
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
11+
import uk.gov.companieshouse.limitedpartnershipsapi.interceptor.LoggingInterceptor;
12+
13+
14+
import static org.mockito.ArgumentMatchers.any;
15+
import static org.mockito.Mockito.inOrder;
16+
import static org.mockito.Mockito.times;
17+
import static org.mockito.Mockito.verify;
18+
import static org.mockito.Mockito.when;
19+
20+
@ExtendWith(MockitoExtension.class)
21+
class InterceptorConfigTest {
22+
23+
@Mock
24+
private InterceptorRegistry interceptorRegistry;
25+
26+
@Mock
27+
private InterceptorRegistration interceptorRegistration;
28+
29+
@Mock
30+
private LoggingInterceptor loggingInterceptor;
31+
32+
33+
@InjectMocks
34+
private InterceptorConfig interceptorConfig;
35+
36+
@Test
37+
void addInterceptorsTest() {
38+
when(interceptorRegistry.addInterceptor(any())).thenReturn(interceptorRegistration);
39+
40+
interceptorConfig.addInterceptors(interceptorRegistry);
41+
42+
InOrder inOrder = inOrder(interceptorRegistry, interceptorRegistration);
43+
inOrder.verify(interceptorRegistry).addInterceptor(loggingInterceptor);
44+
45+
verify(interceptorRegistry, times(1)).addInterceptor(any());
46+
}
47+
}

src/test/java/uk/gov/companieshouse/limitedpartnershipsapi/utils/ApiLoggerTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
import static org.junit.jupiter.api.Assertions.assertEquals;
1010

11-
public class ApiLoggerTest {
11+
class ApiLoggerTest {
1212

1313
private static final String CONTEXT = "CONTEXT";
1414
private static final String TEST_MESSAGE = "TEST";
@@ -41,7 +41,7 @@ void testInfoLoggingDoesNotModifyLogMap() {
4141

4242
@Test
4343
void testInfoContextLoggingDoesNotModifyLogMap() {
44-
ApiLogger.infoContext(CONTEXT, TEST_MESSAGE);
44+
ApiLogger.infoContext(CONTEXT, TEST_MESSAGE, logMap);
4545

4646
assertEquals(1, logMap.size());
4747
assertEquals(LOG_MAP_VALUE, logMap.get(LOG_MAP_KEY));

0 commit comments

Comments
 (0)