logging-log4j-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Gary Gregory <garydgreg...@gmail.com>
Subject Re: Enums and Custom Levels
Date Fri, 24 Jan 2014 01:22:36 GMT
I am discussing custom levels here with the understanding that this is a
separate topic from what the built-in levels are. Here is how I convinced
myself that custom levels are a “good thing”.

No matter which built-in levels exits, I may want custom levels. For
example, I want my app to use the following levels DEFCON1, DEFCON2,
DEFCON3, DEFCON4, and DEFCON5. This might be for one part of my app or a
whole subsystem, no matter, I want to use the built-in levels in addition
to the DEFCON levels. It is worth mentioning that if I want that feature
only as a user, I can “skin” levels in a layout and assign any label to the
built-in levels. If I am also a developer, I want to use DEFCON levels in
the source code.


At first, my code might look like:


logger.log(DefconLevels.DEFCON5, “All is quiet”);


Let’s put aside for now the type of DefconLevels.DEFCON* objects. I am a
user, and I care about my call sites.


What I really want of course is to write:


defconLogger.defcon5(“All is quiet”)


Therefore, I argue that for any “serious” use of a custom level, I will
wrap a Logger in a custom logger class providing call-site friendly methods
like defcon5(String).


So now, as a developer, all I care about is DefConLogger. It might wrap (or
subclass) the Log4J Logger, who knows. The implementation of DefConLogger
is not important to the developer (all I care is that the class has
‘defconN’ method) but it is important to the configuration author. This
tells me that as a developer I do not care how DefConLogger is implemented,
with custom levels, markers, or elves. However, as configuration author, I
also want to use DEFCON level just like the built-in levels.


The configuration code could allow hiding the fact that markers (or elves)
are used so that the configuration looks like a normal configuration. Maybe
a markerLevel attribute is used, who knows. The point is that this is now
getting too complicated and too clever. Bottom line: real custom levels
(not hidden through markers and definitively not elves) are needed to
cleanly implement the custom level feature.


Now, I am convinced that custom levels are needed and useful.


Next up is how to implement them, a different story… but still based on the
fact that I want a DefConLogger class, that’s my user story. First, the
obvious, it would be nice to have:


public enum DefConLevel { DEFCON1, DEFCON2, DEFCON3, DEFCON4, DEFCON5 }


The order would determine the precedence from most to least important
level. The enum might not be strictly needed (at first at least) since I
80/20 care about methods on DefConLogger, not how it works internally.


So how do I write DefConLogger?


Wouldn’t it be nice to be able to write:


@CustomLogger(levels=DefConLevel.class)
public class DefConLogger {}


And have Log4J generate the boiler plate code (If you have the right magic
hooked up in your IDE)? It might generate bytecodes directly, not sure.
There are all sorts of code BC and generation possibilities with ASM, BCEL
or a code generator.


That still leaves the implementation TDB but then it really does not matter
how we do it, as long as we do the dirty work for the user.


Well, we care about the implementation on this ML of course.


Gary


On Wed, Jan 22, 2014 at 10:05 PM, Paul Benedict <pbenedict@apache.org>wrote:

> As Gary wanted, a new thread....
>
> First, each enum needs an inherit strength. This would be part of the
> interface. Forgive me if the word "strength" is wrong; but it's the 100,
> 200, 300, etc. number that triggers the log level. So make sure the
> interface contains the intLevel() method.
>
> Second, we need to know the name, right? The name probably requires a new
> method since it can't be extracted from the enum anymore.
>
> public interface Level {
> int intLevel();
> String name();
> }
>
> PS: The intStrength() name seems hackish. What about strength() or
> treshold()?
>
> Third, the registration can be done manually by providing a static method
> (as your did Remko) that the client needs to invoke, or you could have a
> class-path scanning mechanism. For the latter, you could introduce a new
> annotation to be placed on the enum class.
>
> @CustomLevels
> public enum MyCustomEnums {
> }
>
> Paul
>
> On Wed, Jan 22, 2014 at 8:52 PM, Remko Popma <remko.popma@gmail.com>wrote:
>
>> Paul, can you give a bit more detail?
>>
>> I tried this: copy the current Level enum to a new enum called "Levels"
>> in the same package (other name would be fine too). Then change Level to
>> an interface (removing the constants and static methods, keeping only the
>> non-static methods). Finally make the Levels enum implement the Level
>> interface.
>>
>> After this, we need to do a find+replace for the references to
>> Level.CONSTANT to Levels.CONSTANT and Level.staticMethod() to
>> Levels.staticMethod().
>>
>> Finally, the interesting part: how do users add or register their custom
>> levels and how do we enable the Levels.staticLookupMethod(String, Level) to
>> recognize these custom levels?
>>
>>
>>
>> On Thursday, January 23, 2014, Paul Benedict <pbenedict@apache.org>
>> wrote:
>>
>>> Agreed. This is not an engineering per se, but really more about if the
>>> feature set makes sense.
>>>
>>> Well if you guys ever look into the interface idea, you'll give log4j
>>> the feature of getting enums to represent custom levels. That's pretty
>>> cool, IMO. I don't know if any other logging framework has that and that
>>> would probably get some positive attention. It shouldn't be so hard to do a
>>> find+replace on the code that accepts Level and replace it with another
>>> name. Yes, there will be some minor refactoring that goes with it, but
>>> hard? It shouldn't be.
>>>
>>> A name I propose for the interface is LevelDefinition.
>>>
>>> Paul
>>>
>>>
>>> On Wed, Jan 22, 2014 at 6:48 PM, Gary Gregory <garydgregory@gmail.com>wrote:
>>>
>>> Hi, I do not see this as an engineering problem but more a feature set
>>> definition issue. So while there may be lots of more or less internally
>>> complicated ways of solving this with interfaces, makers and whatnots, the
>>> built in levels are the most user friendly.
>>>
>>> I have have lots of buttons, knobs and settings on my sound system that
>>> I do not use, just like I do not use all the methods in all the classes in
>>> the JRE...
>>>
>>> Gary
>>>
>>>
>


-- 
E-Mail: garydgregory@gmail.com | ggregory@apache.org
Java Persistence with Hibernate, Second Edition<http://www.manning.com/bauer3/>
JUnit in Action, Second Edition <http://www.manning.com/tahchiev/>
Spring Batch in Action <http://www.manning.com/templier/>
Blog: http://garygregory.wordpress.com
Home: http://garygregory.com/
Tweet! http://twitter.com/GaryGregory

Mime
View raw message