I see... I thought the most common use case would be adding custom levels, but I see now that /taking away existing levels/ is also a use case. Perhaps that should be a separate code-gen tool, which generates an interface (& impl) that does not extend from Logger.
One advantage of having the custom logger interface extend Logger is that the object can be passed to any method that accepts a Logger... I'm beginning to think these use cases may need to be supported separately. On Mon, Jan 27, 2014 at 11:51 PM, 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 >> >>