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 >