{title:'Logging / Debugging', created:'9.0.0'}

The REST APIs provides supports enabling logging of HTTP requests and responses through the following annotations:

Debug mode enables the following:

The possible annotation values are:

Example

| // 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 {@link oajr.annotation.Rest#debugOn() @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 {@link oajr.annotation.Rest#debugOn() @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 {@link oajr.logger.CallLogger} and the default is {@link oajr.logger.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 {@link oajr.stats.ThrownStore} bean which is configured via the following: