Fork me on GitHub

Logger Tutorial

This tutorial demonstrates using logging.

To focus on logging, this tutorial uses a simple application that logs the input string sent by the client.

Tutorial Source

Logging from procedure

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;
}

Logging from object

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.

Why inject the Logger?

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.

Testing

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");
	}

Next

The next tutorial covers JWT security.