/admin/logs API와 logback 파일 어펜더 추가 - #157
Conversation
|
Warning Review limit reached
More reviews will be available in 48 minutes and 34 seconds. Learn how PR review limits work. Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file). ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits. 🚦 How do rate limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, the refill rate gradually slows as usage increases. The highest same-day bursts are limited more strictly. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
WalkthroughLogback ChangesAdmin Log Tail API
Sequence Diagram(s)sequenceDiagram
participant Admin as 관리자 브라우저
participant Controller as AdminLogController
participant Service as LogTailService
participant OS as ProcessBuilder
Admin->>Controller: GET /admin/logs/files
Controller->>Service: listFiles()
Service-->>Controller: List<LogFileResponse> (최신순)
Controller-->>Admin: ApiResponse<List<LogFileResponse>>
Admin->>Controller: GET /admin/logs/tail?file=obrit.log&lines=200
Controller->>Service: tail("obrit.log", 200)
Service->>Service: 화이트리스트·canonical path 검증
Service->>OS: tail -n 200 logs/obrit.log
OS-->>Service: stdout
Service-->>Controller: 마지막 200줄 문자열
Controller-->>Admin: text/plain 응답
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@src/main/kotlin/depromeet/hotsix/obrit/admin/controller/AdminLogController.kt`:
- Line 16: The `@Tag` annotation on the AdminLogController class has English text
for both name and description fields, which violates the documentation language
guidelines requiring all Controller documentation to be written in Korean.
Update the name parameter (currently "Admin Logs") and the description parameter
in the `@Tag` annotation to use Korean text instead of English to maintain
consistency with the coding guidelines.
In `@src/main/kotlin/depromeet/hotsix/obrit/admin/service/LogTailService.kt`:
- Around line 64-67: In the LogTailService.kt file, refactor the command
building logic for gzip files (.gz) to avoid using bash -c with string
interpolation. Instead of concatenating target.toAbsolutePath() and lines into a
shell command string, use ProcessBuilder with explicit argument passing that
bypasses shell interpretation. This prevents potential issues with spaces in
file paths and shell expansion vulnerabilities while maintaining the same gunzip
and tail functionality.
- Around line 75-83: The LogTailService.kt code calls process.waitFor before
consuming the process's stdout, which can cause the output pipe to fill up and
block the child process from exiting, resulting in false timeout exceptions.
Refactor the code to consume the process output asynchronously (using a separate
thread or executor) while waiting for the process to complete. Ensure that the
output is read in parallel with waitFor so that the pipe never fills up and
blocks the process, eliminating the risk of premature timeout failures.
In
`@src/main/kotlin/depromeet/hotsix/obrit/global/exception/GlobalExceptionHandler.kt`:
- Line 86: The LogTailTimeoutException class is declared twice in the file,
causing a Kotlin redeclaration compilation error. Locate all occurrences of the
LogTailTimeoutException class declaration in GlobalExceptionHandler.kt and
remove the duplicate declaration, keeping only one instance of the class
definition.
In `@src/test/kotlin/depromeet/hotsix/obrit/admin/service/LogTailServiceTest.kt`:
- Around line 88-92: The Thread.sleep(10) call in the test function listFiles is
unreliable because filesystem lastModified time resolution may not capture such
small delays, causing intermittent test failures. Replace the Thread.sleep(10)
approach with explicit time setting using Files.setLastModifiedTime to
deterministically set different modification times for each file (writeLog calls
for "obrit.log", "obrit.2026-06-18.0.log.gz", and "ignore.txt"). This ensures
consistent lastModified ordering verification regardless of the system's time
resolution.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 1ba93ea7-a210-4588-a235-68d96ee48a05
📒 Files selected for processing (8)
.gitignoresrc/main/kotlin/depromeet/hotsix/obrit/admin/controller/AdminLogController.ktsrc/main/kotlin/depromeet/hotsix/obrit/admin/dto/LogFileResponse.ktsrc/main/kotlin/depromeet/hotsix/obrit/admin/service/LogTailService.ktsrc/main/kotlin/depromeet/hotsix/obrit/global/config/OpenApiConfig.ktsrc/main/kotlin/depromeet/hotsix/obrit/global/exception/GlobalExceptionHandler.ktsrc/main/resources/logback-spring.xmlsrc/test/kotlin/depromeet/hotsix/obrit/admin/service/LogTailServiceTest.kt
| fun `listFiles - 화이트리스트 매칭 파일만 lastModified 내림차순으로 반환`() { | ||
| writeLog("obrit.log", "active\n") | ||
| Thread.sleep(10) | ||
| writeLog("obrit.2026-06-18.0.log.gz", "old\n") | ||
| writeLog("ignore.txt", "no") |
There was a problem hiding this comment.
Thread.sleep 기반 정렬 검증은 CI에서 플래키할 수 있습니다.
Line 90의 Thread.sleep(10)은 파일시스템의 lastModified 해상도에 따라 순서가 같게 기록될 수 있어 테스트가 간헐 실패할 수 있습니다. Files.setLastModifiedTime으로 시간을 명시 설정해 결정적으로 검증하는 편이 안전합니다.
수정 예시
import java.io.ByteArrayOutputStream
import java.nio.file.Files
import java.nio.file.Path
+import java.nio.file.attribute.FileTime
+import java.time.Instant
import java.util.zip.GZIPOutputStream
import kotlin.test.assertEquals
import kotlin.test.assertTrue
@@
fun `listFiles - 화이트리스트 매칭 파일만 lastModified 내림차순으로 반환`() {
- writeLog("obrit.log", "active\n")
- Thread.sleep(10)
- writeLog("obrit.2026-06-18.0.log.gz", "old\n")
+ val active = tempDir.resolve("obrit.log")
+ val rolled = tempDir.resolve("obrit.2026-06-18.0.log.gz")
+ writeLog("obrit.log", "active\n")
+ writeLog("obrit.2026-06-18.0.log.gz", "old\n")
writeLog("ignore.txt", "no")
+
+ Files.setLastModifiedTime(active, FileTime.from(Instant.parse("2026-06-19T00:00:10Z")))
+ Files.setLastModifiedTime(rolled, FileTime.from(Instant.parse("2026-06-19T00:00:00Z")))
val result = service().listFiles()🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/test/kotlin/depromeet/hotsix/obrit/admin/service/LogTailServiceTest.kt`
around lines 88 - 92, The Thread.sleep(10) call in the test function listFiles
is unreliable because filesystem lastModified time resolution may not capture
such small delays, causing intermittent test failures. Replace the
Thread.sleep(10) approach with explicit time setting using
Files.setLastModifiedTime to deterministically set different modification times
for each file (writeLog calls for "obrit.log", "obrit.2026-06-18.0.log.gz", and
"ignore.txt"). This ensures consistent lastModified ordering verification
regardless of the system's time resolution.
Closes #136
Summary
EC2 콘솔/SSH 없이도 브라우저나 curl로 운영 로그를 확인할 수 있도록
admin 로그 조회 API 2개를 추가했습니다. 같이 동작할 logback 파일 어펜더도 함께 도입했습니다!
GET /admin/logs/files—logs/폴더의 로그 파일 목록GET /admin/logs/tail?file=&lines=— 현재 서버 로그의 마지막 N줄Changes
1. logback 파일 어펜더
logs/obrit.log)에 동시에 기록2. 로그 조회 API 구현
tail/gunzip -c | tail로 마지막 N줄만 추출 (큰 파일도 가볍게)lines범위: 1~1000 (기본 200)3. 에러 핸들러 보강
이번에 새로 필요해진 404/504/400 케이스를 잡기 위해 핸들러 추가.
Etc
적용 화면
논의할 부분
Q1. 더 추가하면 좋을 게 있을지?? ex) error 로그의 경우 알림 등
Q2. 지금 설계 괜찮은지!
Summary by CodeRabbit
릴리스 노트
New Features
Chores