Gary, I think that's a very cool idea! Much more flexible, powerful and elegant than pre-defined levels could ever be. It definitely makes sense to design the extensible enum with this potential usage in mind.
Remko On Friday, January 24, 2014, Gary Gregory <garydgreg...@gmail.com> wrote: > 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 > <pbened...@apache.org<javascript:_e({}, 'cvml', 'pbened...@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.po...@gmail.com<javascript:_e({}, 'cvml', 'remko.po...@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 >>> <pbened...@apache.org<javascript:_e({}, 'cvml', 'pbened...@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 >>>> <garydgreg...@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: garydgreg...@gmail.com <javascript:_e({}, 'cvml', > 'garydgreg...@gmail.com');> | ggreg...@apache.org <javascript:_e({}, > 'cvml', 'ggreg...@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 >