Nick, I don't understand your objection. I was not proposing replacing Logger. All I said was extract out a superinterface. Keep Logger usage how it is now, if you want -- and what I am recommending.
On Mon, Jan 27, 2014 at 1:15 PM, 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<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 > > > -- Cheers, Paul