add Film observability with trace id and metrics (#44)
* add Film observability with trace id and metrics * test: provide meter registry in FilmServiceTest
This commit was merged in pull request #44.
This commit is contained in:
@@ -3,6 +3,8 @@ package com.project.movienight.adapters.web
|
||||
import com.project.movienight.domain.exception.BlockedValueException
|
||||
import com.project.movienight.domain.exception.DomainException
|
||||
import com.project.movienight.domain.exception.EntityNotFoundException
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.slf4j.MDC
|
||||
import org.springframework.http.HttpStatus
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler
|
||||
import org.springframework.web.bind.annotation.ResponseStatus
|
||||
@@ -10,22 +12,60 @@ import org.springframework.web.bind.annotation.RestControllerAdvice
|
||||
|
||||
@RestControllerAdvice
|
||||
class ApiExceptionHandler {
|
||||
private val log = LoggerFactory.getLogger(javaClass)
|
||||
|
||||
@ExceptionHandler(EntityNotFoundException::class)
|
||||
@ResponseStatus(HttpStatus.NOT_FOUND)
|
||||
fun handleNotFound(exception: EntityNotFoundException): ErrorResponse =
|
||||
ErrorResponse(message = exception.message ?: "Entity not found")
|
||||
fun handleNotFound(exception: EntityNotFoundException): ErrorResponse {
|
||||
val traceId = currentTraceId()
|
||||
log.warn("Entity not found: traceId='{}', message='{}'", traceId, exception.message)
|
||||
|
||||
return ErrorResponse(
|
||||
message = exception.message ?: "Entity not found",
|
||||
traceId = traceId,
|
||||
)
|
||||
}
|
||||
|
||||
@ExceptionHandler(BlockedValueException::class)
|
||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||
fun handleBlockedValue(exception: BlockedValueException): ErrorResponse =
|
||||
ErrorResponse(message = exception.message ?: "Blocked value")
|
||||
fun handleBlockedValue(exception: BlockedValueException): ErrorResponse {
|
||||
val traceId = currentTraceId()
|
||||
log.warn("Blocked value: traceId='{}', message='{}'", traceId, exception.message)
|
||||
|
||||
return ErrorResponse(
|
||||
message = exception.message ?: "Blocked value",
|
||||
traceId = traceId,
|
||||
)
|
||||
}
|
||||
|
||||
@ExceptionHandler(DomainException::class)
|
||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||
fun handleDomainException(exception: DomainException): ErrorResponse =
|
||||
ErrorResponse(message = exception.message ?: "Domain error")
|
||||
fun handleDomainException(exception: DomainException): ErrorResponse {
|
||||
val traceId = currentTraceId()
|
||||
log.warn("Domain error: traceId='{}', message='{}'", traceId, exception.message)
|
||||
|
||||
return ErrorResponse(
|
||||
message = exception.message ?: "Domain error",
|
||||
traceId = traceId,
|
||||
)
|
||||
}
|
||||
|
||||
@ExceptionHandler(Exception::class)
|
||||
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
fun handleUnexpectedException(exception: Exception): ErrorResponse {
|
||||
val traceId = currentTraceId()
|
||||
log.error("Unexpected error: traceId='{}'", traceId, exception)
|
||||
|
||||
return ErrorResponse(
|
||||
message = "Internal server error",
|
||||
traceId = traceId,
|
||||
)
|
||||
}
|
||||
|
||||
private fun currentTraceId(): String = MDC.get("traceId") ?: "unknown"
|
||||
}
|
||||
|
||||
data class ErrorResponse(
|
||||
val message: String,
|
||||
val traceId: String,
|
||||
)
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.project.movienight.adapters.web
|
||||
|
||||
import jakarta.servlet.FilterChain
|
||||
import jakarta.servlet.http.HttpServletRequest
|
||||
import jakarta.servlet.http.HttpServletResponse
|
||||
import org.slf4j.MDC
|
||||
import org.springframework.stereotype.Component
|
||||
import org.springframework.web.filter.OncePerRequestFilter
|
||||
import java.util.UUID
|
||||
|
||||
@Component
|
||||
class TraceIdFilter : OncePerRequestFilter() {
|
||||
override fun doFilterInternal(
|
||||
request: HttpServletRequest,
|
||||
response: HttpServletResponse,
|
||||
filterChain: FilterChain,
|
||||
) {
|
||||
val traceId = UUID.randomUUID().toString()
|
||||
MDC.put("traceId", traceId)
|
||||
|
||||
try {
|
||||
filterChain.doFilter(request, response)
|
||||
} finally {
|
||||
MDC.remove("traceId")
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user