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 
> first call to LogManager.getCustomLogger(MyLogger.class), the MyLogger 
> instance is created and cached. Also, at this point the annotations are 
> parsed to see what Level instance the MyLogger implementation will pass to 
> the Logger.log(Level, String) method when the "diag" method is called. 
> 
> What is still open in this scenario is how the instance is created. Proxy? Or 
> generate source & compile? Or use a byte code library?
> 
> On Monday, January 27, 2014, Ralph Goers <ralph.go...@dslextreme.com> wrote:
> I am going to have to echo what Nick said.  If you can think of a way to make 
> 
> logger.log(SomeClass.SomeLevel, “hello world”);
> 
> work without actually creating SomeClass then please share!
> 
> Ralph
> 
> On Jan 26, 2014, at 7:45 PM, Nick Williams <nicho...@nicholaswilliams.net> 
> wrote:
> 
>> It would not be possible to do this strictly through configuration because 
>> the user needs a compiled interface to code against. Where is that compiled 
>> interface to come from?
>> 
>> Nick
>> 
>> On Jan 26, 2014, at 9:40 PM, Scott Deboy wrote:
>> 
>>> If there is a way to support this strictly through configuration that would 
>>> be ideal.
>>> 
>>> I'm trying to find a way to remove my request for additional built in 
>>> levels but through configuration instead of adding them ourselves.
>>> 
>>> Scott
>>> Scott
>>> 
>>> On Jan 26, 2014 7:38 PM, "Nick Williams" <nicho...@nicholaswilliams.net> 
>>> wrote:
>>> Here's a split-off thread for discussing how we can make using custom 
>>> levels easier. Some on the team have expressed a desire to make it even 
>>> easier. Given hypothetical custom levels DIAG and NOTE, the following would 
>>> be nice to have:
>>> 
>>> logger.note("message");
>>> logger.diag("message");
>>> etc.
>>> 
>>> We're to discuss how best to approach this. My proposal (from previous 
>>> email):
>>> 
>>> > Allow the user to define an interface that /must/ extend Logger. That 
>>> > interface may contain any methods that match the following signatures 
>>> > (the interface must have at least one method and there is no limit to the 
>>> > number of methods it may have):
>>> >
>>> > void [methodName](Marker, Message)
>>> > void [methodName](Marker, Message, Throwable t)
>>> > void [methodName](Marker, Object)
>>> > void [methodName](Marker, Object, Throwable t)
>>> > void [methodName](Marker, String)
>>> > void [methodName](Marker, String, Object...)
>>> > void [methodName](Marker, String throwable)
>>> > void [methodName](Message)
>>> > void [methodName](Message, Throwable t)
>>> > void [methodName](Object)
>>> > void [methodName](Object, Throwable t)
>>> > void [methodName](String)
>>> > void [methodName](String, Object...)
>>> > void [methodName](String throwable)
>>> >
>>> > Each method /must/ be annotated with @LoggingLevel(name = "levelName"). 
>>> > Now LogManager has a few new methods:
>>> >
>>> > <T extends Logger> T getCustomLogger(Class<T> loggerClass)
>>> > <T extends Logger> T getCustomLogger(Class<T> loggerClass, Class<?>)
>>> > <T extends Logger> T getCustomLogger(Class<T> loggerClass, Class<?>, 
>>> > MessageFactory)
>>> > <T extends Logger> T getCustomLogger(Class<T> loggerClass, MessageFactory)
>>> > <T extends Logger> T getCustomLogger(Class<T> loggerClass, Object)
>>> > <T extends Logger> T getCustomLogger(Class<T> loggerClass, Object, 
>>> > MessageFactory)
>>> > <T extends Logger> T getCustomLogger(Class<T> loggerClass, String)
>>> > <T extends Logger> T getCustomLogger(Class<T> loggerClass, String, 
>>> > MessageFactory)
>>> >
>>> > The user can then obtain such a logger like so, etc.:
>>> >
>>> > MyLogger logger = LogManager.getCustomLogger(MyLogger.class);
>>> >
>>> > Log4j will generate an implementation of MyLogger that extends the 
>>> > default implementation, cache that implementation so that it doesn't have 
>>> > to be implemented again, and then instantiate/cache the logger instance 
>>> > like normal.
>>> 
>>> Others have suggested deriving the level name from the method name instead 
>>> of using an annotation. That's a viable alternative.
>>> 
>>> Matt Sicker asked:
>>> 
>>> > And can't getCustomLogger also provide a default method that uses the 
>>> > getClassName method?
>>> 
>>> I think you misunderstand the purpose of the Class<T> argument. It has 
>>> nothing to do with the logger name--it's the class of the Logger interface 
>>> to automatically implement.
>>> 
>>> Nick
>>> ---------------------------------------------------------------------
>>> To unsubscribe, e-mail: log4j-dev-unsubscr...@logging.apache.org
>>> For additional commands, e-mail: log4j-dev-h...@logging.apache.org
>>> 
>> 
> 

Reply via email to