This tutorial demonstrates using logging.
To focus on logging, this tutorial uses a simple application that logs the input string sent by the client.
To log from a first-class procedure, have the Logger injected as follows:
public void log(LoggedRequest request, Logger procedureLogger, LogObject object) { // Log the request via procedure logger procedureLogger.info("PROCEDURE: " + request.getMessage()); // Have dependency injected object use it's logger object.log(request); }
The Logger will log the message from the input request object:
@HttpObject @Data @AllArgsConstructor @NoArgsConstructor public class LoggedRequest { private String message; }
As alluded to in the procedure, it is also possible to log from an injected object. The injected object is as follows:
public class LogObject { private @Dependency Logger logger; public void log(LoggedRequest request) { this.logger.info("OBJECT: " + request.getMessage()); } }
The Logger for the object is different to the procedure. This is because the respective injected Logger identifies each component individually in the log.
Statically creating, i.e. Logger.getLogger("name"), ties the Logger to the creating Class. This is ok for Dependency Injection only frameworks. These frameworks typically only have single instances of classes serving a request (i.e. an application, thread local or request scoped singleton). Therefore, inferring the class name in the log messages provides reasonable traceability to the single instance of the class logging the message.
When building with Inversion of Coupling Control, there is a lot more re-use of classes. Just identifying the class name does not identify the various places the class may be re-used.
The injected Logger is configured to identify the component within the application. Therefore, if the Class is re-used in the configuration of the application, the logs don't become ambiguous. The logs will identify the component within the application configuration. Just follow the dot notation down the levels of configuration.
The following test demonstrates the component naming of the injected Logger instances:
@RegisterExtension public MockWoofServerExtension server = new MockWoofServerExtension(); @RegisterExtension public LoggerExtension log = new LoggerExtension(); @Test public void ensureLogging() { // Send request to be logged MockHttpResponse response = this.server .send(MockWoofServer.mockJsonRequest(HttpMethod.POST, new LoggedRequest("TEST"))); response.assertResponse(204, ""); // Ensure log input message (from procedure) this.log.assertLog("log.procedure", Level.INFO, "PROCEDURE: TEST"); // Ensure log from object this.log.assertLog("OFFICE.net_officefloor_tutorial_loggerhttpserver_LogObject", Level.INFO, "OBJECT: TEST"); }
JUnit 4 example:
@Rule public final MockWoofServerRule server = new MockWoofServerRule(this); @Rule public final LoggerRule log = new LoggerRule(); @Test public void ensureLogging() { // Send request to be logged MockHttpResponse response = this.server .send(MockWoofServer.mockJsonRequest(HttpMethod.POST, new LoggedRequest("TEST"))); response.assertResponse(204, ""); // Ensure log input message (from procedure) this.log.assertLog("log.procedure", Level.INFO, "PROCEDURE: TEST"); // Ensure log from object this.log.assertLog("OFFICE.net_officefloor_tutorial_loggerhttpserver_LogObject", Level.INFO, "OBJECT: TEST"); }
The next tutorial covers JWT security.