콘텐츠로 이동

Debugging Improvements Plan

  1. 현재 구조의 문제점 분석
  2. 개선 방안 기획
  3. Cloudflare Logpush 통합
  4. 구현 우선순위

1. GitHub Actions Workflow 구조적 문제

섹션 제목: “1. GitHub Actions Workflow 구조적 문제”

❌ 문제점 1: 인라인 스크립트 과다

섹션 제목: “❌ 문제점 1: 인라인 스크립트 과다”
  • 현재 상태: deploy.yml이 750줄로 매우 길고, 대부분의 로직이 인라인 run: 블록에 직접 작성됨
  • 영향:
    • 로컬에서 재현 불가능
    • 디버깅 시 CI 환경에만 의존
    • 코드 재사용 불가
  • 예시: D1/KV provisioning 로직이 200줄 이상의 인라인 bash 코드

❌ 문제점 2: Shell First 전략 미적용

섹션 제목: “❌ 문제점 2: Shell First 전략 미적용”
  • 현재 상태: ci.shsteps/deploy.sh가 존재하지만, deploy.yml에서 직접 사용하지 않음
  • 영향:
    • CI와 로컬 환경이 분리됨
    • 동일한 로직을 두 곳에서 유지보수해야 함
    • 로컬 재현 불가능
  • 현재 상태:
    • ACTIONS_STEP_DEBUG 설정 없음
    • Bash strict mode (set -euxo pipefail) 일관성 없음
    • tmate SSH 세션 없음
    • 로그 그룹핑 없음
  • 영향:
    • 실패 원인 파악이 매우 어려움
    • 환경 변수, 파일 상태 확인 불가
    • 실패한 VM에 접근 불가
  • 현재 상태:
    • wrangler deploy --dry-run 없음
    • Bundle 출력 저장 없음
    • Preview 환경 배포 없음
  • 영향:
    • Cloudflare에 잘못된 코드 배포 가능
    • 배포된 코드 추적 불가
    • 롤백 시점 파악 어려움

❌ 문제점 5: 버전/빌드 정보 없음

섹션 제목: “❌ 문제점 5: 버전/빌드 정보 없음”
  • 현재 상태: Worker 코드에 배포 버전, Git commit hash, 빌드 타임스탬프가 없음
  • 영향:
    • 어떤 코드가 실행 중인지 추적 불가
    • 문제 발생 시 원인 코드 버전 파악 불가
    • 배포 이력과 로그 연결 불가

❌ 문제점 6: 구조화된 로깅 부재

섹션 제목: “❌ 문제점 6: 구조화된 로깅 부재”
  • 현재 상태: console.log만 사용, 구조화된 로그 포맷 없음
  • 영향:
    • HTTP 요청 추적 어려움
    • 에러 컨텍스트 부족
    • 로그 분석 자동화 불가

❌ 문제점 7: Cloudflare Logpush 미설정

섹션 제목: “❌ 문제점 7: Cloudflare Logpush 미설정”
  • 현재 상태: Logpush 설정 없음, 로그가 Cloudflare Dashboard에만 존재
  • 영향:
    • 장기 보관 불가
    • 외부 분석 도구 연동 불가
    • 법적 추적 증거 확보 불가
  • 현재 상태: staging → production 직접 배포
  • 영향:
    • Production 배포 전 최종 검증 불가
    • 자동화된 테스트 없음
    • 승인 프로세스 없음

CI에서 실행하는 모든 로직을 로컬에서도 100% 재현 가능하게 만들기

1.1 GitHub Actions Workflow 단순화

# .github/workflows/deploy.yml (개선 후)
jobs:
deploy:
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Environment
run: .github/scripts/setup.sh
- name: Run CI Pipeline
run: .github/scripts/ci.sh
env:
CI_MODE: deploy
DEPLOY_ENV: ${{ steps.env.outputs.environment }}

1.2 통합 CI 스크립트 구조

.github/scripts/
├── ci.sh # 메인 진입점 (기존)
├── setup.sh # 환경 설정 (신규)
├── steps/
│ ├── research.sh # 기존
│ ├── seed.sh # 기존
│ └── deploy.sh # 개선 필요
└── lib/
├── debug.sh # 디버깅 유틸리티 (신규)
├── validation.sh # 검증 유틸리티 (신규)
└── logging.sh # 로깅 유틸리티 (신규)

