diff --git a/src/main/java/me/thinkcat/opic/practice/controller/DrillAnswerController.java b/src/main/java/me/thinkcat/opic/practice/controller/DrillAnswerController.java index 5da595f..d0d1f73 100644 --- a/src/main/java/me/thinkcat/opic/practice/controller/DrillAnswerController.java +++ b/src/main/java/me/thinkcat/opic/practice/controller/DrillAnswerController.java @@ -144,7 +144,7 @@ public ResponseEntity> updateDrillFeedbackStatus( } @PatchMapping("/internal/transcription") - public ResponseEntity> g( + public ResponseEntity> updateDrillTranscription( @Valid @RequestBody UpdateDrillTranscriptionRequest request) { drillAnswerService.updateTranscription( diff --git a/src/main/java/me/thinkcat/opic/practice/scheduler/AnswerCleanupScheduler.java b/src/main/java/me/thinkcat/opic/practice/scheduler/AnswerCleanupScheduler.java index 837ef19..26b8d1a 100644 --- a/src/main/java/me/thinkcat/opic/practice/scheduler/AnswerCleanupScheduler.java +++ b/src/main/java/me/thinkcat/opic/practice/scheduler/AnswerCleanupScheduler.java @@ -37,7 +37,7 @@ public class AnswerCleanupScheduler { // @Scheduled(cron = "0 0 3 * * *") @Transactional public void cleanupOrphanedAnswers() { - log.info("Starting orphaned answers cleanup task..."); + log.info("event=scheduler_answer_cleanup_start"); LocalDateTime threshold = LocalDateTime.now().minusMinutes(30); @@ -51,8 +51,8 @@ public void cleanupOrphanedAnswers() { orphanedAnswers.forEach(answer -> { answer.markUploadFailed(); - log.warn("Marked answer {} as FAILED due to timeout (created: {}, sessionId: {})", - answer.getId(), answer.getCreatedAt(), answer.getSessionId()); + log.warn("event=scheduler_answer_timeout | answerId={} | sessionId={} | createdAt={}", + answer.getId(), answer.getSessionId(), answer.getCreatedAt()); }); answerRepository.saveAll(orphanedAnswers); @@ -75,7 +75,7 @@ public void timeoutRequestedFeedbacks() { if (!timedOutAnswers.isEmpty()) { timedOutAnswers.forEach(answer -> { answer.failFeedback(); - log.warn("Marked answer {} feedback as FAILED due to timeout (updatedAt: {})", + log.warn("event=scheduler_feedback_timeout | answerId={} | updatedAt={}", answer.getId(), answer.getUpdatedAt()); }); answerRepository.saveAll(timedOutAnswers); @@ -88,7 +88,7 @@ public void timeoutRequestedFeedbacks() { if (!timedOutDrillAnswers.isEmpty()) { timedOutDrillAnswers.forEach(drillAnswer -> { drillAnswer.failFeedback(); - log.warn("Marked drill answer {} feedback as FAILED due to timeout (updatedAt: {})", + log.warn("event=scheduler_feedback_timeout | drillAnswerId={} | updatedAt={}", drillAnswer.getId(), drillAnswer.getUpdatedAt()); }); drillAnswerRepository.saveAll(timedOutDrillAnswers); diff --git a/src/main/java/me/thinkcat/opic/practice/service/AnswerService.java b/src/main/java/me/thinkcat/opic/practice/service/AnswerService.java index 20f18cd..e93f02e 100644 --- a/src/main/java/me/thinkcat/opic/practice/service/AnswerService.java +++ b/src/main/java/me/thinkcat/opic/practice/service/AnswerService.java @@ -1,6 +1,7 @@ package me.thinkcat.opic.practice.service; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import me.thinkcat.opic.practice.dto.mapper.AnswerMapper; import me.thinkcat.opic.practice.dto.request.PresignedUrlRequest; import me.thinkcat.opic.practice.dto.response.AnswerResponse; @@ -28,6 +29,7 @@ @Service @RequiredArgsConstructor +@Slf4j public class AnswerService { private final FeatureFlagService featureFlagService; @@ -64,6 +66,8 @@ public PrepareAnswerUploadResponse prepareAnswerUpload( .build(); Answer savedAnswer = answerRepository.save(answer); + log.info("event=answer_prepare | who={} | sessionId={} | questionId={} | answerId={}", + userId, sessionId, questionId, savedAnswer.getId()); return PrepareAnswerUploadResponse.builder() .answerId(savedAnswer.getId() != null ? savedAnswer.getId().toString() : null) @@ -88,6 +92,7 @@ public AnswerResponse completeAnswerUpload( .orElseThrow(() -> new ValidationException("Unauthorized access to answer")); if (answer.isUploadSuccess()) { + log.warn("event=answer_upload_already_done | who={} | answerId={}", userId, answerId); return resolveAnswerResponse(answer); } @@ -96,9 +101,14 @@ public AnswerResponse completeAnswerUpload( answer.setDurationMs(durationMs); } + log.info("event=answer_upload_complete | who={} | answerId={} | audioUrl={}", + userId, answerId, answer.getAudioUrl()); + if (userRole == UserRole.PAID || userRole == UserRole.ADMIN || featureFlagService.isEnabled("ai-for-free")) { answer.requestFeedback(); Answer updatedAnswer = answerRepository.save(answer); + log.info("event=feedback_requested | who={} | answerId={} | audioUrl={}", + userId, answerId, answer.getAudioUrl()); feedbackLambdaService.invokeSessionFeedbackAsync(answer.getAudioUrl()); return resolveAnswerResponse(updatedAnswer); } @@ -133,6 +143,8 @@ public AnswerResponse getAnswerForPlayback(Long answerId, Long userId) { boolean fileExists = presignedUrlService.checkFileExists(answer.getAudioUrl()); if (fileExists) { + log.warn("event=answer_upload_recovery | who={} | answerId={} | audioUrl={}", + userId, answerId, answer.getAudioUrl()); answer.markUploadSuccess(); answerRepository.save(answer); } else { @@ -142,6 +154,8 @@ public AnswerResponse getAnswerForPlayback(Long answerId, Long userId) { ).toMinutes(); if (minutesSinceCreation > 30) { + log.warn("event=answer_upload_failed | who={} | answerId={} | audioUrl={}", + userId, answerId, answer.getAudioUrl()); answer.markUploadFailed(); answerRepository.save(answer); throw new ValidationException("Answer upload failed or timed out"); @@ -172,6 +186,7 @@ public void updateTranscription(String audioUrl, String transcription, answer.setDurationMs((int) (duration * 1000)); } answerRepository.save(answer); + log.info("event=feedback_transcription_saved | audioUrl={}", audioUrl); } @Transactional @@ -182,6 +197,7 @@ public void updateFeedback(String audioUrl, String feedback) { answer.setFeedback(feedback); answer.completeFeedback(); answerRepository.save(answer); + log.info("event=feedback_completed | answerId={} | audioUrl={}", answer.getId(), audioUrl); } @Transactional @@ -193,8 +209,12 @@ public void updateFeedbackFailed(String audioUrl, FeedbackFailureReason reason) || reason == FeedbackFailureReason.TOO_SHORT; if (isInvalid) { answer.invalidateFeedback(); + log.warn("event=feedback_failed_callback | answerId={} | audioUrl={} | reason={}", + answer.getId(), audioUrl, reason.getCode()); } else { answer.failFeedback(); + log.error("event=feedback_error_callback | answerId={} | audioUrl={} | reason={}", + answer.getId(), audioUrl, reason.getCode()); } answerRepository.save(answer); } diff --git a/src/main/java/me/thinkcat/opic/practice/service/DrillAnswerService.java b/src/main/java/me/thinkcat/opic/practice/service/DrillAnswerService.java index d5b8ec8..5b7c7b7 100644 --- a/src/main/java/me/thinkcat/opic/practice/service/DrillAnswerService.java +++ b/src/main/java/me/thinkcat/opic/practice/service/DrillAnswerService.java @@ -1,6 +1,7 @@ package me.thinkcat.opic.practice.service; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import me.thinkcat.opic.practice.dto.mapper.DrillAnswerMapper; import me.thinkcat.opic.practice.dto.request.PresignedUrlRequest; import me.thinkcat.opic.practice.dto.response.DrillAnswerResponse; @@ -31,6 +32,7 @@ @Service @RequiredArgsConstructor +@Slf4j public class DrillAnswerService { private final FeatureFlagService featureFlagService; @@ -67,6 +69,8 @@ public PrepareDrillAnswerUploadResponse prepareDrillAnswerUpload( .build(); DrillAnswer savedAnswer = drillAnswerRepository.save(drillAnswer); + log.info("event=drill_prepare | who={} | questionId={} | drillAnswerId={}", + userId, questionId, savedAnswer.getId()); return PrepareDrillAnswerUploadResponse.builder() .drillAnswerId(savedAnswer.getId() != null ? savedAnswer.getId().toString() : null) @@ -87,6 +91,7 @@ public DrillAnswerResponse submitDrillAnswer(Long userId, UserRole userRole, Lon } if (answer.isUploadSuccess()) { + log.warn("event=drill_submit_already_done | who={} | drillAnswerId={}", userId, drillAnswerId); return resolveDrillAnswerResponse(answer); } @@ -95,9 +100,14 @@ public DrillAnswerResponse submitDrillAnswer(Long userId, UserRole userRole, Lon answer.setDurationMs(durationMs); } + log.info("event=drill_submit | who={} | drillAnswerId={} | audioUrl={}", + userId, drillAnswerId, answer.getAudioUrl()); + if (userRole == UserRole.PAID || userRole == UserRole.ADMIN || featureFlagService.isEnabled("ai-for-free")) { answer.requestFeedback(); DrillAnswer updatedAnswer = drillAnswerRepository.save(answer); + log.info("event=drill_feedback_requested | who={} | drillAnswerId={} | audioUrl={}", + userId, drillAnswerId, answer.getAudioUrl()); feedbackLambdaService.invokeDrillAnswerFeedbackAsync(answer.getAudioUrl()); return resolveDrillAnswerResponse(updatedAnswer); } @@ -167,6 +177,7 @@ public void updateTranscription(String audioUrl, String transcription, answer.setDurationMs((int) (duration * 1000)); } drillAnswerRepository.save(answer); + log.info("event=drill_transcription_saved | audioUrl={}", audioUrl); } @Transactional @@ -177,6 +188,7 @@ public void updateFeedback(String audioUrl, String feedback) { answer.setFeedback(feedback); answer.completeFeedback(); drillAnswerRepository.save(answer); + log.info("event=drill_feedback_completed | drillAnswerId={} | audioUrl={}", answer.getId(), audioUrl); } @Transactional @@ -188,8 +200,12 @@ public void updateFeedbackFailed(String audioUrl, FeedbackFailureReason reason) || reason == FeedbackFailureReason.TOO_SHORT; if (isInvalid) { answer.invalidateFeedback(); + log.warn("event=drill_feedback_failed_callback | drillAnswerId={} | audioUrl={} | reason={}", + answer.getId(), audioUrl, reason.getCode()); } else { answer.failFeedback(); + log.error("event=drill_feedback_error_callback | drillAnswerId={} | audioUrl={} | reason={}", + answer.getId(), audioUrl, reason.getCode()); } drillAnswerRepository.save(answer); } diff --git a/src/main/java/me/thinkcat/opic/practice/service/FeedbackLambdaService.java b/src/main/java/me/thinkcat/opic/practice/service/FeedbackLambdaService.java index c8d7b93..1dabed6 100644 --- a/src/main/java/me/thinkcat/opic/practice/service/FeedbackLambdaService.java +++ b/src/main/java/me/thinkcat/opic/practice/service/FeedbackLambdaService.java @@ -45,9 +45,9 @@ private void invokeAsync(String audioUrl, String lambdaFunctionName) { lambdaAsyncClient.invoke(request) .whenComplete((response, ex) -> { if (ex != null) { - log.error("Failed to invoke feedback Lambda for audioUrl={}: {}", audioUrl, ex.getMessage()); + log.error("event=feedback_lambda_invoke_fail | audioUrl={} | error={}", audioUrl, ex.getMessage()); } else { - log.info("Feedback Lambda invoked for audioUrl={}, statusCode={}", audioUrl, response.statusCode()); + log.info("event=feedback_lambda_invoke | audioUrl={} | statusCode={}", audioUrl, response.statusCode()); } }); }