micronaut {
...
server {
...
netty {
access-logger {
logger-name = "access-log"
enabled = true
log-format = %a - - %t '%r' %s %b "%{referer}i" "%{user-agent}i" "CID:%{x-request-id}o" %D
}
}
}
...
}
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
<Appenders>
<Console name="console" target="SYSTEM_OUT">
<JSONLayout compact="true" eventEol="true" properties="true" locationInfo="true" stacktraceAsString="true">
<KeyValuePair key="time" value="$${date:yyyy-MM-dd'T'HH:mm:ss.SSSZ}"/>
</JSONLayout>
</Console>
<Console name="accessLog" target="SYSTEM_OUT">
<PatternLayout pattern="%m%n"/>
</Console>
</Appenders>
<Loggers>
<Root level="warn">
</Root>
<!--👇 the important entry right here, yo 👇-->
<logger name="access-log" level="info">
<AppenderRef ref="accessLog"/>
</logger>
<Logger name="io.micronaut" level="info">
<AppenderRef ref="console"/>
</Logger>
<Logger name="io.netty" level="info">
<AppenderRef ref="console"/>
</Logger>
<Logger name="io.github" level="info">
<AppenderRef ref="console"/>
</Logger>
<Logger name="kotlinx.coroutines" level="info">
<AppenderRef ref="console"/>
</Logger>
<Logger name="no.vegaasen" level="info">
<AppenderRef ref="console"/>
</Logger>
</Loggers>
</Configuration>
Got a Spring Boot application based on WebFlux, Netty and Reactive? Require to change some logging format stuff? Just use a variation of this logger 🔥 💥.
Note: This example assumes Log4j2.
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
<Appenders>
<Console name="console-json" target="SYSTEM_OUT">
<JSONLayout compact="true" eventEol="true" properties="true" locationInfo="true" stacktraceAsString="true">
<KeyValuePair key="time" value="$${date:yyyy-MM-dd'T'HH:mm:ss.SSSZ}"/>
</JSONLayout>
</Console>
<Console name="console-plain" target="SYSTEM_OUT">
<PatternLayout pattern="%m%n"/>
</Console>
</Appenders>
<Loggers>
<Root level="INFO"/>
<Logger name="org.springframework.web.servlet.PageNotFound" level="ERROR">
<AppenderRef ref="console-json"/>
</Logger>
<Logger name="org.springframework" level="WARN">
<AppenderRef ref="console-json"/>
</Logger>
<Logger name="reactor.netty.http.server.AccessLog" level="INFO">
<AppenderRef ref="console-plain"/>
</Logger>
<Logger name="no.whatever" level="INFO">
<AppenderRef ref="console-json"/>
</Logger>
<Logger name="liquibase" level="INFO">
<AppenderRef ref="console-json"/>
</Logger>
</Loggers>
</Configuration>
package no.whatever.config
import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory
import org.springframework.boot.web.server.WebServerFactoryCustomizer
import org.springframework.context.annotation.Configuration
import reactor.netty.http.server.logging.AccessLog
import java.net.InetSocketAddress
import java.net.SocketAddress
import java.time.format.DateTimeFormatter
private const val unknown = "-"
private val accessTimeFormatter = DateTimeFormatter.ofPattern("dd/MMM/yyyy:HH:mm:ss Z")
private fun SocketAddress?.ipAddress() = if (this is InetSocketAddress) hostString else unknown
private fun AccessLogArgProvider.correlationId() = requestHeader(header_x_request_id)?.toString()?.also(::correlationIdDefine)
@Configuration
class AccessLogConfiguration : WebServerFactoryCustomizer<NettyReactiveWebServerFactory> {
override fun customize(factory: NettyReactiveWebServerFactory) {
factory.addServerCustomizers({ server ->
server.accessLog(true) { provider ->
AccessLog.create(
"{} - {} [{}] \"{} {} {}\" {} {} {} \"{}\" \"{}\" {}",
provider.remoteAddress().ipAddress(),
provider.user(),
provider.accessDateTime()?.format(accessTimeFormatter).orEmpty(),
provider.method(),
provider.uri(),
provider.protocol(),
provider.status(),
if (provider.contentLength() > -1) provider.contentLength() else unknown,
unknown,
provider.requestHeader("User-Agent") ?: unknown,
provider.correlationId()?.let { "CID:$it" } ?: unknown,
provider.duration()
)
}
})
}
}
You do no longer need to enable the access log explicitly either, as it is already configured by your configuration.
// remove this one, if you have it 👇
private fun SpringApplicationBuilder.useNettyLogging() = also { setProperty(ACCESS_LOG_ENABLED, "false") }