Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
b08e529
chore: internal 모듈에 common 모듈 가져오기
nak-honest Jul 28, 2025
1e520b8
chore: logback-spring.xml 추가
nak-honest Jul 28, 2025
6ec5cf5
feat: 요청/응답을 로깅하는 필터 추가
nak-honest Jul 28, 2025
cc5b94b
chore: 어플리케이션 네임 추가
nak-honest Jul 28, 2025
0a4f5d8
chore: dev 환경 프롬테일 컨테이너 추가
nak-honest Jul 28, 2025
8d893c4
chore: 임시로 PR이 열릴 때 CD 가 되도록 수정
nak-honest Jul 28, 2025
e02998b
chore: 임시로 mysql도 같이 띄우도록 수정
nak-honest Jul 28, 2025
6cb1096
chore: actuator 추가
nak-honest Jul 29, 2025
cc6567b
chore: prod 프로필 추가
nak-honest Jul 29, 2025
532c275
chore: prod yml 추가
nak-honest Jul 29, 2025
bcadbe9
chore: nginx.conf 수정
nak-honest Jul 29, 2025
efc8534
chore: logback prod 프로필 설정 추가
nak-honest Jul 29, 2025
f961150
chore: nginx 로그 경로 수정
nak-honest Jul 29, 2025
ff7465a
chore: 로그에 notification 서버임을 명시
nak-honest Aug 4, 2025
ee093d6
chore: 로그가 찍히지 않는 버그 수정
nak-honest Aug 4, 2025
2d275e4
chore: 줄바꿈으로 인해 로그가 찍히지 않는 문제 수정
nak-honest Aug 4, 2025
39f9415
chore: 프롬테일 정규표현식 올바르게 수정
nak-honest Aug 4, 2025
eee3518
chore: 프롬테일에서 레벨을 추출하기 위한 정규 표현식 올바르게 수정
nak-honest Aug 11, 2025
4fb9b2c
chore: 어플리케이션 이름을 가져오도록 xml 수정
nak-honest Aug 11, 2025
d400bd5
chore: CORS 웹뷰 url 추가
nak-honest Aug 11, 2025
3b27421
chore: level 을 라벨링 하기 위해 정규 표현식 수정
nak-honest Aug 11, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .github/workflows/cd-api-dev.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: CD API DEV

on:
push:
pull_request:
branches: [ develop ]
Comment on lines -4 to 5
Copy link
Contributor

Choose a reason for hiding this comment

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

머지하기 전에는 원복해야겠네요!


jobs:
Expand Down Expand Up @@ -78,10 +78,10 @@ jobs:
[ -d kokomen-notification ] || git clone --filter=blob:none --no-checkout https://github.com/samhap-soft/kokomen-notification.git
cd kokomen-notification
git sparse-checkout init --cone
git fetch origin develop
git checkout develop
git fetch origin feature/#10
git checkout feature/#10
git sparse-checkout set docker/dev
git pull origin develop
git pull origin feature/#10
Comment on lines -81 to +84
Copy link
Contributor

Choose a reason for hiding this comment

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

머지하기 전에는 원복해야겠네요!


- name: Docker Image pull
run: sudo docker pull samhap/kokomen-notification-api:dev
Expand All @@ -95,4 +95,4 @@ jobs:
run: |
export HOSTNAME=$(hostname)
cd kokomen-notification/docker/dev
sudo -E docker compose -f docker-compose-dev.yml up -d kokomen-notification-dev-api
sudo -E docker compose -f docker-compose-dev.yml up -d kokomen-notification-dev-api kokomen-notification-mysql-dev
10 changes: 5 additions & 5 deletions .github/workflows/cd-internal-dev.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: CD INTERNAL DEV

on:
push:
pull_request:
branches: [ develop ]
Comment on lines -4 to 5
Copy link
Contributor

Choose a reason for hiding this comment

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

머지하기 전에는 원복해야겠네요!


jobs:
Expand Down Expand Up @@ -78,10 +78,10 @@ jobs:
[ -d kokomen-notification ] || git clone --filter=blob:none --no-checkout https://github.com/samhap-soft/kokomen-notification.git
cd kokomen-notification
git sparse-checkout init --cone
git fetch origin develop
git checkout develop
git fetch origin feature/#10
git checkout feature/#10
git sparse-checkout set docker/dev
git pull origin develop
git pull origin feature/#10
Comment on lines 80 to +84
Copy link
Contributor

