Master HTTP Request/Response Logging in Spring Boot 3 with Logbook
This guide introduces the Logbook library for Spring Boot 3, explains how to add the starter dependency, configure default logging, customize request filtering, log formatting, sink implementation, and client‑side interception, and provides complete code examples and configuration snippets.
1. Introduction
Logging HTTP request and response data is essential for system observability and debugging. Logbook is an extensible Java library that can capture full request/response traffic for both client and server sides, making it useful for audit, troubleshooting, and analysis.
2. Key Features
Logs HTTP request and response bodies (unauthenticated requests are partially logged).
Customizable log format, storage location, and trigger conditions.
Supports Servlet containers, Apache HttpClient, OkHttp, and can be integrated with other frameworks via a clean API.
Optional sensitive‑data masking.
Spring Boot auto‑configuration.
Compatibility with Scalyr platform.
Reasonable defaults.
3. Dependency
<dependency>
<groupId>org.zalando</groupId>
<artifactId>logbook-spring-boot-starter</artifactId>
<version>3.12.3</version>
</dependency>4. Default Auto‑Configuration
The starter automatically registers several beans, including a servlet filter, an optional second filter for unauthenticated requests (when Spring Security is present), header/parameter/body filters, an HTTP/JSON formatter, and a log writer.
5. Practical Examples
5.1 Basic Logging Configuration
Enable TRACE level for Logbook in application.yml (or application.properties) to activate request/response logging:
logging:
level:
'[org.zalando.logbook.Logbook]': TRACEExample controller method:
@GetMapping("/query")
public ResponseEntity<?> query(String keyword) {
return ResponseEntity.ok("查询: %s".formatted(keyword));
}Console output shows the captured request and response (see image).
5.2 Custom Request Filtering
Define a bean named requestCondition that implements Predicate<HttpRequest> to exclude specific paths from logging:
@Component("requestCondition")
public class ApiPredicate implements Predicate<HttpRequest> {
@Value("${pack.excludes.paths}")
private Set<String> excludes;
@Override
public boolean test(HttpRequest t) {
return !excludes.contains(t.getPath());
}
}Configuration example:
pack:
excludes:
paths: /api/query,/api/createRequests matching those paths will no longer be logged.
5.3 Custom Log Formatter
Implement HttpLogFormatter to control the exact format of logged requests and responses:
@Component
public class PackHttpLogFormatter implements HttpLogFormatter {
@Override
public String format(Precorrelation precorrelation, HttpRequest request) throws IOException {
String correlationId = precorrelation.getId();
StringBuilder sb = new StringBuilder(request.getBodyAsString().length() + 2048);
sb.append(" Request: ").append(correlationId).append('
');
sb.append("Remote: ").append(request.getRemote()).append('
');
sb.append(request.getMethod()).append(' ');
RequestURI.reconstruct(request, sb);
sb.append(' ').append(request.getProtocolVersion()).append('
');
return sb.toString();
}
@Override
public String format(Correlation correlation, HttpResponse response) throws IOException {
String correlationId = correlation.getId();
StringBuilder sb = new StringBuilder(response.getBodyAsString().length() + 2048);
sb.append(" Response: ").append(correlationId).append('
');
sb.append("Duration: ").append(correlation.getDuration().toMillis()).append(" ms
");
sb.append(response.getProtocolVersion()).append(' ').append(response.getStatus());
if (response.getReasonPhrase() != null) {
sb.append(' ').append(response.getReasonPhrase());
}
sb.append('
');
return sb.toString();
}
}Resulting log entries are shown in the accompanying screenshot.
5.4 Custom Sink
Implement Sink to write logs to a database, message queue, or any other destination:
@Component
public class PackLogSink implements Sink {
@Override
public void write(Precorrelation precorrelation, HttpRequest request) throws IOException {
// optional handling for request‑only logging
}
@Override
public void write(Correlation correlation, HttpRequest request, HttpResponse response) throws IOException {
System.err.printf("写日志 - 请求路径: %s, 查询参数: %s%n响应结果:%s%n",
request.getPath(), request.getQuery(), response.getBodyAsString());
}
}Sample console output:
写日志 - 请求路径: /api/query, 查询参数: keyword=spring
响应结果:查询: spring5.5 Logging HTTP Client Calls
Register LogbookClientHttpRequestInterceptor with a RestClient bean to capture outbound HTTP calls:
@Bean
public RestClient restClient(RestClient.Builder builder, LogbookClientHttpRequestInterceptor interceptor) {
return builder.baseUrl("http://localhost:8080")
.requestInterceptors(i -> i.add(interceptor))
.build();
}Example remote‑call controller:
@GetMapping("/remote")
public ResponseEntity<?> remote() {
String body = restClient.get()
.uri("/enum/query?sex={0}", "female")
.retrieve()
.body(String.class);
return ResponseEntity.ok(body);
}Logbook logs the outgoing request and the received response (see image).
6. Additional Configuration
The starter also provides a rich set of optional properties for fine‑tuning log output, bean replacement, and integration with other logging platforms. The following images illustrate the default bean list and further configuration options.
Spring Full-Stack Practical Cases
Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