1.3 로컬 실행 가능성 보장

Terminal window
# 로컬에서 CI와 동일하게 실행
./.github/scripts/ci.sh
# 특정 단계만 실행
CI_MODE=deploy DEPLOY_ENV=staging ./.github/scripts/ci.sh

실패 시 10배 빠르게 원인 파악

2.1 GitHub Actions 디버그 모드 활성화

.github/workflows/deploy.yml
env:
ACTIONS_STEP_DEBUG: true
ACTIONS_RUNNER_DEBUG: true

2.2 Bash Strict Mode 적용

.github/scripts/lib/debug.sh
set -euxo pipefail
# 모든 스크립트 상단에 포함
source "$(dirname "$0")/lib/debug.sh"

2.3 tmate SSH 세션 추가

.github/workflows/deploy.yml
- name: Setup tmate session (on failure)
if: failure()
uses: mxschmitt/action-tmate@v3
with:
limit-access-to-this-repository: true

2.4 로그 그룹핑 및 환경 정보 출력

.github/scripts/lib/logging.sh
log_group() {
echo "::group::$1"
shift
"$@"
echo "::endgroup::"
}
log_env() {
log_group "Environment Variables" env | sort
}
log_files() {
log_group "File Structure" find . -type f -name "*.sh" -o -name "*.json" | head -20
}

Cloudflare에 배포하기 전에 100% 검증

3.1 Wrangler Dry-Run 검증

.github/scripts/steps/deploy.sh
echo "🔍 Running wrangler dry-run..."
wrangler deploy --dry-run --env "$DEPLOY_ENV" > bundle-info.txt 2>&1
# Bundle 정보를 Artifact로 저장
echo "📦 Saving bundle information..."
# GitHub Actions에서 artifact 업로드

3.2 Preview 환경 배포

.github/workflows/deploy.yml
- name: Deploy to Preview
run: |
wrangler deploy --env preview --minify
# Preview URL로 자동 테스트 실행
- name: Approve Production Deployment
if: github.event.inputs.environment == 'production'
# Manual approval 또는 자동 테스트 통과 후

3.3 Bundle 정보 저장

.github/scripts/steps/deploy.sh
BUNDLE_HASH=$(wrangler deploy --dry-run 2>&1 | grep -oE 'hash: [a-f0-9]+' | cut -d' ' -f2)
echo "bundle_hash=$BUNDLE_HASH" >> $GITHUB_OUTPUT

배포된 코드와 실행 로그를 완전히 추적 가능하게

4.1 빌드 정보 주입

// src/lib/build-info.ts (신규)
/**
* Build information injected at build time
* This file is generated by the build process
*/
export const BUILD_INFO = {
version: process.env.BUILD_VERSION || "unknown",
commit: process.env.GIT_COMMIT || "unknown",
timestamp: process.env.BUILD_TIMESTAMP || new Date().toISOString(),
environment: process.env.CF_ENV || "unknown",
};
// src/index.ts
import { BUILD_INFO } from "./lib/build-info";
export default {
fetch(req, env, ctx) {
// 모든 요청에 빌드 정보 로깅
console.log("deploy", {
version: BUILD_INFO.version,
commit: BUILD_INFO.commit,
timestamp: BUILD_INFO.timestamp,
environment: BUILD_INFO.environment,
});
// HTTP 요청 정보 로깅
const url = new URL(req.url);
console.log("http", {
method: req.method,
path: url.pathname,
userAgent: req.headers.get("user-agent"),
ip: req.headers.get("cf-connecting-ip"),
country: req.cf?.country,
requestId: crypto.randomUUID(),
});
// ... 기존 로직
}
};

4.2 빌드 시 정보 주입

.github/scripts/steps/deploy.sh
export BUILD_VERSION="$(date -u +%Y-%m-%dT%H%M%SZ)"
export GIT_COMMIT="${{ github.sha }}"
export BUILD_TIMESTAMP="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
# wrangler deploy 시 환경 변수 전달
wrangler deploy --env "$DEPLOY_ENV" \
--var BUILD_VERSION="$BUILD_VERSION" \
--var GIT_COMMIT="$GIT_COMMIT" \
--var BUILD_TIMESTAMP="$BUILD_TIMESTAMP"

4.3 구조화된 로깅

