Skip to content
Open
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/resources/deploy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,6 @@ send_slack ">>> Nginx 트래픽 전환 ($TARGET_CONTAINER)..."
echo "set \$service_url http://$TARGET_CONTAINER:8080;" > ./nginx/conf.d/service-url.inc

IS_NGINX_RUNNING=$(docker ps | grep nginx)

if [ -z "$IS_NGINX_RUNNING" ]; then
send_slack ">>> Nginx가 실행 중이지 않습니다. Nginx 시작..."
docker compose up -d nginx
Expand All @@ -133,7 +132,8 @@ if [ -n "$CURRENT_PROFILE" ]; then
send_slack ">>> 🛑 구 버전 컨테이너 중지 완료: ${STOP_DURATION}초 소요 ($STOP_MSG)"
fi

send_slack ">>> 사용하지 않는 Docker 이미지 정리(Prune)..."
send_slack ">>> 사용하지 않는 Docker 이미지 정리..."
docker images qasker/api --format "{{.Repository}}:{{.Tag}}" | grep -v ":latest" | xargs docker rmi
Copy link
Member Author

Choose a reason for hiding this comment

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

v 1.6.3등 태그가 이 아니여도 실행중 컨테이너가 가지고있는 이미지가 아니라면 지우게함

docker image prune -f

TOTAL_END_TIME=$(date +%s)
Expand Down
2 changes: 1 addition & 1 deletion .github/resources/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@ services:
environment:
- SPRING_PROFILES_ACTIVE=prod,green
ports:
- "${GREEN_PORT}:8080"
- "${GREEN_PORT}:8080"
10 changes: 6 additions & 4 deletions .github/workflows/prod_deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: Docker Hub Push & 배포 서버 EC2 배포
on:
push:
branches:
- main
- ICC-242-scouter
workflow_dispatch:

jobs:
Expand All @@ -20,7 +20,6 @@ jobs:

- name: 환경변수들 등록
run: |
echo "${{ env.NEWRELIC_YML }}" > app/newrelic/newrelic.yml
echo "${{ env.APPLICATION_PROD_YML }}" > app/src/main/resources/application-prod.yml
echo "${{ env.GRADLE_PROPERTIES }}" > app/gradle.properties

Expand All @@ -34,7 +33,7 @@ jobs:
uses: gradle/actions/setup-gradle@v4

- name: Jib로 Docker 이미지 빌드 및 푸시
run: ./gradlew jib -PPROFILE=prod --build-cache
run: ./gradlew jib --build-cache

deploy:
name: EC2 배포
Expand All @@ -46,7 +45,6 @@ jobs:
EC2_KEY: ${{ secrets.EC2_KEY }}
BLUE_PORT: 8001
GREEN_PORT: 8002
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}

steps:
- name: gradle.properties 값 환경 변수로 등록 및 마스킹
Expand All @@ -67,6 +65,10 @@ jobs:
# DOCKER_CONTAINER_NAME 생성, 등록
DOCKER_CONTAINER_NAME_VALUE="${DOCKER_ID_VALUE}-${DOCKER_IMAGE_NAME_VALUE}"
echo "DOCKER_CONTAINER_NAME=$DOCKER_CONTAINER_NAME_VALUE" >> $GITHUB_ENV

# SLACK_WEBHOOK_URL 추출, 마스킹, 환경 변수 등록
SLACK_WEBHOOK_URL_VALUE=$(echo "${{ secrets.GRADLE_PROPERTIES }}" | grep '^SLACK_WEBHOOK_URL=' | cut -d'=' -f2-)
echo "SLACK_WEBHOOK_URL=$SLACK_WEBHOOK_URL_VALUE" >> $GITHUB_ENV

- name: 코드 체크아웃
uses: actions/checkout@v4
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,5 @@ out/
.env
app/gradle.properties
app/newrelic/newrelic.yml
/heapdump
**/heapdump
monitor_downtime.sh
51 changes: 41 additions & 10 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ dependencies {
implementation project(':aws:aws-impl')
implementation project(':quiz:quiz-impl')

implementation "org.springframework.boot:spring-boot-starter-actuator"
annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
}

