Customizing the logback-access format
If you’re already using Logback and Logback Logstash Encoder with Spring Boot to log to something like ELK or Splunk and want to add HTTP access logs to your application then logback-access is simple to integrate and the output format and destination can be easily configured through XML just like for standard Logback.
To begin add the logback-access dependency to your project:
implementation 'ch.qos.logback:logback-access'
Then configure the embedded server (Tomcat in this case) to integrate with logback-access:
@Configuration
public class LogbackAccessConfiguration implements WebServerFactoryCustomizer<ConfigurableTomcatWebServerFactory> {
@Override
public void customize(ConfigurableTomcatWebServerFactory factory) {
LogbackValve logbackValve = new LogbackValve();
logbackValve.setFilename("logback-access.xml");
factory.addEngineValves(logbackValve);
}
}
And finally create a logback-access.xml
in src/main/resources
:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="net.logstash.logback.encoder.LogstashAccessEncoder" />
</appender>
<appender-ref ref="STDOUT" />
</configuration>
By default the access events do not have a log level, to add one change the encoder
configuration and adding a JSON object in customFields
that will be merged with JSON output from the encoder:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="net.logstash.logback.encoder.LogstashAccessEncoder">
<customFields>{"level": "DEBUG"}</customFields>
</encoder>
</appender>
<appender-ref ref="STDOUT" />
</configuration>
You can also rename fields in the JSON output and add request and response headers to the output.
If you want complete control over the output you can use AccessEventCompositeJsonEncoder
instead of LogstashAccessEncoder
to specify exactly which fields are included in the JSON and the format of the message.
In the following example we include the timestamp
field from the common fields, the requestedUrl
, statusCode
and elapsedTime
fields from the access fields, and in addition a constant level
field, a user_agent
field with value taken from a request header and a simple custom message format:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="net.logstash.logback.encoder.AccessEventCompositeJsonEncoder">
<providers>
<timestamp/>
<requestedUrl/>
<statusCode/>
<elapsedTime/>
<pattern>
<pattern>
{
"level": "DEBUG",
"user_agent": "%i{User-Agent}",
"message": "%requestURL returned %statusCode in %elapsedTime ms"
}
</pattern>
</pattern>
</providers>
</encoder>
</appender>
<appender-ref ref="STDOUT" />
</configuration>
If you want to ignore certain URLs and not have accesses to them logged, you can do this by adding a filter
to your appender
configuration, for example to not log accesses to the /actuator
path (and sub paths):
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.core.filter.EvaluatorFilter">
<evaluator class="ch.qos.logback.access.net.URLEvaluator">
<URL>/actuator</URL>
</evaluator>
<OnMismatch>NEUTRAL</OnMismatch>
<OnMatch>DENY</OnMatch>
</filter>
<encoder class="net.logstash.logback.encoder.LogstashAccessEncoder" />
</appender>
<appender-ref ref="STDOUT" />
</configuration>