Yeah, I was thinking the same thing as you.

Ralph

On Jan 27, 2014, at 11:15 AM, Nick Williams <nicho...@nicholaswilliams.net> 
wrote:

> I would veto such a change, and here is my technical justification:
> 
> You will break EVERYTHING currently using the Log4j 2 API.
> 
> EVERYTHING that EVERY Log4j 2 user has currently written will have to be 
> changed to use StandardLogger instead of Logger. That's not even considering 
> the fact that Logger (or ILogger as the case may be) is *the* industry 
> standard for logger interface names that provide info(), warn(), and other 
> methods. I know that APIs can change when something's still beta, but this is 
> a HUGE CHANGE.
> 
> However, what I WOULD be okay with is creating a SimpleLogger interface for 
> things like log(Level, ...), etc. and having Logger extend SimpleLogger to 
> provide info(), warn(), and so on. This would be backwards compatible and 
> abide by industry norms.
> 
> Nick
> 
> On Jan 27, 2014, at 12:46 PM, Gary Gregory wrote:
> 
>> On Mon, Jan 27, 2014 at 10:24 AM, Paul Benedict <pbened...@apache.org> wrote:
>> I propose this:
>> 
>> 1) If you are willing to view standard levels as a type of DSL, then you 
>> should refactor the Logger interface to separate those concerns. Create a 
>> new superinterface that contains everything else. This is what custom 
>> loggers will extend.
>> 
>> That's brilliant! The Logger interface contains methods like log(Level, ...) 
>> and StandardLogger extends Logger to provide info(), warn() and so on.
>> 
>> This let's me create a custom Logger (DEFCON example) AND an extension to 
>> StandardLogger with refined levels (NOTICE, DIAG, VERBOSE).
>> 
>> This makes it clear that a Custom Logger is different than an Extensible 
>> Logger to StandardLogger.
>> 
>> Gary
>> 
>> 
>> 2) The customer loggers not only register an interface but also the 
>> implementation that goes with it.
>> 
>> 3) Retrieve a custom logger as follows:
>> <T extends LoggerSuperInterface> T Logger.getCustomLogger(T t);
>> 
>> Paul
>> 
>> 
>> On Mon, Jan 27, 2014 at 8:51 AM, Gary Gregory <garydgreg...@gmail.com> wrote:
>> I also want to avoid extending Logger for domain specific applications. For 
>> medical devices for example I could only have critical, warning, advisory.
>> 
>> 
>> -------- Original message --------
>> From: Remko Popma 
>> Date:01/27/2014 09:15 (GMT-05:00) 
>> To: Log4J Developers List 
>> Subject: Re: Using Custom Levels with a Custom/Wrapper Interface 
>> 
>> How about starting with something very simple at first?
>> 
>> We provide a tool that generates the source code for a custom logger 
>> interface.
>> To invoke the tool the user passes it the fully qualified name of the 
>> interface, and a list of NAME=INTLEVEL custom log levels.
>> The generated source code contains both the interface and an implementation. 
>> The implementation is an inner class of the interface (so users only need to 
>> manage one single file).
>> The generated interface is annotated with the class name of the 
>> implementation class.
>> 
>> At runtime, users call LogManager.getCustomLogger(Class, String) to get a 
>> custom logger instance.
>> The LogManager then uses the annotation on the interface class to 
>> instantiate objects of the implementation class.
>> 
>> 
>> Example tool invocation:
>> java org.apache.logging.log4j.util.Generate com.mycomp.myproject.MyLogger 
>> DIAG=350 NOTICE=450 VERBOSE=550
>> 
>> 
>> Generated code:
>> 
>> @CustomLoggerImplementation(MyLogger.Impl.class)
>> public interface MyLogger extends Logger {
>>     void diag(Marker marker, Message msg);
>>     void diag(Marker marker, Message msg, Throwable t);
>>      // ... other methods
>>      
>>      public static final class Impl extends AbstractLoggerWrapper implements 
>> MyLogger {
>>      private final static Level DIAG = Level.getOrCreateLevel("DIAG", 350);
>>      private final static Level NOTICE = Level.getOrCreateLevel("NOTICE", 
>> 450);
>>      private final static Level VERBOSE = Level.getOrCreateLevel("VERBOSE", 
>> 550);
>> 
>>      public Impl(final AbstractLogger logger) {
>>              super(logger, logger.getName(), logger.getMessageFactory());
>>      }
>> 
>>      public void diag(Marker marker, Message msg) {
>>              logger.log(DIAG, marker, msg);
>>      }
>> 
>>      public void diag(Marker marker, Message msg, Throwable t) {
>>              logger.log(DIAG, marker, msg, t);
>>      }
>> 
>>              // ... other methods
>>      }
>> }
>> 
>> 
>> LogManager:
>> public static <T extends Logger> T getCustomLogger(Class<T> cls, String 
>> name) {
>>      Logger wrapped = getLogger(name);
>>      return wrap(cls, wrapped);
>> }
>> 
>> private static <T extends Logger> T wrap(Class<T> cls, Logger wrapped) {
>>      CustomLoggerImplementation annotation = 
>> cls.getAnnotation(CustomLoggerImplementation.class);
>>      Class<?> implClass = annotation.value();
>>      try {
>>              Constructor<?> constr = implClass.getConstructor(Logger.class);
>>              return (T) constr.newInstance(wrapped);
>>      } catch (Exception ex) {
>>              throw new IllegalStateException(
>>                              "Unable to construct instance of custom logger 
>> class "
>>                                              + implClass.getName(), ex);
>>      }
>> }
>> 
>> 
>> On Monday, January 27, 2014, Scott Deboy <scott.de...@gmail.com> wrote:
>> I know we can't do what I would like via configuration.  My point was to 
>> primarily to spark discussion on how we could make the api as simple as 
>> possible.
>> 
>> I'm ok with where we are on the custom level support.
>> 
>> I do think this brings us back around to adding built in levels, in a 
>> separate thread.
>> 
>> I'm really pleased with how things are coming together. Good stuff.
>> 
>> Scott
>> 
>> On Jan 26, 2014 9:25 PM, "Nicholas Williams" <nicho...@nicholaswilliams.net> 
>> wrote:
>> Yes, I was saying that. But, unless I'm misunderstanding, Scott doesn't want 
>> the user to even have to write the interface. He wants them to just 
>> configure it and the interface become available "magically." I was pointing 
>> out that there's a disconnect between when the configuration is used 
>> (runtime) and when the user needs the interface (compile time). 
>> 
>> Unless we provide a code-generation tool for the user to run from the 
>> command line or from Ant/Maven/Gradle, they're going to have to write the 
>> interface themselves.
>> 
>> Nick
>> 
>> Sent from my iPhone, so please forgive brief replies and frequent typos
>> 
>> On Jan 26, 2014, at 22:49, Remko Popma <remko.po...@gmail.com> wrote:
>> 
>>> Nick, I thought that you meant that users would provide their own 
>>> interface, like this:
>>> public interface MyLogger extends Logger {
>>>     @LoggingLevel(name="DIAG")
>>>     void diag(String message);
>>>     // optional other methods
>>> }
>>> 
>>> That way, this interface exists at compile time. 
>>> 
>>> On Monday, January 27, 2014, Nicholas Williams 
>>> <nicho...@nicholaswilliams.net> wrote:
>>> Scott, invokedynamic and javassist...those are all /runtime/ things. The 
>>> user needs Logger#notice to be available at compile time. Those are not 
>>> compatible.
>>> 
>>> Nick
>>> 
>>> Sent from my iPhone, so please forgive brief replies and frequent typos
>>> 
>>> > On Jan 26, 2014, at 22:37, Scott Deboy <scott.de...@gmail.com> wrote:
>>> >
>>> > Yes, I would like to declare in the config:
>>> >
>>> > Level: NOTICE, value: 232
>>> >
>>> > And in Java code be able to use logger.notice("some message").
>>> >
>>> > But I think that'd require invokedynamic..which would probably
>>> > require..javassist/ASM?
>>> >
>>> > I'd be ok with anything that's really close to that :)
>>> >
>>> > Scott
>>> >
>>> >
>>> >> On 1/26/14, Ralph Goers <ralph.go...@dslextreme.com> wrote:
>>> >> Scott would like users to add a level definition to the logging
>>> >> configuration and have everything else happen auto-magically.  That would
>>> >> happen at run-time which is a bit late since the methods need to be
>>> >> available at compile time.
>>> >>
>>> >> I believe Scott said he would be fine if users had to do
>>> >>
>>> >> logger.log(SomeClass.SomeLevel, "message);
>>> >>
>>> >> but even that requires "SomeClass" to be available at compile time.
>>> >>
>>> >> So what Scott says he would like and what Nick is proposing are two
>>> >> different things.
>>> >>
>>> >> Ralph
>>> >>
>>> >>
>>> >>
>>> >>> On Jan 26, 2014, at 8:09 PM, Remko Popma <remko.po...@gmail.com> wrote:
>>> >>>
>>> >>> I actually thought that Nick's idea was the answer to that: users 
>>> >>> create a
>>> >>> custom interface, something like this:
>>> >>>
>>> >>> public interface MyLogger extends Logger {
>>> >>>    @LoggingLevel(name="DIAG")
>>> >>>    void diag(String message);
>>> >>>    // optional other methods
>>> >>> }
>>> >>>
>>> >>> They get an instance of this interface by calling:
>>> >>> LogManager.getCustomLogger(MyLogger.class);
>>> >>>
>>> >>> LogManager has access to the processed configuration. The config has
>>> >>> <Levels><Level name="DIAG" intValue="450"> elements. During 
>>> >>> configuration
>>> >>> processing, the custom Level instances are created and registered, so on
>>> >>> the firs
>> 
>> 
>> 
>> -- 
>> Cheers,
>> Paul
>> 
>> 
>> 
>> -- 
>> E-Mail: garydgreg...@gmail.com | ggreg...@apache.org 
>> Java Persistence with Hibernate, Second Edition
>> JUnit in Action, Second Edition
>> Spring Batch in Action
>> Blog: http://garygregory.wordpress.com 
>> Home: http://garygregory.com/
>> Tweet! http://twitter.com/GaryGregory
> 

Reply via email to