Expand All @@ -37,23 +36,55 @@ jib {
extraDirectories {
paths {
path {
setFrom(file("newrelic").toPath())
into = "/app/newrelic"
setFrom(file("./scouter").toPath())
into = "/app/scouter"
}
}
}
container {
def jvmHeapSize = project.property("JVM_HEAP_SIZE")

// 기본 JVM 플래그 설정
jvmFlags = ["-Xms${jvmHeapSize}", "-Xmx${jvmHeapSize}"]

def newRelicConfig = project.file("newrelic/newrelic.yml")
def newRelicJar = project.file("newrelic/newrelic.jar")
if (newRelicConfig.exists() && newRelicJar.exists()) {
jvmFlags = jvmFlags + [
"-Dnewrelic.config.file=/app/newrelic/newrelic.yml",
"-javaagent:/app/newrelic/newrelic.jar",
]
def scouterJar = project.file("./scouter/agent.java/scouter.agent.jar")

if (!scouterJar.exists()) {
throw new GradleException("Scouter agent file not found: ${scouterJar.absolutePath}")
}

// 1. 필수값 검증 (값이 없으면 여기서 빌드 실패함 🛑)
def requiredProps = ["SCOUTER_IP", "SCOUTER_PORT", "SCOUTER_OBJ_NAME"]
requiredProps.each { prop ->
if (!project.hasProperty(prop)) {
throw new GradleException("❌ [빌드 실패] ${prop} 프로퍼티가 누락되었습니다. (-P${prop}=값 필요)")
}
}

// 2. 값 할당 (검증 통과했으므로 안전하게 가져옴)
def collectorIp = project.property("SCOUTER_IP")
def objName = project.property("SCOUTER_OBJ_NAME")
def collectorPort = project.property("SCOUTER_PORT")

jvmFlags = jvmFlags + [
// [필수] 에이전트 로드
"-javaagent:/app/scouter/agent.java/scouter.agent.jar",

// [필수] Java 16+ 대응을 위한 모듈 접근 허용 옵션
"--add-opens=java.base/java.lang=ALL-UNNAMED",
"--add-opens=java.base/java.util=ALL-UNNAMED",

// [필수] conf 파일 대신 직접 설정 주입
"-Dnet_collector_ip=${collectorIp}",
"-Dnet_collector_udp_port=${collectorPort}",
"-Dnet_collector_tcp_port=${collectorPort}",

// [보안 설정: 권장] 클라이언트에서 제어 기능(HeapDump, Method Patch 등) 비활성화
"-Denable_mgr_agent=false",

// [권장] 어플리케이션 이름
"-Dobj_name=${objName}"

]
}
}
Binary file removed app/newrelic/newrelic.jar
Binary file not shown.
12 changes: 12 additions & 0 deletions app/scouter/agent.java/conf/scouter.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
### scouter java agent configuration sample
#obj_name=WAS-01
#net_collector_ip=127.0.0.1
#net_collector_udp_port=6100
#net_collector_tcp_port=6100
#hook_method_patterns=sample.mybiz.*Biz.*,sample.service.*Service.*
#trace_http_client_ip_header_key=X-Forwarded-For
#profile_spring_controller_method_parameter_enabled=false
#hook_exception_class_patterns=my.exception.TypedException
#profile_fullstack_hooked_exception_enabled=true
#hook_exception_handler_method_patterns=my.AbstractAPIController.fallbackHandler,my.ApiExceptionLoggingFilter.handleNotFoundErrorResponse
#hook_exception_hanlder_exclude_class_patterns=exception.BizException
1 change: 1 addition & 0 deletions app/scouter/agent.java/conf/testcase-scouter.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
objName=test-case-scouter
9 changes: 9 additions & 0 deletions app/scouter/agent.java/plugin/capture.plug
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[args]
// void capArgs(WrContext $ctx, HookArgs $hook)

[return]
// void capReturn(WrContext $ctx, HookReturn $hook)


[this]
// void capThis(WrContext $ctx, String $class, String $desc, Object $this)
2 changes: 2 additions & 0 deletions app/scouter/agent.java/plugin/counter.plug
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[counter]
//public void counter(scouter.lang.pack.PerfCounterPack $pack)
2 changes: 2 additions & 0 deletions app/scouter/agent.java/plugin/httpcall.plug
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[call]
// void call(WrContext $ctx, WrHttpCallRequest $req)
12 changes: 12 additions & 0 deletions app/scouter/agent.java/plugin/httpservice.plug
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[start]
// void start(WrContext $ctx, WrRequest $req, WrResponse $res)



[end]
// void end(WrContext $ctx, WrRequest $req, WrResponse $res)


[reject]
// boolean reject(WrContext $ctx, WrRequest $req, WrResponse $res)
return false;
4 changes: 4 additions & 0 deletions app/scouter/agent.java/plugin/jdbcpool.plug
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[url]
// String url(WrContext $ctx, String $msg, Object $pool)

return null;
138 changes: 138 additions & 0 deletions app/scouter/agent.java/plugin/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
## Javaagent Plugin
- Default File Location : ${directory of scouter.agent.jar}/plugin
- Dynamic application
- By java code
- Plugin 종류
- Http-service
- Service
- HttpCall
- Capture
- JDBC-Pool

### Http-service Plugin(httpservice.plug)

1. void start(WrContext $ctx, WrRequest $req, WrResponse $res) : Http Service 시작 시점
2. void end(WrContext $ctx, WrRequest $req, WrResponse $res) : Http Service 종료 시점
3. boolean reject(WrContext $ctx, WrRequest $req, WrResponse $res) : Http Service 시작 시점에 reject 조건 (default : false)

### Service Plugin(service.plug)
**추가적인 hooking 설정을 통해서만 동작**

1. void start(WrContext $ctx, HookArgs $hook) : Service 시작 시점
2. void end(WrContext $ctx) : Service 종료 시점

### HttpCall Plugin(httpcall.plug)

1. void call(WrContext $ctx, WrHttpCallRequest $req) : Http Call 요청 시점

### Capture Plugin(capture.plug)
**추가적인 hooking 설정을 통해서만 동작**

1. void capArgs(WrContext $ctx, HookArgs $hook) : Method 시작 시점
2. void capReturn(WrContext $ctx, HookReturn $hook) : Method Return 시점
3. void capThis(WrContext $ctx, String $class, String $desc, Object $this) : Constructor 생성 시점
Comment on lines +1 to +33
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Address markdownlint MD007/MD036 in lists and headings.
There are multiple top-level lists indented by one space and emphasized lines used as headings (Lines 19, 29). Please normalize list indentation and convert those emphasized lines into actual headings. As per static analysis, this is causing MD007/MD036 warnings.

Also applies to: 43-136

🧰 Tools
🪛 markdownlint-cli2 (0.18.1)

2-2: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


3-3: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


4-4: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


5-5: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


6-6: Unordered list indentation
Expected: 2; Actual: 3

(MD007, ul-indent)


7-7: Unordered list indentation
Expected: 2; Actual: 3

(MD007, ul-indent)


8-8: Unordered list indentation
Expected: 2; Actual: 3

(MD007, ul-indent)


9-9: Unordered list indentation
Expected: 2; Actual: 3

(MD007, ul-indent)


10-10: Unordered list indentation
Expected: 2; Actual: 3

(MD007, ul-indent)


19-19: Emphasis used instead of a heading

(MD036, no-emphasis-as-heading)


29-29: Emphasis used instead of a heading

(MD036, no-emphasis-as-heading)

🤖 Prompt for AI Agents
In `@app/scouter/agent.java/plugin/readme.md` around lines 1 - 33, Normalize list
indentation by removing leading single-space indents so all top-level lists
start at column 0 and use consistent list markers; replace emphasized lines like
"**추가적인 hooking 설정을 통해서만 동작**" with proper Markdown headings (e.g., "### 추가적인
hooking 설정을 통해서만 동작") where they act as section headings; apply these changes
for the Service and Capture sections (the repeated emphasized lines) and
similarly fix list indentation and emphasized-heading occurrences throughout the
remainder of the file (lines referenced around 43-136) to resolve MD007/MD036.


### JDBC-Pool Plugin(jdbcpool.plug)

1. String url(WrContext $ctx, String $msg, Object $pool)
: DB Connection URL 요청 시점


## API

### Common API
- void log(Object c) : Logger를 통한 log
- void println(Object c) : System.out를 통한 log
- Object field(Object o, String field) : Object의 filed 값을 가져옴
- Object method(Object o, String method) : Object의 method를 강제invoke 함
- Object method1(Object o, String method) : Object의 method를 invoke 함
- Object method(Object o, String method, String param) : Object의 method를 String 파라미터와 함께 invoke 함
- String toString(Object o) : Object 를 toString 하여 반환
- String toString(Object o, String def) : Object 를 toString 하여 반환, null 이면 default string 반환
- void alert(char level, String title, String message) : Alert 을 보냄
- int syshash(Object o) : Object 의 identityHash 값 반환
- int syshash(HookArgs hook, int x) : Arguments의 i 인덱스의 identyHash 값 반환
- int syshash(HookArgs hook) : This 의 identyHash 값 반환
- void forward(WrContext wctx, int uuid) : Async Thread 를 App service로 연결
- void forwardThread(WrContext wctx, int uuid) : Async Thread 를 Background service로 연결
- void receive(WrContext ctx, int uuid) : 앞서 등록된 Service가 있으면 연결


### WrContext class API
- String service() : Service Name 을 반환
- void service(String name) : Service Name 을 set
- int serviceHash() : Service Hash 값을 반환
- void remoteIp(String ip) : Remote IP 을 set
- String remoteIp() : Remote IP를 반환
- void error(String err) : 임의의 error 를 주입
- boolean isError() : 에러 체크
- void group(String group) : 임의의 group을 set
- String group() : Group을 반환
- void login(String id) : 임의의 사용자 ID 를 set
- String login() : 사용자 ID를 반환
- void desc(String desc) : 임의의 Desc를 set
- String desc() : Desc를 반환
- String httpMethod() : Http Method를 반환
- String httpQuery() : Http Query를 반환
- String httpContentType() : Http Content-type을 반환
- String userAgent() : User-Agent를 반환
- void profile(String msg) : Msg 를 profile에 기록
- long txid() : txid 를 반환
- long gxid() : gxid 를 반환
- TraceContext inner() : context를 반환

### WrRequest class API
- String getCookie(String key) : Cookie 값을 반환
- String getRequestURI() : Request URI를 반환
- String getRemoteAddr() : Remote Address를 반환
- String getMethod() : Method 를 반환
- String getQueryString() : Query String을 반환
- String getParameter(String key) : Parameter를 반환
- Object getAttribute(String key) : Attribute를 반환
- String getHeader(String key) : Header값을 반환
- Enumeration getParameterNames() : Parameter 값들을 반환
- Enumeration getHeaderNames() : HeaderName들을 반환
- WrSession getSession() : WrSession객체를 반환
- Set getSessionNames() : Session Name들을 반환
- Object getSessionAttribute(String key) : Session 값을 반환
- Object inner() : Request Object를 반환
- boolean isOk() : Plugin 상태 확인
- Throwable error() : Error 확인

### WrResponse class API
- PrintWriter getWriter() : Writer를 반환
- String getContentType() : Content-type을 반환
- String getCharacterEncoding() : Character-encoding을 반환
- Object inner() : Response Object를 반환
- boolean isOk() : Plugin 상태 확인
- Throwable error() : Error 확인

### WrSession class API
- getAttribute(String key) : Attribute를 반환
- Enumeration getAttributeNames() : Attribute Names를 반환
- Object inner() : Session Object를 반환
- boolean isOk() : Plugin 상태 확인
- Throwable error() : Error 확인

### WrHttpCallRequest class API
- void header(Object key, Object value) : Header값 추가
- Object inner() : Request Object를 반환
- boolean isOk() : Plugin 상태 확인
- Throwable error() : Error 확인

### HookArgs class API
- String getClassName() : Class 이름 반환
- String getMethodName() : Method 이름 반환
- String getMethodDesc() : Method 의 Desc 반환
- Object getThis() : this object 반환
- Object[] getArgs() : Arguments 반환
- int getArgCount() : Argument 갯수 반환

### HookReturn class API
- String getClassName() : Class 이름 반환
- String getMethodName() : Method 이름 반환
- String getMethodDesc() : Method 의 Desc 반환
- Object getThis() : this object 반환
- Object getReturn() : Return 값 반환


Loading