Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 2 additions & 2 deletions .github/workflows/deploy-java.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ jobs:
- name: Copy docker compose files to EC2
uses: appleboy/scp-action@v0.1.7
with:
host: ${{ secrets.SERVER_HOST }}ZZ
username: ${{ secrets.SERVER_USER }}
host: ${{ secrets.SERVER_HOST }}
username: ubuntu
key: ${{ secrets.SERVER_SSH_KEY }}
source: "docker/production/docker-compose.yml"
target: "~/app"
Expand Down
Empty file.
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import time
from typing import Dict, Any, List
from fastapi import Request
from loguru import logger
from contextvars import ContextVar

trace_id_context: ContextVar[str] = ContextVar('trace_id', default="NO_TRACE_ID")

class RepositoryLoggingDependency:
"""
레포지토리 로깅을 위한 의존성 클래스
:param repository_type: 레포지토리 유형 (예: "VECTOR_DB", "RDB", "REDIS")
:param track_params: 추적할 매개변수 이름 목록
"""

def __init__(self, repository_type: str, track_params: List[str] = None):
self.repository_type = repository_type
self.track_params = track_params or []

async def __call__(self, request: Request):
"""
의존성 주입 시 호출되는 메서드
:param request: FastAPI Request 객체
:return: 레포지토리 유형과 추출된 매개변수 딕셔너리
"""
trace_id = trace_id_context.get("NO_TRACE_ID")
start_time = time.time()

# 파라미터 추출
params = await self._extract_params(request)
param_str = ""
if params:
param_strs = [f"{k}={v}" for k, v in params.items()]
param_str = " " + " ".join(param_strs)

logger.info(f"[{self.repository_type}_START] trace_id={trace_id}{param_str}")

# 응답 시 사용할 정보를 request.state에 저장
request.state.repository_type = self.repository_type
request.state.start_time = start_time
request.state.param_str = param_str

return {"repository_type": self.repository_type, "params": params}

async def _extract_params(self, request: Request) -> Dict[str, Any]:
"""
요청에서 추적 파라미터 추출
:param request: FastAPI Request 객체
:return: 추출된 매개변수 딕셔너리
"""
params = {}

try:
# Query Parameters 추출
for key, value in request.query_params.items():
if key in self.track_params:
params[key] = value

# JSON Body 추출
try:
json_body = await request.json()
if json_body:
for key, value in json_body.items():
if key in self.track_params:
if isinstance(value, str) and len(value) > 50:
params[f"{key}_length"] = len(value)
elif isinstance(value, list):
params[f"{key}_count"] = len(value)
else:
params[key] = value
except:
pass
except:
pass

return params


# 레포지토리별 의존성 인스턴스 생성
vector_db_dependency = RepositoryLoggingDependency("VECTOR_DB", ["query", "embeddings", "top_k", "collection", "filters"])
rdb_dependency = RepositoryLoggingDependency("RDB", ["table", "where_clause", "limit", "data"])
redis_dependency = RepositoryLoggingDependency("REDIS", ["key", "value", "ttl", "pattern"])
elasticsearch_dependency = RepositoryLoggingDependency("ELASTICSEARCH", ["index", "query", "size", "document"])


# 응답 로깅을 위한 의존성
async def log_repository_response(request: Request):
"""
레포지토리 응답 시 성공 로그 기록
:param request: FastAPI Request 객체
"""
if hasattr(request.state, 'repository_type'):
trace_id = trace_id_context.get("NO_TRACE_ID")
duration = time.time() - request.state.start_time
logger.info(
f"[{request.state.repository_type}_SUCCESS] trace_id={trace_id} execution_time={duration:.4f}s{request.state.param_str}")
return None