Choose a reason for hiding this comment

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

머지하기 전에는 원복해야겠네요!


- name: Docker Image pull
run: sudo docker pull samhap/kokomen-notification-internal:dev
Expand All @@ -95,4 +95,4 @@ jobs:
run: |
export HOSTNAME=$(hostname)
cd kokomen-notification/docker/dev
sudo -E docker compose -f docker-compose-dev.yml up -d kokomen-notification-dev-internal
sudo -E docker compose -f docker-compose-dev.yml up -d kokomen-notification-dev-internal kokomen-notification-mysql-dev
1 change: 1 addition & 0 deletions api/local-api-docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ services:
no_cache: true
ports:
- 8100:8080
- 8001:8001
environment:
SPRING_PROFILES_ACTIVE: local
networks:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package com.samhap.kokomen.global.logging;

import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import java.io.IOException;
import java.util.List;
import java.util.UUID;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.StopWatch;
import org.springframework.web.filter.OncePerRequestFilter;

@Slf4j
@Component
public class LoggingFilter extends OncePerRequestFilter {

private static final List<String> WHITE_LIST = List.of(
"/favicon.ico",
"/docs/index.html",
"/metrics",
"/actuator/**");

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
StopWatch stopWatch = new StopWatch();
stopWatch.start();

String requestId = readRequestId(request);
MDC.put("requestId", requestId);

try {
filterChain.doFilter(request, response);
} finally {
stopWatch.stop();
log.info("{} {} {} ({}) - {}ms",
readMemberId(request),
request.getMethod(),
request.getRequestURI(),
HttpStatus.valueOf(response.getStatus()),
stopWatch.getTotalTimeMillis());

MDC.clear();
}
}

private String readRequestId(HttpServletRequest request) {
String requestId = request.getHeader("X-RequestID");
if (requestId != null && !requestId.isEmpty()) {
return requestId;
}
return UUID.randomUUID().toString();
}

private String readMemberId(HttpServletRequest request) {
HttpSession session = request.getSession(false);
if (session != null) {
Long memberId = (Long) session.getAttribute("MEMBER_ID");
if (memberId != null) {
return "memberId=" + memberId;
}
}
return "";
}

@Override
protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
String requestURI = request.getRequestURI();
AntPathMatcher antPathMatcher = new AntPathMatcher();
return WHITE_LIST.stream().anyMatch(path -> antPathMatcher.match(path, requestURI));
}
}
22 changes: 21 additions & 1 deletion api/src/main/resources/application.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
management:
server:
address: 0.0.0.0
port: 8001
spring:
application:
name: kokomen-notification-api
profiles:
include:
- domain
Expand Down Expand Up @@ -39,10 +45,24 @@ spring:
activate:
on-profile: dev
cors:
allowed-origins: https://dev.kokomen.kr, https://kokomen.kr:3000, https://local.kokomen.kr:3000, http://local.kokomen.kr:3000
allowed-origins: https://dev.kokomen.kr, https://kokomen.kr:3000, https://local.kokomen.kr:3000, http://local.kokomen.kr:3000, https://www.webview-dev.kokomen.kr, https://webview-dev.kokomen.kr
server:
servlet:
session:
cookie:
domain: kokomen.kr
secure: false
---
# prod profile
spring:
config:
activate:
on-profile: prod
cors:
allowed-origins: https://kokomen.kr, https://www.kokomen.kr, https://www.webview.kokomen.kr, https://webview.kokomen.kr
server:
servlet:
session:
cookie:
domain: kokomen.kr
secure: true
3 changes: 3 additions & 0 deletions common/build.gradle
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
implementation 'org.springframework.boot:spring-boot-starter-actuator'

implementation 'io.micrometer:micrometer-registry-prometheus'
}

