Micronaut Http Client and Server Logging
https://blog.pallav.dev/micronaut-and-httpclient-micronaut-declarative-client-and-filters
Micronaut Http Client and Server Logging
https://blog.pallav.dev/micronaut-and-httpclient-micronaut-declarative-client-and-filters
json: | |
server: | |
url: https://jsonplaceholder.typicode.com |
<?xml version="1.0" encoding="UTF-8"?> | |
<Configuration status="info"> | |
<Appenders> | |
<Console name="LogToConsole" target="SYSTEM_OUT"> | |
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} %X{X-API-ID} - %msg%n"/> | |
</Console> | |
</Appenders> | |
<Loggers> | |
<Logger name="io.micronaut.context" level="off" additivity="false"> | |
<AppenderRef ref="LogToConsole"/> | |
</Logger> | |
<Logger name="io.micronaut.configuration" level="off" additivity="false"> | |
<AppenderRef ref="LogToConsole"/> | |
</Logger> | |
<Logger name="io.micronaut.configuration.kafka" level="off" additivity="false"> | |
<AppenderRef ref="LogToConsole"/> | |
</Logger> | |
<Logger name="com.richardagyei" level="info" additivity="false"> | |
<AppenderRef ref="LogToConsole"/> | |
</Logger> | |
<Root level="error"> | |
<AppenderRef ref="LogToConsole"/> | |
</Root> | |
</Loggers> | |
</Configuration> |
@Client("\${json.server.url}") | |
interface PostClient { | |
@Get("/posts") | |
suspend fun getPost(@QueryValue("id") id: Int): List<Post>? | |
} | |
data class Post( | |
val id: Int, | |
val userId: Int, | |
val title: String, | |
val body: String | |
) | |
data class Error( | |
val status: String, | |
val message: String | |
) | |
import io.micronaut.context.event.ApplicationEventListener | |
import io.micronaut.context.event.StartupEvent | |
import io.micronaut.runtime.Micronaut.* | |
import jakarta.inject.Singleton | |
import kotlinx.coroutines.CoroutineScope | |
import kotlinx.coroutines.Dispatchers | |
import kotlinx.coroutines.launch | |
fun main(args: Array<String>) { | |
run(*args) | |
} | |
@Singleton | |
class ApplicationStarted(private val postClient: PostClient) : ApplicationEventListener<StartupEvent> { | |
override fun onApplicationEvent(event: StartupEvent?) { | |
CoroutineScope(Dispatchers.IO).launch { | |
postClient.getPost(1)?.forEach { p -> println(p) } | |
} | |
} | |
} |
import io.micronaut.http.HttpResponse | |
import io.micronaut.http.MutableHttpRequest | |
import io.micronaut.http.annotation.Filter | |
import io.micronaut.http.filter.ClientFilterChain | |
import io.micronaut.http.filter.HttpClientFilter | |
import mu.KotlinLogging | |
import org.reactivestreams.Publisher | |
import org.slf4j.MDC | |
import java.util.* | |
@Filter("/**") | |
class MDCLoggingClientFilter : HttpClientFilter { | |
private val logger = KotlinLogging.logger { } | |
override fun doFilter(request: MutableHttpRequest<*>, chain: ClientFilterChain): Publisher<out HttpResponse<*>> { | |
val requestHeaders = request.headers | |
val correlationId = | |
requestHeaders.get(MDCServerLoggingFilter.CORRELATION_ID_KEY) | |
?: requestHeaders.get(MDCServerLoggingFilter.API_ID_KEY) ?: UUID.randomUUID().toString() | |
MDC.put(MDCServerLoggingFilter.CORRELATION_ID_KEY, correlationId) | |
MDC.put(MDCServerLoggingFilter.API_ID_KEY, correlationId) | |
logger.info { "sending a request for ${request.uri} and path ${request.path}" } | |
println("sending a request for ${request.uri} and path ${request.path}") | |
request.setAttribute(MDCServerLoggingFilter.CORRELATION_ID_KEY, correlationId) | |
request.headers.add(MDCServerLoggingFilter.API_ID_KEY, correlationId) | |
request.headers.add(MDCServerLoggingFilter.CORRELATION_ID_KEY, correlationId) | |
return chain.proceed(request) | |
} | |
} |
import io.micronaut.http.annotation.Filter | |
import io.micronaut.http.filter.HttpServerFilter | |
import io.micronaut.http.filter.ServerFilterChain | |
import mu.KotlinLogging | |
import org.reactivestreams.Publisher | |
import org.slf4j.MDC | |
import reactor.core.publisher.Flux | |
import java.util.* | |
@Filter("/**") | |
class MDCServerLoggingFilter : HttpServerFilter { | |
// | |
private val logger = KotlinLogging.logger { } | |
companion object { | |
const val CORRELATION_ID_KEY = "X-CORRELATION-ID" | |
const val API_ID_KEY = "X-API-ID" | |
} | |
override fun doFilter(request: HttpRequest<*>, chain: ServerFilterChain): Publisher<MutableHttpResponse<*>> { | |
val requestHeaders = request.headers | |
val correlationId = | |
requestHeaders.get(CORRELATION_ID_KEY) ?: requestHeaders.get(API_ID_KEY) ?: UUID.randomUUID().toString() | |
MDC.put(CORRELATION_ID_KEY, correlationId) | |
MDC.put(API_ID_KEY, correlationId) | |
logger.info { "Got a request coming in ${request.uri} and path ${request.path}" } | |
request.setAttribute(CORRELATION_ID_KEY, correlationId) | |
return Flux.from(chain.proceed(request)) | |
.map { res -> | |
res.headers.add(CORRELATION_ID_KEY, correlationId) | |
res.headers.add(API_ID_KEY, correlationId) | |
res | |
} | |
} | |
} |