"""
라우터 예시
@router.post("/search")
async def vector_search(
query: str,
top_k: int = 10,
request: Request = None,
_: None = Depends(vector_db_dependency), # 직접 의존성 주입
__: None = Depends(log_repository_response)
):

또는 라우터 레벨에서:
vector_router = APIRouter(
prefix="/vector",
tags=["vector"],
dependencies=[Depends(vector_db_dependency)]
)
"""
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import time
from typing import Dict, Any, List
from fastapi import Request
from loguru import logger
from contextvars import ContextVar

trace_id_context: ContextVar[str] = ContextVar('trace_id', default="NO_TRACE_ID")


class ServiceLoggingDependency:
"""
서비스 로깅을 위한 의존성 클래스
:param service_type: 서비스 유형 (예: "CHUNKING", "PARSING", "EMBEDDING")
:param track_params: 추적할 매개변수 이름 목록
"""

def __init__(self, service_type: str, track_params: List[str] = None):
self.service_type = service_type
self.track_params = track_params or []

async def __call__(self, request: Request):
"""
의존성 주입 시 호출되는 메서드
:param request: FastAPI Request 객체
:return: 서비스 유형과 추출된 매개변수 딕셔너리
"""
trace_id = trace_id_context.get("NO_TRACE_ID")
start_time = time.time()

# 파라미터 추출
params = await self._extract_params(request)
param_str = ""
if params:
param_strs = [f"{k}={v}" for k, v in params.items()]
param_str = " " + " ".join(param_strs)

logger.info(f"[{self.service_type}_START] trace_id={trace_id}{param_str}")

# 응답 시 사용할 정보를 request.state에 저장
request.state.service_type = self.service_type
request.state.start_time = start_time
request.state.param_str = param_str

return {"service_type": self.service_type, "params": params}

async def _extract_params(self, request: Request) -> Dict[str, Any]:
"""
요청에서 추적 파라미터 추출
:param request: FastAPI Request 객체
:return: 추출된 매개변수 딕셔너리
"""
params = {}

try:
# Query Parameters 추출
for key, value in request.query_params.items():
if key in self.track_params:
params[key] = value

# JSON Body 추출
try:
json_body = await request.json()
if json_body:
for key, value in json_body.items():
if key in self.track_params:
if isinstance(value, str) and len(value) > 50:
params[f"{key}_length"] = len(value)
elif isinstance(value, list):
params[f"{key}_count"] = len(value)
else:
params[key] = value
except:
pass
except:
pass

return params


# 서비스별 의존성 인스턴스 생성
chunking_dependency = ServiceLoggingDependency("CHUNKING", ["text", "chunk_size", "overlap"])
parsing_dependency = ServiceLoggingDependency("PARSING", ["file_path", "file_type", "document"])
embedding_dependency = ServiceLoggingDependency("EMBEDDING", ["chunks", "model_name", "batch_size"])

# 응답 로깅을 위한 의존성
async def log_service_response(request: Request):
"""
서비스 응답 시 성공 로그 기록
:param request: FastAPI Request 객체
"""
if hasattr(request.state, 'service_type'):
trace_id = trace_id_context.get("NO_TRACE_ID")
duration = time.time() - request.state.start_time
logger.info(
f"[{request.state.service_type}_SUCCESS] trace_id={trace_id} execution_time={duration:.4f}s{request.state.param_str}")
return None

"""
라우터 예시
@router.post("/chunk")
async def chunk_text(
text: str,
chunk_size: int = 100,
overlap: int = 20,
request: Request = None,
_: None = Depends(chunking_dependency), # 직접 의존성 주입
__: None = Depends(log_service_response)
):
"""
Empty file.
13 changes: 0 additions & 13 deletions apps/pre-processing-service/app/core/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,3 @@ class PrdSettings(BaseSettingsConfig):
class Config:
env_file = ['.env', 'prd.env']


def get_settings() -> BaseSettingsConfig:
"""환경 변수에 따라 적절한 설정 객체를 반환하는 함수"""
mode = os.getenv("MODE", "dev")
if mode == "dev":
return DevSettings()
elif mode == "prd":
return PrdSettings()
else:
raise ValueError(f"Invalid MODE environment variable: {mode}")


