Logging / Debugging
The REST APIs provides supports enabling logging of HTTP requests and responses through the following annotations:
Debug mode enables the following:
- HTTP request/response bodies are cached in memory for logging purposes.
- HTTP requests/responses are logged to the registered CallLogger.
The possible annotation values are:
true
- Debug is enabled for all requests.false
- Debug is disabled for all requests.conditional
- Debug is enabled only for requests that have aDebug: true
header.
// Enable debugging on all op calls on this resource
@Rest(debug="true")
public class MyResource {...}
These annotations support SVL variables, so it's possible to define them as a system property for example.
// Enable via system property 'MyResource.debug'
@Rest(debug="$S{MyResource.debug}")
public class MyResource {...}
The @Rest(debugOn) annotation can also be used to
enable debugging.
It takes a comma-delimited list of key-value pairs, the keys being class or method names, and the values being one of true|false|conditional
.
// Turn on debug per-request on the class and always on the doX() method
@Rest(debugOn="MyResource=conditional,MyResource.doX=true")
public class MyResource {...}
The primary advantage of @Rest(debugOn) is that you can control debugging externally such as through a system property or environment variable:
// Turn on debug per-request on the class and always on the doX() method
@Rest(debugOn="$E{DEBUG}")
public class MyResource {...}
Debugging can also be enabled programmatically with the use of the following APIs:
HTTP calls can be logged with the following levels of granularity:
The following examples show the output format for each detail type:
STATUS_LINE
WARNING: [500] HTTP POST /foo?foo=bar
HEADER
WARNING:
=== HTTP Call (incoming) ===================================================
[500] HTTP POST /foo?foo=bar
Request length: 3 bytes
Response code: 500
Response length: 3 bytes
Exec time: 20ms
---Request Headers---
Foo: bar
---Response Headers---
Foo: bar
`Content-Type: text/plain`
=== END ===================================================================
ENTITY
WARNING:
=== HTTP Call (incoming) ===================================================
[500] HTTP POST /foo?foo=bar
Request length: 3 bytes
Response code: 500
Response length: 3 bytes
Exec time: 20ms
---Request Headers---
Foo: bar
---Response Headers---
Foo: bar
`Content-Type: text/plain`
---Request Content UTF-8---
Foo
---Request Content Hex---
46 6F 6F
---Response Content UTF-8---
Foo
---Response Content Hex---
46 6F 6F
=== END ===================================================================
The interface responsible for generating the log entries is CallLogger and the default is BasicCallLogger which produces the output above.
It can be changed through any of the following:
The call logger uses logging rules to map requests to logging detail levels.
By default, these are the logging rules:
RestLogger
.create()
.beanStore(beanStore) // Allow injected beans in constructor
.normalRules( // Rules when debugging is not enabled
RestLoggerRule.create() // Log 500+ errors with status-line and header information
.statusFilter(x -> x >= 500)
.level(SEVERE)
.requestDetail(HEADER)
.responseDetail(HEADER)
.build(),
RestLoggerRule.create() // Log 400-500 errors with just status-line information
.statusFilter(x -> x >= 400)
.level(WARNING)
.requestDetail(STATUS_LINE)
.responseDetail(STATUS_LINE)
.build()
)
.debugRules( // Rules when debugging is enabled
RestLoggerRule.create() // Log everything with full details
.level(SEVERE)
.requestDetail(ENTITY)
.responseDetail(ENTITY)
.build()
);
Thrown exceptions get logged with a stack trace hash and a counter like below:
WARNING: [500,9b85cc96.13] HTTP POST /foo?foo=bar
Stack trace hashes are controlled by the ThrownStore bean which is configured via the following:
- The BasicTestCallLogger class is useful for testing and allows you to suppress logging when testing error conditions by passing in a
noTrace=true
query parameter orNo-Trace: true
header on requests. - DebugEnablement, CallLogger, and ThrownStore can all be defined globally as Spring beans in a Spring Boot environment.