Skip to content

1 Introduction

apryamostanov edited this page Aug 7, 2019 · 2 revisions

Table of contents generated with markdown-toc

Introduction

Foreword

Possibly due to a certain lack of theoretical provision, Logging has always been a zone of turbulence in the Java world.

This caused a diversity of logging libraries to appear over the time, such as:

  • Log4j
  • Java Util Logging
  • Commons Logging
  • Logback
  • Log4j2

Aiming to address the limitations of others, each one of them unfortunately has been bringing its own shortcomings.

While from the code standardization perspective things got improved with the adaptation of Slf4j as a logging abstraction layer, there are still unresolved issues in the existing logging frameworks.

As an Open Source Community, we are taking initiative to come up with a new revolutionary approach to create a lightweight yet functionally saturated Logger using latest technology such as scripting.

Problems

Declarative programming in Logger configuration

Existing logging solutions provide only partial support for scripting in configuration.

We end up doing declarative programming in logger configuration (XML, JSON, YAML, programmatic configuration) rather than configuring logger to dynamically interpret configuration values during run-time using imperative scripting.

Let's consider the example of Logback filter configuration to log only INFO messages:

<filter class="ch.qos.logback.classic.filter.LevelFilter">
  <level>INFO</level>
  <onMatch>ACCEPT</onMatch>
  <onMismatch>DENY</onMismatch>
</filter>

This is a typical example of declarative XML programming.

Note: Logback supports Groovy Script filter - but it is applicable only on specific appender configuration, not on Logger configuration.

And there is no support for Groovy message text formatting (encoder pattern).

Complicated and verbose configuration

Let's take examples of Logback and Log4j2.

It is impossible to configure log level on the appender level.

  • Appenders are defined separately from Loggers and Loggers reference the appender using AppenderRef.
  • Only Loggers accept Level and Class Name configuration

Let's say we would like to exclude debug of class Foo from a specific log file, without affecting other log files and classes.

In Logback this is solved using Groovy Script Filter on Appender, but when we have many appenders - configuration is duplicated and its size grows quickly.

Log files per Log Level

We could not find how to store each log level in individual file with efficient configuration.

Existing possibilities require duplication of appenders per log level.

Class name filtering on Root logger

Only log level is configurable on Root logger, however there is no possibility for centralized control which classes are enabled to be logged.

There is a disconnect between how the log data is produced by the application and how it is being consumed by the Logger

As a historical practice, loggers (and their configuration) are Class-centric, rather than file-centric.

However the human perception is more logical towards expectation around end file contents, rather than bothering about specific classes.

In practice this misconception causes functional limitations for existing loggers such as:

  • Complicated configuration of file naming, log separation and archiving
  • Irrational logger configuration

For example:

  • Logback supports maximum 1 discriminator in SiftingAppender
  • SiftingAppender has limitations in support of archiving and rolling policies
  • Complicated configuration of RoutingAppender in Log4j2

The Solution

Full support for scripting in logger run-time configuration files

Bobbin is using the configuration as a placeholder for Groovy scripts that define the run-time operation of the logger.

Here is how the above filter example would have looked like when logger is configured to interpret imperative run-time scripts:

{
  "levels": "['info'].contains(level)"
}

Each and every aspect of the logger is configurable using Groovy Script:

  • Log levels
  • Class Names
  • Message Formats
  • File Names

Easy and concise configuration

Bobbin does not need Encoders, Patterns, Filters, Discriminators and many other excessive stuff.

It is configured by a very small number of main parameters:

  1. Levels
  2. Class Names
  3. Destinations
  4. Message format

There are also very few supplementary parameters:

  1. File name
  2. Supplementary message formats (such as message with throwable)

Very easy to remember isn't it? But so much freedom to manipulate.

Log files per Log Level

Just put ${level} into the file name mask parameter of Bobbin configuration.

By it's nature, Bobbin Logger is thread-safe.

Bobbin does not have any synchronized statements or methods.

Each Bobbin instance maintains separate sets of file descriptors per thread (using ThreadLocal), thus achieving thread safety of data written into the log files.

You can’t perform that action at this time.