On Fri, Jan 24, 2014 at 11:48 AM, Remko Popma <remko.po...@gmail.com> wrote:
> Gary, > > The hard-coded levels were proposed because it seemed that the extensible > enum idea raised by Nick was not going to be accepted. > My original position was that Markers could fulfill the requirement but > Nick and yourself made it clear that this was not satisfactory. > > With extensible enums and markers off the table it seemed that the > hard-coded levels was the only alternative, and discussion ensued about > what these levels should be called and what strength they should have. > > During this discussion, several people, including me, repeatedly expressed > strong reservations about adding pre-defined levels, but by this time I > think people were thinking there was no alternative. > > It looked like we were getting stuck, with half the group moving in one > direction ("add pre-defined levels!") and the other half wanting to move in > another direction ("don't add pre-defined levels!"). I asked that we > re-reviewed our assumptions and try to reach a solution that would satisfy > all users. > > We then decided to explore the option of using extensible enums again. > This is still ongoing, but I haven't seen anyone arguing against this idea > since we started this thread. > > Hard-coded levels and the extensible enum are different solutions to the > same problem. > Hello All: Absolutely not. See my DEFCON example. Talking about an "extensible enum" is mixing design and implementation, we are talking about 'custom' and/or 'extensible' levels. Custom/Extensible levels can be designed to serve one or all of: - Allow inserting custom levels between built-in levels. - Allow for domain specific levels outside of the concept of built-in levels, the DEFCON example. - Should the custom levels themselves be extensible? Gary > The extensible enum solution satisfies all of us who are opposed to adding > pre-defined levels, while also satisfying the original requirement raised > by Nick and yourself. Frankly I don't understand why you would still want > the pre-defined levels. > > Remko > > > > On Sat, Jan 25, 2014 at 12:53 AM, Gary Gregory <garydgreg...@gmail.com>wrote: > >> On Thu, Jan 23, 2014 at 10:45 PM, Remko Popma <remko.po...@gmail.com>wrote: >> >>> Gary, >>> >>> I think that's a very cool idea! >>> Much more flexible, powerful and elegant than pre-defined levels could >>> ever be. >>> >> >> As I wrote: "I am discussing custom levels here with the understanding >> that this is a separate topic from what the built-in levels are." >> >> I'm not sure why you want to make the features mutually exclusive. (Some) >> others agree that these are different features. >> >> I see two topics: >> >> - What are the default levels for a 21st century logging framework. Do we >> simply blindly copy Log4j 1? Or do we look at frameworks from different >> languages and platforms for inspiration? >> - How (not if, I think we all agree) should we allow for custom levels. >> >> Gary >> >> 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>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>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> >>>>>> 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 | 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 >>>> >>> >> >> >> -- >> E-Mail: garydgreg...@gmail.com | 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 >> > > -- E-Mail: garydgreg...@gmail.com | 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