// src/lib/logger.ts (신규)
interface LogContext {
requestId?: string;
userId?: string;
action?: string;
[key: string]: unknown;
}
export function log(level: "info" | "warn" | "error", message: string, context?: LogContext) {
console.log(JSON.stringify({
level,
message,
timestamp: new Date().toISOString(),
...context,
}));
}

모든 Worker 로그를 외부 저장소로 자동 푸시하여 장기 보관 및 분석

5.1 Logpush 설정 (수동)

Terminal window
# Cloudflare Dashboard 또는 API를 통해 설정
# Workers Logpush는 현재 Beta 기능이므로 API 사용 필요
# R2 Bucket에 로그 저장 설정
curl -X POST "https://api.cloudflare.com/client/v4/accounts/{account_id}/logpush/jobs" \
-H "Authorization: Bearer {api_token}" \
-H "Content-Type: application/json" \
-d '{
"name": "workers-logs",
"destination_conf": "r2://newsfork-logs/{DATE}?account-id={account_id}&access-key-id={access_key_id}&secret-access-key={secret_access_key}",
"dataset": "workers_trace_events",
"logpull_options": "fields=EventTimestampMs,Outcome,Exceptions,Logs,ScriptName"
}'

5.2 Worker 코드에서 구조화된 로그 출력

src/index.ts
export default {
fetch(req, env, ctx) {
const requestId = crypto.randomUUID();
const startTime = Date.now();
// 요청 시작 로그
console.log(JSON.stringify({
type: "request_start",
requestId,
method: req.method,
url: req.url,
timestamp: new Date().toISOString(),
build: BUILD_INFO,
}));
return ctx.waitUntil(
(async () => {
try {
const response = await app.fetch(req, env, ctx);
// 요청 완료 로그
console.log(JSON.stringify({
type: "request_end",
requestId,
status: response.status,
duration: Date.now() - startTime,
timestamp: new Date().toISOString(),
}));
return response;
} catch (error) {
// 에러 로그
console.error(JSON.stringify({
type: "request_error",
requestId,
error: error.message,
stack: error.stack,
timestamp: new Date().toISOString(),
}));
throw error;
}
})()
);
}
};

5.3 Logpush 설정 자동화

  • 기획 및 정책: docs/LOGPUSH_INTEGRATION_PLAN.md
  • 구현: provision 단계에서 staging/production일 때 provision-logpush.sh가 R2 버킷(newsfork-logs-{env}) 생성 및 Logpush Job(workers_trace_events → R2) 생성. verify 단계에서 해당 Job 존재·enabled 검사.
  • 스크립트: .github/scripts/steps/provision-logpush.sh, .github/scripts/lib/logpush-api.sh

  1. GitHub Actions 디버그 모드 활성화

    • ACTIONS_STEP_DEBUG: true 추가
    • 예상 시간: 5분
  2. Bash Strict Mode 적용

    • 모든 스크립트에 set -euxo pipefail 추가
    • 예상 시간: 30분
  3. 로그 그룹핑 추가

    • 환경 변수, 파일 구조 출력
    • 예상 시간: 1시간
  4. Worker 빌드 정보 주입

    • BUILD_INFO 생성 및 로깅
    • 예상 시간: 2시간
  1. Shell First 전략 완전 적용

    • deploy.yml 단순화
    • 모든 로직을 .github/scripts/로 이동
    • 예상 시간: 4시간
  2. Wrangler Dry-Run 검증

    • 배포 전 bundle 검증
    • 예상 시간: 2시간
  3. tmate SSH 세션 추가

    • 실패 시 SSH 접속 가능
    • 예상 시간: 30분
  1. Preview 환경 구축

    • Preview 배포 → 테스트 → Production 승인
    • 예상 시간: 4시간
  2. Cloudflare Logpush 설정

    • R2 또는 외부 저장소 연동
    • 예상 시간: 2시간 (수동 설정)
  3. 구조화된 로깅 시스템

    • JSON 로그 포맷
    • 로그 분석 도구 연동
    • 예상 시간: 4시간

  • 현재: 실패 원인 파악에 평균 2-4시간
  • 개선 후: 평균 15-30분 (80% 단축)
  • 현재: Production 배포 실패율 ~10%
  • 개선 후: ~2% (Dry-run 검증으로 사전 차단)
  • 현재: Cloudflare Dashboard만 (7일 보관)
  • 개선 후: R2 장기 보관 + 외부 분석 도구 연동