{8.1.0-new} Logging / Debugging
The REST APIs provides support for fine-tuned control of logging for HTTP requests and responses.
The APIs involved are:
The amount of detail on requests and responses is controlled via the {@link oajr.annotation.LoggingRule#req() @LoggingRule(req)} and {@link oajr.annotation.LoggingRule#res() @LoggingRule(res)} annotations:
The following code shows the output produced using the
The log output produced from the code above looks like this:
WARNING: [500] HTTP POST /foo java.lang.StringIndexOutOfBoundsException at org.apache.juneau.rest.annotation.RestResourceLoggingTest$MyRestClass.myRestMethod(RestResourceLoggingTest.java:672) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) ...
In comparison, using
Request/response bodies are only cached for logging if debugging is enabled via the
The log file now contains the following with shows the contents of the request and response bodies in both UTF-8 and spaced-hex:
WARNING: === HTTP Request (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 Body UTF-8--- Foo ---Request Body Hex--- 46 6F 6F ---Response Body UTF-8--- Foo ---Response Body Hex--- 46 6F 6F === END =================================================================== java.lang.StringIndexOutOfBoundsException at org.apache.juneau.rest.annotation.RestResourceLoggingTest$MyRestClass.myRestMethod(RestResourceLoggingTest.java:672) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) ...
Logging rules can match against status codes, exception class names, and the debug flag.
The following shows various examples of logging rule matches.
Rules are matched in the order listed on the annotation. Rules on methods are matched before rules on classes. Rules on child methods/classes are matched before rules on parent classes.
The debug mode setting allows HTTP request/response bodies to be cached in memory for logging purposes:
The possible values for the debug setting are (case-insensitive):
Note that caching HTTP bodies in memory can produce significant performance penalties, so use the setting wisely.
In particular, do not leave this setting enabled on production instances since it can easily lead to
denial-of-service attacks.
Servlet code can check the debug setting via the {@link oajr.RestRequest#isDebug()} method allowing it to be used for custom purposes.
Debug mode can also be enabled on a request by calling the {@link oajr.RestRequest#setDebug(Boolean)} or {@link oajr.RestResponse#setDebug(Boolean)} methods. Note however that you must be sure not to have already consumed the request or started writing the response before calling this method.
The {@link oajr.annotation.Logging#disabled() @Logging(disabled)} and {@link oajr.annotation.LoggingRule#disabled() @LoggingRule(disabled)} annotations can be used to disable logging entirely or on a per-request basis:
The possible values for the disabled setting are (case-insensitive):
Disabled logging is particularly useful when running testcases that are expected to throw exceptions or cause other errors and you don't want these errors logged.
Disabled logging can also be set on a request by calling the {@link oajr.RestRequest#setNoTrace(Boolean)} or {@link oajr.RestResponse#setNoTrace(Boolean)} methods.
The {@link oajr.annotation.Logging#useStackTraceHashing() @Logging(useStackTraceHashing)} setting can be used to eliminate duplicate stacktraces in your log file by logging them once and then logging identifying hash IDs.
In the example below, we're causing two exceptions but only logging the first one:
The log file will show a 4 byte hash ID
Jul 11, 2019 3:38:48 PM org.apache.juneau.rest.BasicRestCallLogger log WARNING: [500,9b85cc96.1] HTTP POST /foo java.lang.StringIndexOutOfBoundsException at org.apache.juneau.rest.annotation.RestResourceLoggingTest$MyRestClass.myRestMethod(RestResourceLoggingTest.java:671) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) ... WARNING: [500,9b85cc96.2] HTTP POST /foo
The {@link oajr.annotation.Logging#stackTraceHashingTimeout() @Logging(stackTraceHashingTimeout)} setting can be used to periodically log the stacktrace to the log file again.