Add logging improvements, shutdown listener, and request filter

- Introduced `ShutdownListener` to log application shutdown details and thread stack dump.
- Added `RequestLoggerFilter` to log incoming HTTP requests and responses.
- Enhanced `LccApplication` with memory usage logging at start and end.
- Replaced `System.out` calls with SLF4J logging in `DevUserEmulationFilter`.
- Updated `pom.xml` to mark devtools dependency as optional.
This commit is contained in:
Jan 2025-11-28 13:01:59 +01:00
parent 0b02021fde
commit 8e9cf59f25
5 changed files with 99 additions and 12 deletions

View file

@ -33,11 +33,6 @@
<flyway.version>11.18.0</flyway.version> <flyway.version>11.18.0</flyway.version>
</properties> </properties>
<dependencies> <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-batch</artifactId>
</dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId> <artifactId>spring-boot-starter-jdbc</artifactId>
@ -139,6 +134,7 @@
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId> <artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope> <scope>runtime</scope>
<optional>true</optional>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.mockito</groupId> <groupId>org.mockito</groupId>

View file

@ -1,13 +1,26 @@
package de.avatic.lcc; package de.avatic.lcc;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication @SpringBootApplication
public class LccApplication { public class LccApplication {
public static void main(String[] args) { static Logger logger = LoggerFactory.getLogger(LccApplication.class);
SpringApplication.run(LccApplication.class, args);
} public static void main(String[] args) {
Runtime runtime = Runtime.getRuntime();
long usedMemory = (runtime.totalMemory() - runtime.freeMemory()) / 1024 / 1024;
logger.info("LCC Start - Memory: {} used, {} total, {} free, {} max ", usedMemory, runtime.totalMemory() / 1024 / 1024, runtime.freeMemory() / 1024 / 1024, runtime.maxMemory() / 1024 / 1024);
SpringApplication.run(LccApplication.class, args);
usedMemory = (runtime.totalMemory() - runtime.freeMemory()) / 1024 / 1024;
logger.info("LCC End - Memory: {} used, {} total, {} free, {} max ", usedMemory, runtime.totalMemory() / 1024 / 1024, runtime.freeMemory() / 1024 / 1024, runtime.maxMemory() / 1024 / 1024);
}
} }

View file

@ -0,0 +1,20 @@
package de.avatic.lcc.config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.event.ContextClosedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
@Component
public class ShutdownListener {
private static final Logger log = LoggerFactory.getLogger(ShutdownListener.class);
@EventListener
public void onShutdown(ContextClosedEvent event) {
log.error("Application shutdown. Context: {}, Thread: {}", event.getApplicationContext(), Thread.currentThread().getName());
log.error("Thread stack dump:");
Thread.dumpStack();
}
}

View file

@ -10,6 +10,8 @@ import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession; import jakarta.servlet.http.HttpSession;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Profile; import org.springframework.context.annotation.Profile;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.GrantedAuthority;
@ -32,6 +34,8 @@ import java.util.Set;
@Profile("dev | test") @Profile("dev | test")
public class DevUserEmulationFilter extends OncePerRequestFilter { public class DevUserEmulationFilter extends OncePerRequestFilter {
private final Logger log = LoggerFactory.getLogger(DevUserEmulationFilter.class);
private static final String DEV_USER_ID_SESSION_KEY = "dev.emulated.user.id"; private static final String DEV_USER_ID_SESSION_KEY = "dev.emulated.user.id";
private final UserRepository userRepository; private final UserRepository userRepository;
@ -48,17 +52,17 @@ public class DevUserEmulationFilter extends OncePerRequestFilter {
Integer emulatedUserId = (Integer) session.getAttribute(DEV_USER_ID_SESSION_KEY); Integer emulatedUserId = (Integer) session.getAttribute(DEV_USER_ID_SESSION_KEY);
// Add logging to debug // Add logging to debug
System.out.println("DevUserEmulationFilter - Session ID: " + session.getId()); log.debug("DevUserEmulationFilter - Session ID: " + session.getId());
System.out.println("DevUserEmulationFilter - Emulated User ID: " + emulatedUserId); log.debug("DevUserEmulationFilter - Emulated User ID: " + emulatedUserId);
if(emulatedUserId != null) { if(emulatedUserId != null) {
User user = userRepository.getById(emulatedUserId); User user = userRepository.getById(emulatedUserId);
if (user != null) { if (user != null) {
setEmulatedUser(user); setEmulatedUser(user);
System.out.println("DevUserEmulationFilter - Set user: " + user.getEmail()); log.debug("DevUserEmulationFilter - Set user: " + user.getEmail());
} }
} else { } else {
System.out.println("DevUserEmulationFilter - " + request.getRequestURI() + " - No emulated user set"); log.debug("DevUserEmulationFilter - " + request.getRequestURI() + " - No emulated user set");
} }
filterChain.doFilter(request, response); filterChain.doFilter(request, response);

View file

@ -0,0 +1,54 @@
package de.avatic.lcc.config.filter;
import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.io.IOException;
@Component
public class RequestLoggerFilter implements Filter {
private static final Logger log = LoggerFactory.getLogger(RequestLoggerFilter.class);
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
long startTime = System.currentTimeMillis();
log.info(">>> INCOMING REQUEST: {} {} from {} - Headers: {}",
httpRequest.getMethod(),
httpRequest.getRequestURI(),
httpRequest.getRemoteAddr(),
getHeadersAsString(httpRequest));
try {
chain.doFilter(request, response);
} finally {
long duration = System.currentTimeMillis() - startTime;
log.info("<<< RESPONSE: {} {} -> Status: {} ({}ms)",
httpRequest.getMethod(),
httpRequest.getRequestURI(),
httpResponse.getStatus(),
duration);
}
}
private String getHeadersAsString(HttpServletRequest request) {
StringBuilder headers = new StringBuilder();
var headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()) {
String headerName = headerNames.nextElement();
headers.append(headerName).append("=")
.append(request.getHeader(headerName)).append("; ");
}
return headers.toString();
}
}