@@ -10,6 +10,36 @@ import (
1010 "ticketmate-logviewer/internal/dockercli"
1111)
1212
13+ type flushWriter struct {
14+ writer http.ResponseWriter
15+ flusher http.Flusher
16+ }
17+
18+ // ResponseWriter 가 http.Flusher를 지원하는지 확인하고 감싸주는 함수
19+ func newFlushWriter (writer http.ResponseWriter ) (* flushWriter , error ) {
20+ flusher , ok := writer .(http.Flusher )
21+ if ! ok {
22+ return nil , fmt .Errorf ("http.ResponseWriter가 스트리밍을 지원하지 않습니다" )
23+ }
24+
25+ return & flushWriter {
26+ writer : writer ,
27+ flusher : flusher ,
28+ }, nil
29+ }
30+
31+ // io.Writer 인터페이스 구현
32+ func (flushWriterInstance * flushWriter ) Write (p []byte ) (int , error ) {
33+ written , err := flushWriterInstance .writer .Write (p )
34+ if err != nil {
35+ return written , err
36+ }
37+
38+ // 매번 쓰고 나서 즉시 클라이언트로 flush
39+ flushWriterInstance .flusher .Flush ()
40+ return written , nil
41+ }
42+
1343func containersHandler (writer http.ResponseWriter , request * http.Request ) {
1444 if request .Method != http .MethodGet {
1545 http .Error (writer , "허용되지 않은 HTTP 메서드 압니다" , http .StatusMethodNotAllowed )
@@ -62,6 +92,34 @@ func containerLogsHandler(writer http.ResponseWriter, request *http.Request) {
6292 return
6393 }
6494
95+ // follow 파라미터 처리: follow = true 또는 follow = 1이면 실시간 스트리밍
96+ followParam := request .URL .Query ().Get ("follow" )
97+ follow := strings .EqualFold (followParam , "true" ) || followParam == "1"
98+
99+ // 로그는 text/plain 스트리밍 또는 전체 응답
100+ writer .Header ().Set ("Content-Type" , "text/plain; charset=utf-8" )
101+
102+ if follow {
103+ // 실시간 스트리밍 모드
104+ streamWriter , newWriterErr := newFlushWriter (writer )
105+ if newWriterErr != nil {
106+ log .Printf ("HTTP 스트리밍을 지원하지 않는 환경입니다: %v" , newWriterErr )
107+ http .Error (writer , "스트리밍을 지원하지 않는 환경입니다" , http .StatusInternalServerError )
108+ return
109+ }
110+
111+ log .Printf ("컨테이너 로그 스트리밍 시작 (follow 모드). 컨테이너 ID: %s" , containerID )
112+
113+ // request.Context() 를 넘겨서 클라이언트가 연결을 끊으면 doker 프로세스도 종료
114+ streamErr := dockercli .StreamContainerLogs (request .Context (), containerID , tailLines , streamWriter )
115+ if streamErr != nil {
116+ // 스트리밍 중 에러는 서버 로그로만 출력. 응답 바디에는 보내지 않음
117+ log .Printf ("컨테이너 로그 스트리밍 실패. 컨테이너 ID: %s: %v" , containerID , streamErr )
118+ }
119+ log .Printf ("컨테이너 로그 스트리밍 종료. 컨테이너 ID: %s" , containerID )
120+ return
121+ }
122+
65123 logText , err := dockercli .FetchContainerLogs (containerID , tailLines )
66124 if err != nil {
67125 log .Printf ("컨테이너 로그 조회에 실패했습니다. 컨테이너 ID: %s: %v" , containerID , err )
0 commit comments