-
Notifications
You must be signed in to change notification settings - Fork 0
디버깅 로그 추가 #22
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
디버깅 로그 추가 #22
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -14,18 +14,40 @@ export class TravelDocWebSocketServer { | |||||||||||||||
| start() { | ||||||||||||||||
| this.server.on("upgrade", this.handleUpgrade.bind(this)); | ||||||||||||||||
| this.wss.on("connection", this.handleConnection.bind(this)); | ||||||||||||||||
| console.log( | ||||||||||||||||
| `[ws] upgrade handler ready maxUsersPerRoom=${this.maxUsersPerRoom}` | ||||||||||||||||
| ); | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| handleUpgrade(req, socket, head) { | ||||||||||||||||
| const requestLog = this.getRequestLogContext(req, socket); | ||||||||||||||||
| console.log( | ||||||||||||||||
| `[ws upgrade] received url=${requestLog.url} remote=${requestLog.remoteAddress} host=${requestLog.host}` | ||||||||||||||||
| ); | ||||||||||||||||
|
|
||||||||||||||||
| const authResult = this.authenticator.authenticateUpgrade(req); | ||||||||||||||||
| if (!authResult.ok) { | ||||||||||||||||
| console.warn( | ||||||||||||||||
| `[ws upgrade] auth rejected status=${authResult.statusCode} message="${authResult.message}" url=${requestLog.url} remote=${requestLog.remoteAddress}` | ||||||||||||||||
| ); | ||||||||||||||||
| this.rejectUpgrade(socket, authResult.statusCode, authResult.message); | ||||||||||||||||
| return; | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| const { travelDocId, userId } = authResult.session; | ||||||||||||||||
| console.log( | ||||||||||||||||
| `[ws upgrade] auth accepted userId=${userId} travelDocId=${travelDocId} url=${requestLog.url}` | ||||||||||||||||
| ); | ||||||||||||||||
|
|
||||||||||||||||
| const reservationResult = this.reserveRoomSlot(travelDocId, userId); | ||||||||||||||||
| console.log( | ||||||||||||||||
| `[ws upgrade] room reservation result ok=${reservationResult.ok} reserved=${reservationResult.reserved ?? false} userId=${userId} travelDocId=${travelDocId} activeUsers=${this.getRoomUserCount(travelDocId)} pendingUsers=${this.getPendingRoomUserCount(travelDocId)}` | ||||||||||||||||
| ); | ||||||||||||||||
|
|
||||||||||||||||
| if (!reservationResult.ok) { | ||||||||||||||||
| console.warn( | ||||||||||||||||
| `[ws upgrade] room rejected maxUsersPerRoom=${this.maxUsersPerRoom} userId=${userId} travelDocId=${travelDocId}` | ||||||||||||||||
| ); | ||||||||||||||||
| this.rejectUpgrade( | ||||||||||||||||
| socket, | ||||||||||||||||
| 403, | ||||||||||||||||
|
|
@@ -37,9 +59,15 @@ export class TravelDocWebSocketServer { | |||||||||||||||
| if (reservationResult.reserved) { | ||||||||||||||||
| this.releaseReservedRoomSlot(travelDocId, userId); | ||||||||||||||||
| } | ||||||||||||||||
| console.warn( | ||||||||||||||||
| `[ws upgrade] secondary token rejected as already used userId=${userId} travelDocId=${travelDocId}` | ||||||||||||||||
| ); | ||||||||||||||||
| this.rejectUpgrade(socket, 401, "Secondary token already used"); | ||||||||||||||||
| return; | ||||||||||||||||
| } | ||||||||||||||||
| console.log( | ||||||||||||||||
| `[ws upgrade] secondary token consumed userId=${userId} travelDocId=${travelDocId}` | ||||||||||||||||
| ); | ||||||||||||||||
|
|
||||||||||||||||
| let reservationSettled = false; | ||||||||||||||||
| const rollbackReservation = () => { | ||||||||||||||||
|
|
@@ -48,6 +76,9 @@ export class TravelDocWebSocketServer { | |||||||||||||||
| } | ||||||||||||||||
| reservationSettled = true; | ||||||||||||||||
| this.releaseReservedRoomSlot(travelDocId, userId); | ||||||||||||||||
| console.warn( | ||||||||||||||||
| `[ws upgrade] room reservation rolled back userId=${userId} travelDocId=${travelDocId} activeUsers=${this.getRoomUserCount(travelDocId)} pendingUsers=${this.getPendingRoomUserCount(travelDocId)}` | ||||||||||||||||
| ); | ||||||||||||||||
| }; | ||||||||||||||||
| const finalizeReservation = () => { | ||||||||||||||||
| if (reservationSettled) { | ||||||||||||||||
|
|
@@ -69,17 +100,24 @@ export class TravelDocWebSocketServer { | |||||||||||||||
| try { | ||||||||||||||||
| this.wss.handleUpgrade(req, socket, head, ws => { | ||||||||||||||||
| finalizeReservation(); | ||||||||||||||||
| console.log( | ||||||||||||||||
| `[ws upgrade] handshake accepted userId=${userId} travelDocId=${travelDocId} url=${requestLog.url}` | ||||||||||||||||
| ); | ||||||||||||||||
| this.wss.emit("connection", ws, req); | ||||||||||||||||
| }); | ||||||||||||||||
| } catch { | ||||||||||||||||
| } catch (error) { | ||||||||||||||||
| rollbackReservation(); | ||||||||||||||||
| console.error( | ||||||||||||||||
| `[ws upgrade] handshake failed userId=${userId} travelDocId=${travelDocId} error=${error?.message ?? error}` | ||||||||||||||||
| ); | ||||||||||||||||
|
Comment on lines
+110
to
+112
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 에러 로그 기록 시 error.message만 문자열에 포함하면 실제 에러의 스택 트레이스(Stack Trace) 정보를 잃게 됩니다. console.error의 두 번째 인자로 에러 객체를 직접 전달하면 더 상세한 디버깅 정보를 기록할 수 있습니다.
Suggested change
|
||||||||||||||||
| this.rejectUpgrade(socket, 500, "WebSocket handshake failed"); | ||||||||||||||||
| } | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| handleConnection(ws, req) { | ||||||||||||||||
| const session = req.session; | ||||||||||||||||
| if (!session) { | ||||||||||||||||
| console.error("[ws connection] rejected because session is missing"); | ||||||||||||||||
| ws.close(1011, "session missing"); | ||||||||||||||||
| return; | ||||||||||||||||
| } | ||||||||||||||||
|
|
@@ -90,11 +128,23 @@ export class TravelDocWebSocketServer { | |||||||||||||||
| } | ||||||||||||||||
| this.addRoomParticipant(travelDocId, userId); | ||||||||||||||||
| this.addUserSession(userId, ws); | ||||||||||||||||
| console.log( | ||||||||||||||||
| `[ws connection] connected userId=${userId} travelDocId=${travelDocId} userSessions=${this.getUserSessionCount(userId)} activeUsers=${this.getRoomUserCount(travelDocId)}` | ||||||||||||||||
| ); | ||||||||||||||||
| this.yWebSocketHandler.handleConnection(ws, req, session); | ||||||||||||||||
|
|
||||||||||||||||
| ws.on("close", () => { | ||||||||||||||||
| ws.on("close", (code, reason) => { | ||||||||||||||||
| this.removeUserSession(userId, ws); | ||||||||||||||||
| this.removeRoomParticipant(travelDocId, userId); | ||||||||||||||||
| console.log( | ||||||||||||||||
| `[ws connection] closed userId=${userId} travelDocId=${travelDocId} code=${code} reason="${reason.toString()}" userSessions=${this.getUserSessionCount(userId)} activeUsers=${this.getRoomUserCount(travelDocId)}` | ||||||||||||||||
| ); | ||||||||||||||||
| }); | ||||||||||||||||
|
|
||||||||||||||||
| ws.on("error", error => { | ||||||||||||||||
| console.error( | ||||||||||||||||
| `[ws connection] error userId=${userId} travelDocId=${travelDocId} error=${error?.message ?? error}` | ||||||||||||||||
| ); | ||||||||||||||||
|
Comment on lines
+145
to
+147
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||||||||||||||||
| }); | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
|
|
@@ -201,7 +251,43 @@ export class TravelDocWebSocketServer { | |||||||||||||||
| } | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| getRoomUserCount(travelDocId) { | ||||||||||||||||
| return this.roomParticipants.get(travelDocId)?.size ?? 0; | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| getPendingRoomUserCount(travelDocId) { | ||||||||||||||||
| return this.pendingRoomParticipants.get(travelDocId)?.size ?? 0; | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| getUserSessionCount(userId) { | ||||||||||||||||
| return this.userSessions.get(userId)?.size ?? 0; | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| getRequestLogContext(req, socket) { | ||||||||||||||||
| return { | ||||||||||||||||
| url: this.sanitizeRequestUrl(req), | ||||||||||||||||
| host: req.headers.host ?? "-", | ||||||||||||||||
| remoteAddress: | ||||||||||||||||
| req.headers["x-forwarded-for"] ?? socket.remoteAddress ?? "-" | ||||||||||||||||
| }; | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| sanitizeRequestUrl(req) { | ||||||||||||||||
| const host = req.headers.host ?? "localhost"; | ||||||||||||||||
| try { | ||||||||||||||||
| const url = new URL(req.url ?? "/", `http://${host}`); | ||||||||||||||||
| if (url.searchParams.has("secondaryToken")) { | ||||||||||||||||
| url.searchParams.set("secondaryToken", "[redacted]"); | ||||||||||||||||
| } | ||||||||||||||||
| return `${url.pathname}${url.search}`; | ||||||||||||||||
| } catch { | ||||||||||||||||
| return req.url ?? "/"; | ||||||||||||||||
| } | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| rejectUpgrade(socket, statusCode, message) { | ||||||||||||||||
| console.warn(`[ws upgrade] responding status=${statusCode} message="${message}"`); | ||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||||||||||||||||
|
|
||||||||||||||||
| let statusText = "Internal Server Error"; | ||||||||||||||||
| if (statusCode === 400) { | ||||||||||||||||
| statusText = "Bad Request"; | ||||||||||||||||
|
|
||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
운영 환경에서의 디버깅과 로그 관리를 위해 console.log 대신 winston이나 pino와 같은 구조화된 로거(Structured Logger) 사용을 권장합니다. 구조화된 로그를 사용하면 userId, travelDocId와 같은 필드를 개별 속성으로 저장할 수 있어, 나중에 로그 검색 및 분석이 훨씬 용이해집니다.