Long long ago, when there is not any mature logging system, Tom is facing the problem of logging. The native logging system form Java SDK has some issues of class loading, in which it may cause memory leaks1.
The first concept is the class which used to log by different packages and classes. Considering its functionality, tom would like to call it
"
“We do similar things about the format requirement. We can have a
The final requirement is to control the logging level.
"This is easy. We can define a enum[^enmu] which has five priorities:
“Em, I don’t know.”
“The abstraction should be isolated, or in other words, the design should be orthogonal.”
“Isolated? Orthogonal?”
"Yes, have you noticed that the requirement of
“Once we make our abstractions isolated from each other, they can change in their own dimension and not affect others.” The leader concluded.
Requirement
He discussed this problem with leader and they decided to write their own logging system with the following requirements:- The logging system can be used by different package, class at the same time and we can easily differentiate them;
- The logging system can output to different location, for example, console, file or even network;
- The logging system can output formatted log content: plain text, JSON, XML etc;
- The logging system can have different levels to control the behavior in different environments: in development env, we can log more, but in production env, we maybe log only exception;
Design
Tom now begin to analyze the requirements of logging system using OO related patterns and try to make some basic abstraction from them.The first concept is the class which used to log by different packages and classes. Considering its functionality, tom would like to call it
Logger
. In order to differentiate them, we can give Logger
a unique name. But how to ensure the uniqueness of this name? The UUID
is the first idea come up to his mind."
UUID
seems will not be duplicate in a application with not so much logger, but the readability is so bad. What about the class name? Great idea!" A inspiration is caught by Tom.Logger logger = new Logger("com.foo");
The next requirement is the output destination: console, file etc. This is relative easy, an abstract class with multiple subclass can solve the problem. Considering we always append the log entry to this destination, we can call them Appender
.“We do similar things about the format requirement. We can have a
Layout
interface class and XMLLayout
, HTMLLayout
, PatternLayout
implementations.” Tom thought.public String getHeader();
public String getFooter();
public String doLayout(LogEntry e);
"Oh, It seems that we didn’t define a class represent logging entry. So we call it LoggingEvent
".The final requirement is to control the logging level.
"This is easy. We can define a enum[^enmu] which has five priorities:
TRACE
, DEBUG
, INFO
, WARN
, ERROR
and add set a level in logger to control. We can even add some utility method like trace
, debug
to avoid explicit level check by user.public void trace(String msg);
public void debug(String msg);
Relationship
Now, Tom think he need to make the relationship between those classes more clear. He analyzed as following:Logger -- Destination: 1 vs n
Destination -- Layout: 1 vs 1
Logger -- Layout: 1 vs n
Logger -- Level: 1 vs 1
So the class relationship can be organized like this:Design Principle
When tom bring the design to leader, leader is very satisfied. He said, “Great job! One more question, do you get some design principle from this tasks?”“Em, I don’t know.”
“The abstraction should be isolated, or in other words, the design should be orthogonal.”
“Isolated? Orthogonal?”
"Yes, have you noticed that the requirement of
Logger
, Appender
and Layout
is in different dimension? Changing the requirement of one of them will not affect others. If we need another output target like email, we can simple add a SMTPAppender
and no other abstraction will be affected.“Once we make our abstractions isolated from each other, they can change in their own dimension and not affect others.” The leader concluded.
Postscript
The logging system referred in this blog is SLF4J and Logback, and the tom is Ceki Gülcü who developed SLF4J, Log4j and Logback. We just talked about some basic design decisions of logging systems, and there exists many other things that we don’t cover:- Logger hierarchy and inheritance: level & resource & appender
- Target level & Filter
- Layout & Encoder
Ref
Written with StackEdit.
评论
发表评论