settings = get_settings()
Empty file.
Empty file.
Empty file.
2 changes: 1 addition & 1 deletion apps/user-service/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ COPY build/libs/*.jar app.jar

EXPOSE 8080

CMD ["java", "-jar", "app.jar"]
CMD ["java", "-jar", "app.jar"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.gltkorea.icebang.config;

import java.time.Duration;

import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

@Configuration
public class WebConfig {

@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
// 1. SimpleClientHttpRequestFactory 객체를 직접 생성
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();

// 2. 타임아웃 설정 (이 메서드들은 deprecated 아님)
requestFactory.setConnectTimeout(Duration.ofSeconds(5));
requestFactory.setReadTimeout(Duration.ofSeconds(5));

// 3. 빌더에 직접 생성한 requestFactory를 설정
return builder.requestFactory(() -> requestFactory).build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.gltkorea.icebang.filter;

import java.io.IOException;
import java.util.UUID;

import org.slf4j.MDC;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

@Component
public class LoggingFilter extends OncePerRequestFilter {

public static final String TRACE_ID_HEADER = "X-Request-ID";

@Override
protected void doFilterInternal(
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {

// 다른 시스템에서 이미 전달한 Trace ID가 있는지 확인
String traceId = request.getHeader(TRACE_ID_HEADER);

// 없다면 새로 생성 (요청의 시작점)
if (traceId == null || traceId.isEmpty()) {
traceId = UUID.randomUUID().toString();
}

MDC.put("traceId", traceId.substring(0, 8));

// ⭐️ 요청 객체에 attribute로 traceId를 저장하여 컨트롤러 등에서 사용할 수 있게 함
request.setAttribute("X-Request-ID", traceId);

// 응답 헤더에 traceId를 넣어주면 클라이언트가 추적하기 용이
response.setHeader(TRACE_ID_HEADER, traceId);

filterChain.doFilter(request, response);
}
}
4 changes: 2 additions & 2 deletions apps/user-service/src/main/resources/log4j2-develop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ Configuration:
value: "UTF-8"
# 통일된 콘솔 패턴 - 모든 로그에 RequestId 포함
- name: "console-layout-pattern"
value: "%highlight{[%-5level]} [%X{id}] %d{MM-dd HH:mm:ss} [%t] %n %msg%n%n"
value: "%highlight{[%-5level]} [%X{traceId}] %d{MM-dd HH:mm:ss} [%t] %n %msg%n%n"
# 파일용 상세 패턴 - RequestId 포함
- name: "file-layout-pattern"
value: "[%X{id}] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"
value: "[%X{traceId}] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"
# 로그 파일 경로들
- name: "info-log"
value: ${log-path}/user-service/info.log
Expand Down
3 changes: 2 additions & 1 deletion apps/user-service/src/test/resources/sql/create-schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ CREATE TABLE "USER" (
PRIMARY KEY ("user_id")
);


CREATE TABLE "GROUP_INFO" (
"group_info_id" BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
"name" VARCHAR(255) NULL,
Expand Down Expand Up @@ -95,4 +96,4 @@ CREATE TABLE "ROLE_PERMISSION" (
FOREIGN KEY ("role_id") REFERENCES "ROLE" ("role_id"),
FOREIGN KEY ("permission_id") REFERENCES "PERMISSION" ("permission_id"),
UNIQUE ("role_id", "permission_id")
);
);
1 change: 0 additions & 1 deletion docker/local/init-scripts/create-schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ DROP TABLE IF EXISTS "GROUP_INFO";
DROP TABLE IF EXISTS "USER";


-- 사용자 정보 (외부 노출 가능성 높음 -> UUID)
CREATE TABLE "USER" (
"user_id" VARCHAR(36) NOT NULL,
"name" VARCHAR(100) NULL,
Expand Down
Loading