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