Logging in a containerized world

One of the 12-factor principles is to treat logging as a stream of events. This includes the idea that handling log files should not be a concern of the enterprise application. Log events should simply output to the process' standard output.

The application's runtime environment consolidates and processes the log streams. There are solutions for unified access over all participating applications that can be deployed into the environment. The runtime environment where the application is deployed takes care of processing the log streams. fluentd, which is part of the Cloud Native Computing Foundation unifies the access to log events in a distributed environment.

Application developers should treat the used logging technology as simply as possible. The application container is configured to output all server and application log events to standard output. This approach simplifies matters for enterprise developers and enables them to focus more on solving actual business problems.

As we have seen, there is not much information left that application developers reasonably can log in a traditional way. Monitoring, journaling, or tracing solutions, as well as event sourcing, can solve the requirements in more suitable ways.

Together with logging to standard output without the need for sophisticated log file handling, there is no need for sophisticated logging framework. This supports zero-dependency applications and enables developers to be able to focus on business concerns instead.

It's therefore advisable to avoid third-party logging frameworks, as well as writing to traditional log files. The need to manage log rotations, log entry formats, levels, and framework dependencies, as well as configuration, becomes no longer necessary.

However, the following might seem antithetical to enterprise developers.

The straightforward, 12-factor way to log the output is using the standard output capabilities of Java via System.out and System.err. This directly writes the synchronous output without needless layers of buffering.

It's important to mention that outputting data via this approach will not perform. The introduced synchronization, again, ties otherwise independent parts of the application together. If the output of the process is grabbed and emitted by a video card, the performance will further decrease.

Logging to console is only meant to emit errors that are, as the name of the Java type indicates - an exception. In all other cases, engineers must ask themselves why they want to output an information in the first place, or whether other solutions are more suitable. Therefore, logged errors should indicate a fatal problem that requires engineering action. It should not be expected to receive this log output in production; in this fatal error case, performance can be disrespected.

In order to output fatal error information, Java EE applications can use CDI features as well as Java SE 8 functional interfaces to provide a uniform logging functionality:

public class LoggerExposer {

    @Produces
    public Consumer<Throwable> fatalErrorConsumer() {
        return Throwable::printStackTrace;
    }
}

The Consumer<Throwable> logger is then injectable in other beans, and it logs using the accept() method of the consumer type. If a more readable interface is desired, a thin logger facade type which is injected via @Inject can be defined as follows:

public class ErrorLogger {

    public void fatal(Throwable throwable) {
        throwable.printStackTrace();
    }
}

This approach will seem antithetical to enterprise developers, especially logging without using a logging framework. Using a sophisticated logging framework, which is used to direct the output to standard out again, introduces overhead, which ultimately ends up in the same result. Some developers may prefer to use JDK logging at this point.

However, providing sophisticated log interfaces and thus giving application developers the opportunity to output all kinds of information, especially human-readable strings, is counterproductive. This is why the code examples only allow to output throwable types in fatal error situations.

It's important to notice the following few aspects:

  • Traditional logging should be avoided and substituted with more-suited solutions
  • Only fatal error cases that are the exception, and are expected to ideally never happen, should be logged
  • Containerized applications are advised to output log events to standard out
  • Application logging and interfaces should be as simple as possible, preventing developers from excessive use
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.129.26.22