diff --git a/build.gradle b/build.gradle index b9c1a7f..9a08227 100644 --- a/build.gradle +++ b/build.gradle @@ -47,6 +47,8 @@ dependencies { // actuator implementation 'org.springframework.boot:spring-boot-starter-actuator' + implementation 'io.micrometer:micrometer-core' + implementation 'io.micrometer:micrometer-registry-prometheus' implementation 'io.sentry:sentry-spring-boot-starter-jakarta:8.3.0' implementation 'javax.enterprise:cdi-api:2.0' diff --git a/src/main/java/com/example/Jinus/controller/DietController.java b/src/main/java/com/example/Jinus/controller/DietController.java index d3b0ccf..018e08e 100644 --- a/src/main/java/com/example/Jinus/controller/DietController.java +++ b/src/main/java/com/example/Jinus/controller/DietController.java @@ -8,15 +8,22 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + @RestController @RequestMapping("/api/spring") @RequiredArgsConstructor public class DietController { - private final DietService dietServiceV2; + private final DietService dietService; + private static final Logger logger = LoggerFactory.getLogger(DietController.class); @PostMapping("/v2/dish") public String handleRequest(@RequestBody RequestDto requestDto) { - return dietServiceV2.requestHandler(requestDto); + String threadName = Thread.currentThread().getName(); + logger.info("[식단 요청] 스레드 이름: {}", threadName); + + return dietService.requestHandler(requestDto); } } diff --git a/src/main/java/com/example/Jinus/monitor/HikariCPMonitor.java b/src/main/java/com/example/Jinus/monitor/HikariCPMonitor.java new file mode 100644 index 0000000..3bcd0ed --- /dev/null +++ b/src/main/java/com/example/Jinus/monitor/HikariCPMonitor.java @@ -0,0 +1,35 @@ +package com.example.Jinus.monitor; + +import com.zaxxer.hikari.HikariDataSource; +import com.zaxxer.hikari.HikariPoolMXBean; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +public class HikariCPMonitor { + + private final HikariDataSource dataSource; + + @Autowired + public HikariCPMonitor(HikariDataSource dataSource) { + this.dataSource = dataSource; + } + + @Scheduled(fixedRateString = "${monitor.pool.status.rate.ms:60000}") // 상태 출력 주기 (기본 1분) + public void logHikariStatus() { + if (dataSource != null) { + HikariPoolMXBean poolMXBean = dataSource.getHikariPoolMXBean(); + + int total = poolMXBean.getTotalConnections(); + int active = poolMXBean.getActiveConnections(); + int idle = poolMXBean.getIdleConnections(); + int waiting = poolMXBean.getThreadsAwaitingConnection(); + + log.info("[HikariCP 상태] 전체: {} / 사용 중: {} / 유휴: {} / 대기 중: {}", + + total, active, idle, waiting); + } + } +} diff --git a/src/main/java/com/example/Jinus/monitor/TomcatThreadMonitor.java b/src/main/java/com/example/Jinus/monitor/TomcatThreadMonitor.java new file mode 100644 index 0000000..967429a --- /dev/null +++ b/src/main/java/com/example/Jinus/monitor/TomcatThreadMonitor.java @@ -0,0 +1,47 @@ +package com.example.Jinus.monitor; + +import lombok.extern.slf4j.Slf4j; +import org.apache.catalina.connector.Connector; +import org.apache.coyote.ProtocolHandler; +import org.apache.coyote.AbstractProtocol; +import org.apache.tomcat.util.threads.ThreadPoolExecutor; +import org.springframework.boot.web.embedded.tomcat.TomcatWebServer; +import org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.util.concurrent.Executor; + +@Component +@Slf4j +public class TomcatThreadMonitor { + + private final ServletWebServerApplicationContext context; + + public TomcatThreadMonitor(ServletWebServerApplicationContext context) { + this.context = context; + } + + @Scheduled(fixedRateString = "${monitor.pool.status.rate.ms:60000}") // 상태 출력 주기 (기본 1분) + public void logTomcatThreadPoolStatus() { + if (context.getWebServer() instanceof TomcatWebServer tomcatWebServer) { + Connector connector = tomcatWebServer.getTomcat().getConnector(); + ProtocolHandler handler = connector.getProtocolHandler(); + + if (handler instanceof AbstractProtocol protocol) { + Executor executor = protocol.getExecutor(); + + if (executor instanceof ThreadPoolExecutor threadPoolExecutor) { + int max = threadPoolExecutor.getMaximumPoolSize(); + int poolSize = threadPoolExecutor.getPoolSize(); + int active = threadPoolExecutor.getActiveCount(); + long taskCount = threadPoolExecutor.getTaskCount(); + long completedTaskCount = threadPoolExecutor.getCompletedTaskCount(); + + log.info("[Tomcat 스레드] MaxPoolSize: {}, PoolSize: {}, 활성: {}, TaskCount: {}, 완료: {}", + + max, poolSize, active, taskCount, completedTaskCount); + } + } + } + } +} diff --git a/src/main/java/com/example/Jinus/service/cafeteria/CacheService.java b/src/main/java/com/example/Jinus/service/cafeteria/CacheService.java index c2c246c..a1bd371 100644 --- a/src/main/java/com/example/Jinus/service/cafeteria/CacheService.java +++ b/src/main/java/com/example/Jinus/service/cafeteria/CacheService.java @@ -55,10 +55,10 @@ private long calculateTtlUntilNextMidnight(Date dietDate) { // Redis에서 조회 (없으면 DB에서 가져옴) - @Cacheable( - value = "cafeteriaList", - key = "#p0", - cacheManager = "contentCacheManager") +// @Cacheable( +// value = "cafeteriaList", +// key = "#p0", +// cacheManager = "contentCacheManager") public List getCafeteriaList(int campusId) { return cafeteriaRepositoryV2.findCafeteriaListByCampusId(campusId); } diff --git a/src/main/java/com/example/Jinus/service/cafeteria/CafeteriaQueryService.java b/src/main/java/com/example/Jinus/service/cafeteria/CafeteriaQueryService.java index 0dcc2f0..b1763c3 100644 --- a/src/main/java/com/example/Jinus/service/cafeteria/CafeteriaQueryService.java +++ b/src/main/java/com/example/Jinus/service/cafeteria/CafeteriaQueryService.java @@ -12,19 +12,19 @@ public class CafeteriaQueryService { private final CafeteriaRepository cafeteriaRepositoryV2; - @Cacheable( - value = "cafeteriaId", - key = "#p0 + '::' + #p1", - unless = "#result == -1", - cacheManager = "contentCacheManager") +// @Cacheable( +// value = "cafeteriaId", +// key = "#p0 + '::' + #p1", +// unless = "#result == -1", +// cacheManager = "contentCacheManager") public int getCafeteriaId(String cafeteriaName, int campusId) { return cafeteriaRepositoryV2.findCafeteriaId(cafeteriaName, campusId).orElse(-1); } - @Cacheable( - value = "cafeteriaUrl", - key = "#p0", - cacheManager = "contentCacheManager") +// @Cacheable( +// value = "cafeteriaUrl", +// key = "#p0", +// cacheManager = "contentCacheManager") public String getImgUrl(int cafeteriaId) { return cafeteriaRepositoryV2.findImgUrlByCafeteriaId(cafeteriaId); } diff --git a/src/main/java/com/example/Jinus/service/cafeteria/CampusService.java b/src/main/java/com/example/Jinus/service/cafeteria/CampusService.java index 6d4f35f..74bf7cc 100644 --- a/src/main/java/com/example/Jinus/service/cafeteria/CampusService.java +++ b/src/main/java/com/example/Jinus/service/cafeteria/CampusService.java @@ -15,10 +15,10 @@ public class CampusService { private final CampusRepository campusRepositoryV2; - @Cacheable( - value = "campusId", - key = "#p0", - cacheManager = "contentCacheManager") +// @Cacheable( +// value = "campusId", +// key = "#p0", +// cacheManager = "contentCacheManager") // 사용자의 campusId 받아 캠퍼스 이름 찾기 public String getUserCampusName(int campusId) { return campusRepositoryV2.findCampusNameByCampusId(campusId); @@ -29,10 +29,10 @@ public List getCampusList() { return campusRepositoryV2.findCampusList(); } - @Cacheable( - value = "campusName", - key = "#p0", - cacheManager = "contentCacheManager") +// @Cacheable( +// value = "campusName", +// key = "#p0", +// cacheManager = "contentCacheManager") // 캠퍼스 이름으로 id 찾기 public int getCampusId(String campusName) { return campusRepositoryV2.findCampusIdByName(campusName); diff --git a/src/main/java/com/example/Jinus/service/diet/DietQueryService.java b/src/main/java/com/example/Jinus/service/diet/DietQueryService.java index 0ae8d03..53cab73 100644 --- a/src/main/java/com/example/Jinus/service/diet/DietQueryService.java +++ b/src/main/java/com/example/Jinus/service/diet/DietQueryService.java @@ -20,7 +20,6 @@ public class DietQueryService { private final CacheService cacheServiceV2; - private final DietRepository dietRepositoryV2; // 메뉴 존재 여부에 따른 반환값 처리 로직 public String getDietResponse(HandleRequestDto parameters, int cafeteriaId) { diff --git a/src/main/java/com/example/Jinus/service/userInfo/CollegeService.java b/src/main/java/com/example/Jinus/service/userInfo/CollegeService.java index 91bf820..c8eb2ef 100644 --- a/src/main/java/com/example/Jinus/service/userInfo/CollegeService.java +++ b/src/main/java/com/example/Jinus/service/userInfo/CollegeService.java @@ -1,6 +1,5 @@ package com.example.Jinus.service.userInfo; -import com.example.Jinus.entity.userInfo.CollegeEntity; import com.example.Jinus.repository.userInfo.CollegeRepository; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -8,39 +7,10 @@ @Service public class CollegeService { - private static final Logger logger = LoggerFactory.getLogger(CollegeService.class); private final CollegeRepository collegeRepository; public CollegeService(CollegeRepository collegeRepository) { this.collegeRepository = collegeRepository; -// logger.info("CollegeService 실행"); } - public String getCollegeName(int collegeId) { -// logger.info("getCollegeName 실행"); - CollegeEntity collegeEntity = collegeRepository.findById(collegeId).orElse(null); -// logger.info("collegeEntity: {}", collegeEntity); - - if (collegeEntity != null) { -// logger.info("collegeEng: {}", collegeEntity.getCollegeEng()); - return collegeEntity.getCollegeEng(); // 학과 영어 이름 리턴(테이블 찾기 위함) - } else { - logger.debug("CollegeService: collge를 찾을 수 없습니다."); - return null; - } - } - - public boolean checkEtcValue(int collegeId) { - CollegeEntity collegeEntity = collegeRepository.findById(collegeId).orElse(null); - return collegeEntity.isEtcValue(); - } - - // collegeId에 해당하는 campusId 찾기 - public int getCampusId(int collegeId) { -// logger.info("getCampusId 실행"); - int campusId = collegeRepository.findCampusId(collegeId); -// logger.info("campusId: {}", campusId); - - return campusId; - } }