From 8e9cf59f25130ac4797f5fa83e88da5c875f2c34 Mon Sep 17 00:00:00 2001 From: Jan Date: Fri, 28 Nov 2025 13:01:59 +0100 Subject: [PATCH] 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. --- pom.xml | 6 +-- .../java/de/avatic/lcc/LccApplication.java | 19 +++++-- .../avatic/lcc/config/ShutdownListener.java | 20 +++++++ .../config/filter/DevUserEmulationFilter.java | 12 +++-- .../config/filter/RequestLoggerFilter.java | 54 +++++++++++++++++++ 5 files changed, 99 insertions(+), 12 deletions(-) create mode 100644 src/main/java/de/avatic/lcc/config/ShutdownListener.java create mode 100644 src/main/java/de/avatic/lcc/config/filter/RequestLoggerFilter.java diff --git a/pom.xml b/pom.xml index ebf5633..f06df5f 100644 --- a/pom.xml +++ b/pom.xml @@ -33,11 +33,6 @@ 11.18.0 - - - org.springframework.boot - spring-boot-starter-batch - org.springframework.boot spring-boot-starter-jdbc @@ -139,6 +134,7 @@ org.springframework.boot spring-boot-devtools runtime + true org.mockito diff --git a/src/main/java/de/avatic/lcc/LccApplication.java b/src/main/java/de/avatic/lcc/LccApplication.java index c6fd3cb..00195e9 100644 --- a/src/main/java/de/avatic/lcc/LccApplication.java +++ b/src/main/java/de/avatic/lcc/LccApplication.java @@ -1,13 +1,26 @@ package de.avatic.lcc; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class LccApplication { - public static void main(String[] args) { - SpringApplication.run(LccApplication.class, args); - } + static Logger logger = LoggerFactory.getLogger(LccApplication.class); + + 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); + + } } diff --git a/src/main/java/de/avatic/lcc/config/ShutdownListener.java b/src/main/java/de/avatic/lcc/config/ShutdownListener.java new file mode 100644 index 0000000..f2f35b0 --- /dev/null +++ b/src/main/java/de/avatic/lcc/config/ShutdownListener.java @@ -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(); + } +} \ No newline at end of file diff --git a/src/main/java/de/avatic/lcc/config/filter/DevUserEmulationFilter.java b/src/main/java/de/avatic/lcc/config/filter/DevUserEmulationFilter.java index c203e9c..0f6b5b0 100644 --- a/src/main/java/de/avatic/lcc/config/filter/DevUserEmulationFilter.java +++ b/src/main/java/de/avatic/lcc/config/filter/DevUserEmulationFilter.java @@ -10,6 +10,8 @@ import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpSession; import org.jetbrains.annotations.NotNull; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Profile; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; @@ -32,6 +34,8 @@ import java.util.Set; @Profile("dev | test") 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 final UserRepository userRepository; @@ -48,17 +52,17 @@ public class DevUserEmulationFilter extends OncePerRequestFilter { Integer emulatedUserId = (Integer) session.getAttribute(DEV_USER_ID_SESSION_KEY); // Add logging to debug - System.out.println("DevUserEmulationFilter - Session ID: " + session.getId()); - System.out.println("DevUserEmulationFilter - Emulated User ID: " + emulatedUserId); + log.debug("DevUserEmulationFilter - Session ID: " + session.getId()); + log.debug("DevUserEmulationFilter - Emulated User ID: " + emulatedUserId); if(emulatedUserId != null) { User user = userRepository.getById(emulatedUserId); if (user != null) { setEmulatedUser(user); - System.out.println("DevUserEmulationFilter - Set user: " + user.getEmail()); + log.debug("DevUserEmulationFilter - Set user: " + user.getEmail()); } } else { - System.out.println("DevUserEmulationFilter - " + request.getRequestURI() + " - No emulated user set"); + log.debug("DevUserEmulationFilter - " + request.getRequestURI() + " - No emulated user set"); } filterChain.doFilter(request, response); diff --git a/src/main/java/de/avatic/lcc/config/filter/RequestLoggerFilter.java b/src/main/java/de/avatic/lcc/config/filter/RequestLoggerFilter.java new file mode 100644 index 0000000..0613e79 --- /dev/null +++ b/src/main/java/de/avatic/lcc/config/filter/RequestLoggerFilter.java @@ -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(); + } +}