跳至主要内容

SLF4J Introduction(1): Basic

Introduction

SLF4J is a very commonly used log library in many Java application. It is favored because it allows the end-user to plug in the desired logging framework at deployment time.

How is this feature implemented? How to use it? Let’s continue.

Binding

API & Implementation

SLF4J library has two main parts: api and implementations. Its implementations are referred as bindings.

In order to use SLF4J we have to both the api jar and bindings. We can replace slf4j bindings on our class path to switch logging frameworks.

If we start a project with only slf4j-api-x.jar dependency, we will see the following warning:

SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.

This is because if no binding is found on the class path, SLF4J will default to a no-operation implementation.

Change Binding

From the SLF4J doc:

SLF4J does not rely on any special class loader machinery. In fact, each SLF4J binding is hardwired at compile time to use one and only one specific logging framework.

And this can be verified from the LoggerFactory source code:

StaticLoggerBinder.getSingleton().getLoggerFactory();

So, if we want to change the bindings, we can simply replace original implementation with another one. This is very useful if we want to use different logging system in test and in production, or our project will be used as a library.

What should be noticed is that, in addition to slf4j-api-x.jar, we can simply drop one and only one binding of our choice onto the appropriate class path location. Placing more than one binding on class path will causing a warning emitted by SLF4J. But, even when multiple bindings are present, SLF4J will pick one logging framework/implementation and bind with it. The way SLF4J picks a binding is determined by the JVM and should be considered random.

Logger Hierarchy

Like other Java logging system, SLF4J has parent-child log hierarchy:

At the top of the hierarchy exists a root logger. The root logger exists outside the scope of any custom logger hierarchy that we may come up with. It always exists as the root logger for all possible logger hierarchies, and it has no namespace. All the other application-specific Logger objects are child objects to the root logger. The parent-child relationship of loggers signifies the dependency of the loggers acting within the same application.

And this can be seen from the source code logback.classic.Logger:

/**
 * The parent of this category. All categories have at least one ancestor
 * which is the root category.
 */
transient private Logger parent;
/**
 * The children of this logger. A logger may have zero or more children.
 */
transient private List<Logger> childrenList;

Down to Child Logger

When we have the parent-child hierarchy, what can we get from parent logger?

A child logger can inherit properties from its parent logger recursively up the tree. Typically, a child logger will inherit the following properties from its parent logger(s):

  • Level: If the child logger has no explicit tree level specified, it will use the level of its closest parent or the first proper level it finds recursively up the hierarchy.
  • Appender: If there is no appender attached to a logger, the child logger uses the appender of its closest parent logger or the first appender it finds recursively up the tree.
  • ResourceBundle: ResourceBundles are key-value pattern properties files used for the localization of logging messages. A child logger inherits any ResourceBundle associated with its parent logger.

And also can be seen from source:

// The effective levelInt is the assigned levelInt and if null, a levelInt is
// inherited form a parent.
transient private int effectiveLevelInt;

Up to Father Logger

When we log, the event will go up to the father logger. But sometimes, we don’t want to share a private log, we can forbid the propagation of the log event by setting additive.

Ref

Written with StackEdit.

评论

此博客中的热门博文

Spring Boot: Customize Environment

Spring Boot: Customize Environment Environment variable is a very commonly used feature in daily programming: used in init script used in startup configuration used by logging etc In Spring Boot, all environment variables are a part of properties in Spring context and managed by Environment abstraction. Because Spring Boot can handle the parse of configuration files, when we want to implement a project which uses yml file as a separate config file, we choose the Spring Boot. The following is the problems we met when we implementing the parse of yml file and it is recorded for future reader. Bind to Class Property values can be injected directly into your beans using the @Value annotation, accessed via Spring’s Environment abstraction or bound to structured objects via @ConfigurationProperties. As the document says, there exists three ways to access properties in *.properties or *.yml : @Value : access single value Environment : can access multi

Elasticsearch: Join and SubQuery

Elasticsearch: Join and SubQuery Tony was bothered by the recent change of search engine requirement: they want the functionality of SQL-like join in Elasticsearch! “They are crazy! How can they think like that. Didn’t they understand that Elasticsearch is kind-of NoSQL 1 in which every index should be independent and self-contained? In this way, every index can work independently and scale as they like without considering other indexes, so the performance can boost. Following this design principle, Elasticsearch has little related supports.” Tony thought, after listening their requirements. Leader notice tony’s unwillingness and said, “Maybe it is hard to do, but the requirement is reasonable. We need to search person by his friends, didn’t we? What’s more, the harder to implement, the more you can learn from it, right?” Tony thought leader’s word does make sense so he set out to do the related implementations Application-Side Join “The first implementation

Implement isdigit

It is seems very easy to implement c library function isdigit , but for a library code, performance is very important. So we will try to implement it and make it faster. Function So, first we make it right. int isdigit ( char c) { return c >= '0' && c <= '9' ; } Improvements One – Macro When it comes to performance for c code, macro can always be tried. #define isdigit (c) c >= '0' && c <= '9' Two – Table Upper version use two comparison and one logical operation, but we can do better with more space: # define isdigit(c) table[c] This works and faster, but somewhat wasteful. We need only one bit to represent true or false, but we use a int. So what to do? There are many similar functions like isalpha(), isupper ... in c header file, so we can combine them into one int and get result by table[c]&SOME_BIT , which is what source do. Source code of ctype.h : # define _ISbit(bit) (1 << (