bootJar {
Expand Down
26 changes: 25 additions & 1 deletion common/src/main/resources/application-common.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,18 @@
# Common configuration for all profiles
management:
endpoint:
health:
show-components: always
access: read_only
info:
access: read_only
metrics:
access: read_only
prometheus:
access: read_only
endpoints:
web:
exposure:
include: prometheus, info, health, metrics
---
# local profile
spring:
Expand All @@ -20,3 +34,13 @@ spring:
redis:
host: kokomen-redis-dev
port: 6379
---
# prod profile
spring:
config:
activate:
on-profile: prod
data:
redis:
host: ${REDIS_PRIMARY_HOST_PROD}
port: 6379
56 changes: 56 additions & 0 deletions common/src/main/resources/logback-spring.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>

<springProperty scope="context" name="springAppName" source="spring.application.name"/>

<!-- 공통 Appender 정의 -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>
<![CDATA[[%X{requestId:-noRequest}] %d{yyyy-MM-dd HH:mm:ss.SSS} ${springAppName:-kokomen-notification} [%thread] %-5level %logger{36} - %msg%n]]>
</pattern>
</encoder>
</appender>

<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>./logs/app.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>./logs/app.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>
<![CDATA[[%X{requestId:-noRequest}] %d{yyyy-MM-dd HH:mm:ss.SSS} ${springAppName:-kokomen-notification} [%thread] %-5level %logger{36} - %msg%n]]>
</pattern>
</encoder>
</appender>

<!-- local 환경: 콘솔만 사용 -->
<springProfile name="local">
<root level="INFO">
<appender-ref ref="CONSOLE"/>
</root>
</springProfile>

<!-- dev 환경: FILE 저장 -->
<springProfile name="dev">
<root level="INFO">
<appender-ref ref="FILE"/>
</root>
</springProfile>

<!-- prod 환경: FILE 저장 -->
<springProfile name="prod">
<root level="INFO">
<appender-ref ref="FILE"/>
</root>
</springProfile>

<!-- test 환경: 콘솔만 사용 -->
<springProfile name="test">
<root level="INFO">
<appender-ref ref="CONSOLE"/>
</root>
</springProfile>
</configuration>
21 changes: 21 additions & 0 deletions docker/dev/docker-compose-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ services:
restart: on-failure:3
expose:
- 8080
- 8000
volumes:
- ./notification/internal/app/logs:/logs
environment:
Expand All @@ -24,6 +25,7 @@ services:
restart: on-failure:3
expose:
- 8080
- 8001
volumes:
- ./notification/api/app/logs:/logs
environment:
Expand Down Expand Up @@ -76,9 +78,28 @@ services:
networks:
- dev-kokomen-net

promtail-notification-dev:
image: grafana/promtail
container_name: promtail-notification-dev
volumes:
- ./promtail/promtail.yaml:/etc/promtail/promtail.yaml
- ./notification/internal/app/logs:/logs/internal
- ./notification/api/app/logs:/logs/api
- promtail-notification-tmp:/tmp
command:
- "-config.file=/etc/promtail/promtail.yaml"
- "-config.expand-env=true"
restart: unless-stopped
environment:
TZ: Asia/Seoul
HOSTNAME: ${HOSTNAME}
networks:
- dev-kokomen-net

volumes:
notification-mysql-data:
notification-mysql-init:
promtail-notification-tmp:

networks:
dev-kokomen-net:
Expand Down
34 changes: 34 additions & 0 deletions docker/dev/promtail/promtail.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
server:
http_listen_port: 9080

positions:
filename: /tmp/positions.yaml

clients:
- url: http://loki:3100/loki/api/v1/push

scrape_configs:
- job_name: kokomen-notification-api-dev
static_configs:
- labels:
job: kokomen-notification-api
app: kokomen-notification-api
host: ${HOSTNAME}
__path__: /logs/api/app.log
pipeline_stages:
- regex:
expression: '\[.*?\] [\d\-:.\s]+ [^\[\]]+ \[.*?\]\s+(?P<level>[A-Z]+)\s+[^\s]+'
- labels:
level:
- job_name: kokomen-notification-internal-dev
static_configs:
- labels:
job: kokomen-notification-internal
app: kokomen-notification-internal
host: ${HOSTNAME}
__path__: /logs/internal/app.log
pipeline_stages:
- regex:
expression: '\[.*?\] [\d\-:.\s]+ [^\[\]]+ \[.*?\]\s+(?P<level>[A-Z]+)\s+[^\s]+'
- labels:
level:
Loading
Loading