Re: Using Custom Levels with a Custom/Wrapper Interface

2014-01-29 Thread Remko Popma
On Wednesday, January 29, 2014, Nick Williams nicho...@nicholaswilliams.net
wrote:


 On Jan 28, 2014, at 5:43 PM, Remko Popma wrote:

 I would really like everyone's feedback on this. I have two questions:

 1. Does this fulfill everyone's requirements?
 Another way of asking this is: would you use this in your own projects?
 (If not, why not?)


 Personally, no. I don't like the code generation for IDE integration
 issues. I'd prefer an interface I wrote.


I'm not sure what you mean by IDE integration issues, but let's not lose
sight of why we are doing this in the first place: we want to provide
convenience methods to make custom levels as easy to use as built-in
levels.
I'm beginning to feel that we are adding additional requirements on top of
this that make it difficult to achieve our original goal...


 2. What do you think of this approach?
 Obviously code generation has drawbacks. For one thing, IDE refactoring
 tools don't work and API changes don't cause compile errors in the
 generator itself, only in the generated code. (I plan to add a JUnit test
 that generates a custom logger, compiles it and executes the custom logging
 methods so we can at least catch issues during the build.)
 The advantage is that it is open-ended and can deal with any custom level
 users can dream up.

 Is this trade-off acceptable?
 Are there other ways to solve this?


 Also IMO, I would tend to steer away from only generating a concrete
 class. The interface and implementation should be separate. Imagine a Log4j
 fixing a bug in the generation code and releasing 2.0.1 or whatever. Now
 the user has a generated implementation, so they can't /just/ upgrade their
 Maven dependency. They /also/ have to re-generate their code. That's a
 pain. However, with the interface and implementation separate, the
 interface probably doesn't have to change, and the implementation will
 change as soon as they fire up their app with the latest Log4j.

 Also, if you separate the interface and implementation, you can make the
 generation of the interface optional. The user can /choose/ whether to
 generate the interface or create the interface themselves. Then the
 implementation generates at runtime.


My original intuition was also to start with a separate interface and
implementation but as I was thinking about what is the simplest thing that
could possibly work? I ended up with this design. Please don't dismiss
this solution just because it is based on a concrete class.

Generating an implementation at runtime just seems so much more complex. It
involves inspecting the signature of every method on the interface to see
which Logger.log(Level, ...) method it should be mapped to. And what is
there is no match? We would need to throw an IllegalArgumentException at
runtime. This problem does not exist with the concrete class.

I've taken a look at ASM (http://asm.ow2.org/) to generate byte
code on-the-fly but I have kind of given up on that idea. (If anyone else
wants to take this on please feel free but it seems the result may
be fragile and difficult to maintain.)

The alternative is probably annotation processing. This is interesting
stuff and I look forward to taking a closer look into this in the next week
or so. But just looking at the API, simple is not the word that comes to
mind. :-)
Also be aware that generating an implementation class at runtime would
require users to have tools.jar in the classpath so we can compile the
generated implementation class source code at runtime. The concrete class
does not need additional jars.

So there's a bunch of trade-offs here. I'd like to understand annotation
processing a bit better first, but I still think the simplicity of the
concrete class has a lot of appeal.



 Nick


 Remko

 On Tuesday, January 28, 2014, Remko Popma remko.po...@gmail.com wrote:

 I created https://issues.apache.org/jira/browse/LOG4J2-519 for this.
 Feedback welcome.

 On Tuesday, January 28, 2014, Remko Popma remko.po...@gmail.com wrote:

 I've started to work on implementing a source code generator along the
 lines described below.

 Does anyone disagree with this approach?

 I was thinking to name the tools Generate$ExtendedLogger and
 Generate$CustomLogger and put the Generate class in the log4j-api project
 under org.apache.logging.log4j.util or create a new package called
 org.apache.logging.log4j.experimental.

 Thoughts?

 On Tuesday, January 28, 2014, Remko Popma remko.po...@gmail.com wrote:

 More thoughts on CustomLogger/ExtendedLogger source code generation:

 Perhaps I was overcomplicating things...
 Why don't we generate source for a concrete class instead of an
 interface+implementation?

 If users want to /extend/ Logger, this class would extend
 AbstractLoggerWrapper (which has the standard debug(), info(), warn(), ...
 methods).

 If users want to hide the standard methods, the generated class would
 simply not extend AbstractLoggerWrapper, so the only public methods would
 be the generated 

Re: Using Custom Levels with a Custom/Wrapper Interface

2014-01-29 Thread Matt Sicker
Annotation processing is beyond over-engineered, yet it still lacks some of
the neat features from runtime annotation processing. I've been meaning
to look more into it as it might be useful for injecting Loggers using
annotations.


On 29 January 2014 07:46, Remko Popma remko.po...@gmail.com wrote:



 On Wednesday, January 29, 2014, Nick Williams 
 nicho...@nicholaswilliams.net wrote:


 On Jan 28, 2014, at 5:43 PM, Remko Popma wrote:

 I would really like everyone's feedback on this. I have two questions:

 1. Does this fulfill everyone's requirements?
 Another way of asking this is: would you use this in your own projects?
 (If not, why not?)


 Personally, no. I don't like the code generation for IDE integration
 issues. I'd prefer an interface I wrote.


 I'm not sure what you mean by IDE integration issues, but let's not lose
 sight of why we are doing this in the first place: we want to provide
 convenience methods to make custom levels as easy to use as built-in
 levels.
 I'm beginning to feel that we are adding additional requirements on top of
 this that make it difficult to achieve our original goal...


 2. What do you think of this approach?
 Obviously code generation has drawbacks. For one thing, IDE refactoring
 tools don't work and API changes don't cause compile errors in the
 generator itself, only in the generated code. (I plan to add a JUnit test
 that generates a custom logger, compiles it and executes the custom logging
 methods so we can at least catch issues during the build.)
 The advantage is that it is open-ended and can deal with any custom level
 users can dream up.

 Is this trade-off acceptable?
 Are there other ways to solve this?


 Also IMO, I would tend to steer away from only generating a concrete
 class. The interface and implementation should be separate. Imagine a Log4j
 fixing a bug in the generation code and releasing 2.0.1 or whatever. Now
 the user has a generated implementation, so they can't /just/ upgrade their
 Maven dependency. They /also/ have to re-generate their code. That's a
 pain. However, with the interface and implementation separate, the
 interface probably doesn't have to change, and the implementation will
 change as soon as they fire up their app with the latest Log4j.

 Also, if you separate the interface and implementation, you can make the
 generation of the interface optional. The user can /choose/ whether to
 generate the interface or create the interface themselves. Then the
 implementation generates at runtime.


 My original intuition was also to start with a separate interface and
 implementation but as I was thinking about what is the simplest thing that
 could possibly work? I ended up with this design. Please don't dismiss
 this solution just because it is based on a concrete class.

 Generating an implementation at runtime just seems so much more complex.
 It involves inspecting the signature of every method on the interface to
 see which Logger.log(Level, ...) method it should be mapped to. And what is
 there is no match? We would need to throw an IllegalArgumentException at
 runtime. This problem does not exist with the concrete class.

 I've taken a look at ASM (http://asm.ow2.org/) to generate byte
 code on-the-fly but I have kind of given up on that idea. (If anyone else
 wants to take this on please feel free but it seems the result may
 be fragile and difficult to maintain.)

 The alternative is probably annotation processing. This is interesting
 stuff and I look forward to taking a closer look into this in the next week
 or so. But just looking at the API, simple is not the word that comes to
 mind. :-)
 Also be aware that generating an implementation class at runtime would
 require users to have tools.jar in the classpath so we can compile the
 generated implementation class source code at runtime. The concrete class
 does not need additional jars.

 So there's a bunch of trade-offs here. I'd like to understand annotation
 processing a bit better first, but I still think the simplicity of the
 concrete class has a lot of appeal.



 Nick


 Remko

 On Tuesday, January 28, 2014, Remko Popma remko.po...@gmail.com wrote:

 I created https://issues.apache.org/jira/browse/LOG4J2-519 for this.
 Feedback welcome.

 On Tuesday, January 28, 2014, Remko Popma remko.po...@gmail.com wrote:

 I've started to work on implementing a source code generator along the
 lines described below.

 Does anyone disagree with this approach?

 I was thinking to name the tools Generate$ExtendedLogger and
 Generate$CustomLogger and put the Generate class in the log4j-api project
 under org.apache.logging.log4j.util or create a new package called
 org.apache.logging.log4j.experimental.

 Thoughts?

 On Tuesday, January 28, 2014, Remko Popma remko.po...@gmail.com wrote:

 More thoughts on CustomLogger/ExtendedLogger source code generation:

 Perhaps I was overcomplicating things...
 Why don't we generate source for a concrete class instead of an
 

Re: Using Custom Levels with a Custom/Wrapper Interface

2014-01-29 Thread Paul Benedict
I would like to propose not doing anything on this subject until there is a
request from the community. It's probably way too easy to over-engineer and
devise solutions to problems that a small percentage (or zero?) of the
users will need. I am all for ingenuity and passion, but after GA occurs
and there's no experience with custom levels directly, we might get a
better idea what the right answer is.

So slate this for 2.x in JIRA and let's get to GA.


On Wed, Jan 29, 2014 at 4:53 PM, Matt Sicker boa...@gmail.com wrote:

 Annotation processing is beyond over-engineered, yet it still lacks some
 of the neat features from runtime annotation processing. I've been
 meaning to look more into it as it might be useful for injecting Loggers
 using annotations.


 On 29 January 2014 07:46, Remko Popma remko.po...@gmail.com wrote:



 On Wednesday, January 29, 2014, Nick Williams 
 nicho...@nicholaswilliams.net wrote:


 On Jan 28, 2014, at 5:43 PM, Remko Popma wrote:

 I would really like everyone's feedback on this. I have two questions:

 1. Does this fulfill everyone's requirements?
 Another way of asking this is: would you use this in your own projects?
 (If not, why not?)


 Personally, no. I don't like the code generation for IDE integration
 issues. I'd prefer an interface I wrote.


 I'm not sure what you mean by IDE integration issues, but let's not lose
 sight of why we are doing this in the first place: we want to provide
 convenience methods to make custom levels as easy to use as built-in
 levels.
 I'm beginning to feel that we are adding additional requirements on top
 of this that make it difficult to achieve our original goal...


 2. What do you think of this approach?
 Obviously code generation has drawbacks. For one thing, IDE refactoring
 tools don't work and API changes don't cause compile errors in the
 generator itself, only in the generated code. (I plan to add a JUnit test
 that generates a custom logger, compiles it and executes the custom logging
 methods so we can at least catch issues during the build.)
 The advantage is that it is open-ended and can deal with any custom
 level users can dream up.

 Is this trade-off acceptable?
 Are there other ways to solve this?


 Also IMO, I would tend to steer away from only generating a concrete
 class. The interface and implementation should be separate. Imagine a Log4j
 fixing a bug in the generation code and releasing 2.0.1 or whatever. Now
 the user has a generated implementation, so they can't /just/ upgrade their
 Maven dependency. They /also/ have to re-generate their code. That's a
 pain. However, with the interface and implementation separate, the
 interface probably doesn't have to change, and the implementation will
 change as soon as they fire up their app with the latest Log4j.

 Also, if you separate the interface and implementation, you can make the
 generation of the interface optional. The user can /choose/ whether to
 generate the interface or create the interface themselves. Then the
 implementation generates at runtime.


 My original intuition was also to start with a separate interface and
 implementation but as I was thinking about what is the simplest thing that
 could possibly work? I ended up with this design. Please don't dismiss
 this solution just because it is based on a concrete class.

 Generating an implementation at runtime just seems so much more complex.
 It involves inspecting the signature of every method on the interface to
 see which Logger.log(Level, ...) method it should be mapped to. And what is
 there is no match? We would need to throw an IllegalArgumentException at
 runtime. This problem does not exist with the concrete class.

 I've taken a look at ASM (http://asm.ow2.org/) to generate byte
 code on-the-fly but I have kind of given up on that idea. (If anyone else
 wants to take this on please feel free but it seems the result may
 be fragile and difficult to maintain.)

 The alternative is probably annotation processing. This is interesting
 stuff and I look forward to taking a closer look into this in the next week
 or so. But just looking at the API, simple is not the word that comes to
 mind. :-)
 Also be aware that generating an implementation class at runtime would
 require users to have tools.jar in the classpath so we can compile the
 generated implementation class source code at runtime. The concrete class
 does not need additional jars.

 So there's a bunch of trade-offs here. I'd like to understand annotation
 processing a bit better first, but I still think the simplicity of the
 concrete class has a lot of appeal.



 Nick


 Remko

 On Tuesday, January 28, 2014, Remko Popma remko.po...@gmail.com wrote:

 I created https://issues.apache.org/jira/browse/LOG4J2-519 for this.
 Feedback welcome.

 On Tuesday, January 28, 2014, Remko Popma remko.po...@gmail.com wrote:

 I've started to work on implementing a source code generator along the
 lines described below.

 Does anyone disagree with 

Re: Using Custom Levels with a Custom/Wrapper Interface

2014-01-29 Thread Nick Williams
I agree.

Nick

On Jan 29, 2014, at 5:09 PM, Paul Benedict wrote:

 I would like to propose not doing anything on this subject until there is a 
 request from the community. It's probably way too easy to over-engineer and 
 devise solutions to problems that a small percentage (or zero?) of the users 
 will need. I am all for ingenuity and passion, but after GA occurs and 
 there's no experience with custom levels directly, we might get a better idea 
 what the right answer is. 
 
 So slate this for 2.x in JIRA and let's get to GA.
 
 
 On Wed, Jan 29, 2014 at 4:53 PM, Matt Sicker boa...@gmail.com wrote:
 Annotation processing is beyond over-engineered, yet it still lacks some of 
 the neat features from runtime annotation processing. I've been meaning to 
 look more into it as it might be useful for injecting Loggers using 
 annotations.
 
 
 On 29 January 2014 07:46, Remko Popma remko.po...@gmail.com wrote:
 
 
 On Wednesday, January 29, 2014, Nick Williams nicho...@nicholaswilliams.net 
 wrote:
 
 On Jan 28, 2014, at 5:43 PM, Remko Popma wrote:
 
 I would really like everyone's feedback on this. I have two questions:
 
 1. Does this fulfill everyone's requirements?
 Another way of asking this is: would you use this in your own projects? (If 
 not, why not?)
 
 Personally, no. I don't like the code generation for IDE integration issues. 
 I'd prefer an interface I wrote.
 
 I'm not sure what you mean by IDE integration issues, but let's not lose 
 sight of why we are doing this in the first place: we want to provide 
 convenience methods to make custom levels as easy to use as built-in levels. 
 I'm beginning to feel that we are adding additional requirements on top of 
 this that make it difficult to achieve our original goal...
 
 
 2. What do you think of this approach?
 Obviously code generation has drawbacks. For one thing, IDE refactoring 
 tools don't work and API changes don't cause compile errors in the generator 
 itself, only in the generated code. (I plan to add a JUnit test that 
 generates a custom logger, compiles it and executes the custom logging 
 methods so we can at least catch issues during the build.)
 The advantage is that it is open-ended and can deal with any custom level 
 users can dream up. 
 
 Is this trade-off acceptable?
 Are there other ways to solve this?
 
 Also IMO, I would tend to steer away from only generating a concrete class. 
 The interface and implementation should be separate. Imagine a Log4j fixing a 
 bug in the generation code and releasing 2.0.1 or whatever. Now the user has 
 a generated implementation, so they can't /just/ upgrade their Maven 
 dependency. They /also/ have to re-generate their code. That's a pain. 
 However, with the interface and implementation separate, the interface 
 probably doesn't have to change, and the implementation will change as soon 
 as they fire up their app with the latest Log4j.
 
 Also, if you separate the interface and implementation, you can make the 
 generation of the interface optional. The user can /choose/ whether to 
 generate the interface or create the interface themselves. Then the 
 implementation generates at runtime.
 
 My original intuition was also to start with a separate interface and 
 implementation but as I was thinking about what is the simplest thing that 
 could possibly work? I ended up with this design. Please don't dismiss this 
 solution just because it is based on a concrete class. 
 
 Generating an implementation at runtime just seems so much more complex. It 
 involves inspecting the signature of every method on the interface to see 
 which Logger.log(Level, ...) method it should be mapped to. And what is there 
 is no match? We would need to throw an IllegalArgumentException at runtime. 
 This problem does not exist with the concrete class. 
 
 I've taken a look at ASM (http://asm.ow2.org/) to generate byte code 
 on-the-fly but I have kind of given up on that idea. (If anyone else wants to 
 take this on please feel free but it seems the result may be fragile and 
 difficult to maintain.)
 
 The alternative is probably annotation processing. This is interesting stuff 
 and I look forward to taking a closer look into this in the next week or so. 
 But just looking at the API, simple is not the word that comes to mind. :-) 
 Also be aware that generating an implementation class at runtime would 
 require users to have tools.jar in the classpath so we can compile the 
 generated implementation class source code at runtime. The concrete class 
 does not need additional jars. 
 
 So there's a bunch of trade-offs here. I'd like to understand annotation 
 processing a bit better first, but I still think the simplicity of the 
 concrete class has a lot of appeal. 
 
 
 
 Nick
 
 
 Remko
 
 On Tuesday, January 28, 2014, Remko Popma remko.po...@gmail.com wrote:
 I created https://issues.apache.org/jira/browse/LOG4J2-519 for this. 
 Feedback welcome. 
 
 On Tuesday, January 28, 2014, Remko Popma 

Re: Using Custom Levels with a Custom/Wrapper Interface

2014-01-28 Thread Remko Popma
I created https://issues.apache.org/jira/browse/LOG4J2-519 for this.
Feedback welcome.

On Tuesday, January 28, 2014, Remko Popma remko.po...@gmail.com wrote:

 I've started to work on implementing a source code generator along the
 lines described below.


 Does anyone disagree with this approach?


 I was thinking to name the tools Generate$ExtendedLogger and
 Generate$CustomLogger and put the Generate class in the log4j-api project
 under org.apache.logging.log4j.util or create a new package called
 org.apache.logging.log4j.experimental.


 Thoughts?

 On Tuesday, January 28, 2014, Remko Popma 
 remko.po...@gmail.comjavascript:_e({}, 'cvml', 'remko.po...@gmail.com');
 wrote:

 More thoughts on CustomLogger/ExtendedLogger source code generation:


 Perhaps I was overcomplicating things...

 Why don't we generate source for a concrete class instead of an
 interface+implementation?


 If users want to /extend/ Logger, this class would extend
 AbstractLoggerWrapper (which has the standard debug(), info(), warn(), ...
 methods).


 If users want to hide the standard methods, the generated class would
 simply not extend AbstractLoggerWrapper, so the only public methods would
 be the generated methods for the custom log levels.


 This allows users to generate both extended loggers (with extra methods)
 and custom domain specific Loggers (like a logger that only has defcon1(),
 defcon2(), defcon3() methods).


 Note: this would also enable users to /take away/ existing log4j log
 levels.

 Suppose you don't like the FATAL or TRACE log levels?

 Simply generate a custom logger with levels ERROR=200 WARN=300 INFO=400
 DEBUG=500.


 Since this is a wrapper, there is no need for API changes or additional
 methods on LogManager: the generated custom logger has factory methods that
 internally call the existing LogManager.getLogger() methods and wrap the
 resulting Logger.


 So in client code, users would obtain a custom logger this way:

 MyLogger logger = MyLogger.create(MyClass.class);


 Thoughts?



 On Tuesday, January 28, 2014, Gary Gregory garydgreg...@gmail.com
 wrote:

 On Mon, Jan 27, 2014 at 2: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.


 Of course, let's not get caught up in the names here and focus on the
 design first. What matters is that the current interface in split between a
 generic Level agnostic parent and a DSL sub-interface. I agree that 80/20
 says that Logger should be the name of the interface that has info(),
 warn() and so on. The parent can be called LevelLogger for example since it
 must be called with a Level. I do not like SimpleLogger because it does
 not describe anything and 'simple' feels like a judgment call.

 Gary



 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.orgwrote:

 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.comwrote:

 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

Re: Using Custom Levels with a Custom/Wrapper Interface

2014-01-28 Thread Remko Popma
I would really like everyone's feedback on this. I have two questions:

1. Does this fulfill everyone's requirements?
Another way of asking this is: would you use this in your own projects? (If
not, why not?)

2. What do you think of this approach?
Obviously code generation has drawbacks. For one thing, IDE refactoring
tools don't work and API changes don't cause compile errors in the
generator itself, only in the generated code. (I plan to add a JUnit test
that generates a custom logger, compiles it and executes the custom logging
methods so we can at least catch issues during the build.)
The advantage is that it is open-ended and can deal with any custom level
users can dream up.

Is this trade-off acceptable?
Are there other ways to solve this?

Remko

On Tuesday, January 28, 2014, Remko Popma remko.po...@gmail.com wrote:

 I created https://issues.apache.org/jira/browse/LOG4J2-519 for this.
 Feedback welcome.

 On Tuesday, January 28, 2014, Remko Popma remko.po...@gmail.com wrote:

 I've started to work on implementing a source code generator along the
 lines described below.


 Does anyone disagree with this approach?


 I was thinking to name the tools Generate$ExtendedLogger and
 Generate$CustomLogger and put the Generate class in the log4j-api project
 under org.apache.logging.log4j.util or create a new package called
 org.apache.logging.log4j.experimental.


 Thoughts?

 On Tuesday, January 28, 2014, Remko Popma remko.po...@gmail.com wrote:

 More thoughts on CustomLogger/ExtendedLogger source code generation:


 Perhaps I was overcomplicating things...

 Why don't we generate source for a concrete class instead of an
 interface+implementation?


 If users want to /extend/ Logger, this class would extend
 AbstractLoggerWrapper (which has the standard debug(), info(), warn(), ...
 methods).


 If users want to hide the standard methods, the generated class would
 simply not extend AbstractLoggerWrapper, so the only public methods would
 be the generated methods for the custom log levels.


 This allows users to generate both extended loggers (with extra methods)
 and custom domain specific Loggers (like a logger that only has defcon1(),
 defcon2(), defcon3() methods).


 Note: this would also enable users to /take away/ existing log4j log
 levels.

 Suppose you don't like the FATAL or TRACE log levels?

 Simply generate a custom logger with levels ERROR=200 WARN=300 INFO=400
 DEBUG=500.


 Since this is a wrapper, there is no need for API changes or additional
 methods on LogManager: the generated custom logger has factory methods that
 internally call the existing LogManager.getLogger() methods and wrap the
 resulting Logger.


 So in client code, users would obtain a custom logger this way:

 MyLogger logger = MyLogger.create(MyClass.class);





Re: Using Custom Levels with a Custom/Wrapper Interface

2014-01-28 Thread Gary Gregory
I plan on catching up on all this tomorrow night.

Gary


On Tue, Jan 28, 2014 at 6:43 PM, Remko Popma remko.po...@gmail.com wrote:

 I would really like everyone's feedback on this. I have two questions:

 1. Does this fulfill everyone's requirements?
 Another way of asking this is: would you use this in your own projects?
 (If not, why not?)

 2. What do you think of this approach?
 Obviously code generation has drawbacks. For one thing, IDE refactoring
 tools don't work and API changes don't cause compile errors in the
 generator itself, only in the generated code. (I plan to add a JUnit test
 that generates a custom logger, compiles it and executes the custom logging
 methods so we can at least catch issues during the build.)
 The advantage is that it is open-ended and can deal with any custom level
 users can dream up.

 Is this trade-off acceptable?
 Are there other ways to solve this?

 Remko


 On Tuesday, January 28, 2014, Remko Popma remko.po...@gmail.com wrote:

 I created https://issues.apache.org/jira/browse/LOG4J2-519 for this.
 Feedback welcome.

 On Tuesday, January 28, 2014, Remko Popma remko.po...@gmail.com wrote:

 I've started to work on implementing a source code generator along the
 lines described below.


 Does anyone disagree with this approach?


 I was thinking to name the tools Generate$ExtendedLogger and
 Generate$CustomLogger and put the Generate class in the log4j-api project
 under org.apache.logging.log4j.util or create a new package called
 org.apache.logging.log4j.experimental.


 Thoughts?

 On Tuesday, January 28, 2014, Remko Popma remko.po...@gmail.com wrote:

 More thoughts on CustomLogger/ExtendedLogger source code generation:


 Perhaps I was overcomplicating things...

 Why don't we generate source for a concrete class instead of an
 interface+implementation?


 If users want to /extend/ Logger, this class would extend
 AbstractLoggerWrapper (which has the standard debug(), info(), warn(), ...
 methods).


 If users want to hide the standard methods, the generated class would
 simply not extend AbstractLoggerWrapper, so the only public methods would
 be the generated methods for the custom log levels.


 This allows users to generate both extended loggers (with extra methods)
 and custom domain specific Loggers (like a logger that only has defcon1(),
 defcon2(), defcon3() methods).


 Note: this would also enable users to /take away/ existing log4j log
 levels.

 Suppose you don't like the FATAL or TRACE log levels?

 Simply generate a custom logger with levels ERROR=200 WARN=300 INFO=400
 DEBUG=500.


 Since this is a wrapper, there is no need for API changes or additional
 methods on LogManager: the generated custom logger has factory methods that
 internally call the existing LogManager.getLogger() methods and wrap the
 resulting Logger.


 So in client code, users would obtain a custom logger this way:

 MyLogger logger = MyLogger.create(MyClass.class);





-- 
E-Mail: garydgreg...@gmail.com | ggreg...@apache.org
Java Persistence with Hibernate, Second Editionhttp://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


Re: Using Custom Levels with a Custom/Wrapper Interface

2014-01-28 Thread Nick Williams

On Jan 28, 2014, at 5:43 PM, Remko Popma wrote:

 I would really like everyone's feedback on this. I have two questions:
 
 1. Does this fulfill everyone's requirements?
 Another way of asking this is: would you use this in your own projects? (If 
 not, why not?)

Personally, no. I don't like the code generation for IDE integration issues. 
I'd prefer an interface I wrote.

 2. What do you think of this approach?
 Obviously code generation has drawbacks. For one thing, IDE refactoring tools 
 don't work and API changes don't cause compile errors in the generator 
 itself, only in the generated code. (I plan to add a JUnit test that 
 generates a custom logger, compiles it and executes the custom logging 
 methods so we can at least catch issues during the build.)
 The advantage is that it is open-ended and can deal with any custom level 
 users can dream up. 
 
 Is this trade-off acceptable?
 Are there other ways to solve this?

Also IMO, I would tend to steer away from only generating a concrete class. The 
interface and implementation should be separate. Imagine a Log4j fixing a bug 
in the generation code and releasing 2.0.1 or whatever. Now the user has a 
generated implementation, so they can't /just/ upgrade their Maven dependency. 
They /also/ have to re-generate their code. That's a pain. However, with the 
interface and implementation separate, the interface probably doesn't have to 
change, and the implementation will change as soon as they fire up their app 
with the latest Log4j.

Also, if you separate the interface and implementation, you can make the 
generation of the interface optional. The user can /choose/ whether to generate 
the interface or create the interface themselves. Then the implementation 
generates at runtime.

Nick

 
 Remko
 
 On Tuesday, January 28, 2014, Remko Popma remko.po...@gmail.com wrote:
 I created https://issues.apache.org/jira/browse/LOG4J2-519 for this. 
 Feedback welcome. 
 
 On Tuesday, January 28, 2014, Remko Popma remko.po...@gmail.com wrote:
 I've started to work on implementing a source code generator along the lines 
 described below.
 
 Does anyone disagree with this approach?
 
 I was thinking to name the tools Generate$ExtendedLogger and 
 Generate$CustomLogger and put the Generate class in the log4j-api project 
 under org.apache.logging.log4j.util or create a new package called 
 org.apache.logging.log4j.experimental.
 
 Thoughts?
 
 On Tuesday, January 28, 2014, Remko Popma remko.po...@gmail.com wrote:
 More thoughts on CustomLogger/ExtendedLogger source code generation:
 
 Perhaps I was overcomplicating things...
 Why don't we generate source for a concrete class instead of an 
 interface+implementation?
 
 If users want to /extend/ Logger, this class would extend 
 AbstractLoggerWrapper (which has the standard debug(), info(), warn(), ... 
 methods).
 
 If users want to hide the standard methods, the generated class would simply 
 not extend AbstractLoggerWrapper, so the only public methods would be the 
 generated methods for the custom log levels.
 
 This allows users to generate both extended loggers (with extra methods) and 
 custom domain specific Loggers (like a logger that only has defcon1(), 
 defcon2(), defcon3() methods).
 
 Note: this would also enable users to /take away/ existing log4j log levels.
 Suppose you don't like the FATAL or TRACE log levels?
 Simply generate a custom logger with levels ERROR=200 WARN=300 INFO=400 
 DEBUG=500.
 
 Since this is a wrapper, there is no need for API changes or additional 
 methods on LogManager: the generated custom logger has factory methods that 
 internally call the existing LogManager.getLogger() methods and wrap the 
 resulting Logger.
 
 So in client code, users would obtain a custom logger this way:
 MyLogger logger = MyLogger.create(MyClass.class); 
 



Re: Using Custom Levels with a Custom/Wrapper Interface

2014-01-27 Thread Remko Popma
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(ClassT cls, String
name) {

Logger wrapped = getLogger(name);

return wrap(cls, wrapped);

}


private static T extends Logger T wrap(ClassT 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
 
  

Re: Using Custom Levels with a Custom/Wrapper Interface

2014-01-27 Thread Paul Benedict
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.

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.comwrote:

 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(ClassT cls, String
 name) {

 Logger wrapped = getLogger(name);

 return wrap(cls, wrapped);

 }


 private static T extends Logger T wrap(ClassT 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

Re: Using Custom Levels with a Custom/Wrapper Interface

2014-01-27 Thread Gary Gregory
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 remko.po...@gmail.com 
Date:01/27/2014  09:15  (GMT-05:00) 
To: Log4J Developers List log4j-dev@logging.apache.org 
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(ClassT cls, String name) {
Logger wrapped = getLogger(name);
return wrap(cls, wrapped);
}

private static T extends Logger T wrap(ClassT 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

Re: Using Custom Levels with a Custom/Wrapper Interface

2014-01-27 Thread Remko Popma
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.comwrote:

 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(ClassT cls, String
 name) {

 Logger wrapped = getLogger(name);

 return wrap(cls, wrapped);

 }


 private static T extends Logger T wrap(ClassT 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

Re: Using Custom Levels with a Custom/Wrapper Interface

2014-01-27 Thread Paul Benedict
It's OK for a custom logger interface to extend Logger as long as the
framework provides a stock implementation of the Logger interface. You want
your customers to easily subclass existing code and not create the entire
implementation from scratch. If you guys can make the Logger Implementation
part of the supported client code, then it will be easy -- so easy that
custom generation of code may just be overkill.


On Mon, Jan 27, 2014 at 9:30 AM, Remko Popma remko.po...@gmail.com wrote:

 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.comwrote:

 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(ClassT cls, String
 name) {

 Logger wrapped = getLogger(name);

 return wrap(cls, wrapped);

 }


 private static T extends Logger T wrap(ClassT 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

Re: Using Custom Levels with a Custom/Wrapper Interface

2014-01-27 Thread Gary Gregory
On Mon, Jan 27, 2014 at 10:24 AM, Paul Benedict pbened...@apache.orgwrote:

 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.comwrote:

 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(ClassT cls, String
 name) {

 Logger wrapped = getLogger(name);

 return wrap(cls, wrapped);

 }


 private static T extends Logger T wrap(ClassT 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

Re: Using Custom Levels with a Custom/Wrapper Interface

2014-01-27 Thread Nick Williams
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(ClassT cls, String name) 
 {
   Logger wrapped = getLogger(name);
   return wrap(cls, wrapped);
 }
 
 private static T extends Logger T wrap(ClassT 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

Re: Using Custom Levels with a Custom/Wrapper Interface

2014-01-27 Thread Ralph Goers
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(ClassT cls, String 
 name) {
  Logger wrapped = getLogger(name);
  return wrap(cls, wrapped);
 }
 
 private static T extends Logger T wrap(ClassT 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

Re: Using Custom Levels with a Custom/Wrapper Interface

2014-01-27 Thread Paul Benedict
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.orgwrote:

 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.comwrote:

 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(ClassT cls, String
 name) {
 Logger wrapped = getLogger(name);
 return wrap(cls, wrapped);
 }

 private static T extends Logger T wrap(ClassT 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

Re: Using Custom Levels with a Custom/Wrapper Interface

2014-01-27 Thread Paul Benedict

 On Jan 27, 2014, at 11:15 AM, Nick Williams nicho...@nicholaswilliams.net
 wrote:

 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.


This is what I was recommending. Sorry for any confusion.

Paul


Re: Using Custom Levels with a Custom/Wrapper Interface

2014-01-27 Thread Nick Williams
Okay, I see now. I got confused by what Gary said:

 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).

Nick

On Jan 27, 2014, at 1:25 PM, Paul Benedict wrote:

 On Jan 27, 2014, at 11:15 AM, Nick Williams nicho...@nicholaswilliams.net 
 wrote:
 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.
 
 
 This is what I was recommending. Sorry for any confusion. 
 
 Paul



Re: Using Custom Levels with a Custom/Wrapper Interface

2014-01-27 Thread Paul Benedict
I would like to see SimpleLogger be where custom interfaces are extended.
Now you can't forget that if we provide a default implementation class,
that will already implement Logger. So it's very easy to cast directly to
Logger if necessary to access your standard methods.


On Mon, Jan 27, 2014 at 1:59 PM, Nick Williams 
nicho...@nicholaswilliams.net wrote:

 Okay, I see now. I got confused by what Gary said:

 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).


 Nick

 On Jan 27, 2014, at 1:25 PM, Paul Benedict wrote:

 On Jan 27, 2014, at 11:15 AM, Nick Williams nicho...@nicholaswilliams.net
 wrote:

 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.


 This is what I was recommending. Sorry for any confusion.

 Paul





-- 
Cheers,
Paul


Re: Using Custom Levels with a Custom/Wrapper Interface

2014-01-27 Thread Gary Gregory
On Mon, Jan 27, 2014 at 2: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.


Of course, let's not get caught up in the names here and focus on the
design first. What matters is that the current interface in split between a
generic Level agnostic parent and a DSL sub-interface. I agree that 80/20
says that Logger should be the name of the interface that has info(),
warn() and so on. The parent can be called LevelLogger for example since it
must be called with a Level. I do not like SimpleLogger because it does
not describe anything and 'simple' feels like a judgment call.

Gary



 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.orgwrote:

 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.comwrote:

 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(ClassT cls, String
 name) {
 Logger wrapped = getLogger(name);
 return wrap(cls, wrapped);
 }

 private static T extends Logger T wrap(ClassT cls, Logger wrapped) {
 CustomLoggerImplementation annotation =
 cls.getAnnotation(CustomLoggerImplementation.class);
 Class? implClass = annotation.value();
 try

Re: Using Custom Levels with a Custom/Wrapper Interface

2014-01-27 Thread Remko Popma
More thoughts on CustomLogger/ExtendedLogger source code generation:


Perhaps I was overcomplicating things...

Why don't we generate source for a concrete class instead of an
interface+implementation?


If users want to /extend/ Logger, this class would extend
AbstractLoggerWrapper (which has the standard debug(), info(), warn(), ...
methods).


If users want to hide the standard methods, the generated class would
simply not extend AbstractLoggerWrapper, so the only public methods would
be the generated methods for the custom log levels.


This allows users to generate both extended loggers (with extra methods)
and custom domain specific Loggers (like a logger that only has defcon1(),
defcon2(), defcon3() methods).


Note: this would also enable users to /take away/ existing log4j log levels.

Suppose you don't like the FATAL or TRACE log levels?

Simply generate a custom logger with levels ERROR=200 WARN=300 INFO=400
DEBUG=500.


Since this is a wrapper, there is no need for API changes or additional
methods on LogManager: the generated custom logger has factory methods that
internally call the existing LogManager.getLogger() methods and wrap the
resulting Logger.


So in client code, users would obtain a custom logger this way:

MyLogger logger = MyLogger.create(MyClass.class);


Thoughts?



On Tuesday, January 28, 2014, Gary Gregory garydgreg...@gmail.com wrote:

 On Mon, Jan 27, 2014 at 2:15 PM, Nick Williams 
 nicho...@nicholaswilliams.net javascript:_e({}, 'cvml',
 '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.


 Of course, let's not get caught up in the names here and focus on the
 design first. What matters is that the current interface in split between a
 generic Level agnostic parent and a DSL sub-interface. I agree that 80/20
 says that Logger should be the name of the interface that has info(),
 warn() and so on. The parent can be called LevelLogger for example since it
 must be called with a Level. I do not like SimpleLogger because it does
 not describe anything and 'simple' feels like a judgment call.

 Gary



 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.orgwrote:

 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.comwrote:

 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

Re: Using Custom Levels with a Custom/Wrapper Interface

2014-01-27 Thread Remko Popma
I've started to work on implementing a source code generator along the
lines described below.


Does anyone disagree with this approach?


I was thinking to name the tools Generate$ExtendedLogger and
Generate$CustomLogger and put the Generate class in the log4j-api project
under org.apache.logging.log4j.util or create a new package called
org.apache.logging.log4j.experimental.


Thoughts?

On Tuesday, January 28, 2014, Remko Popma remko.po...@gmail.com wrote:

 More thoughts on CustomLogger/ExtendedLogger source code generation:


 Perhaps I was overcomplicating things...

 Why don't we generate source for a concrete class instead of an
 interface+implementation?


 If users want to /extend/ Logger, this class would extend
 AbstractLoggerWrapper (which has the standard debug(), info(), warn(), ...
 methods).


 If users want to hide the standard methods, the generated class would
 simply not extend AbstractLoggerWrapper, so the only public methods would
 be the generated methods for the custom log levels.


 This allows users to generate both extended loggers (with extra methods)
 and custom domain specific Loggers (like a logger that only has defcon1(),
 defcon2(), defcon3() methods).


 Note: this would also enable users to /take away/ existing log4j log
 levels.

 Suppose you don't like the FATAL or TRACE log levels?

 Simply generate a custom logger with levels ERROR=200 WARN=300 INFO=400
 DEBUG=500.


 Since this is a wrapper, there is no need for API changes or additional
 methods on LogManager: the generated custom logger has factory methods that
 internally call the existing LogManager.getLogger() methods and wrap the
 resulting Logger.


 So in client code, users would obtain a custom logger this way:

 MyLogger logger = MyLogger.create(MyClass.class);


 Thoughts?



 On Tuesday, January 28, 2014, Gary Gregory 
 garydgreg...@gmail.comjavascript:_e({}, 'cvml', 'garydgreg...@gmail.com');
 wrote:

 On Mon, Jan 27, 2014 at 2: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.


 Of course, let's not get caught up in the names here and focus on the
 design first. What matters is that the current interface in split between a
 generic Level agnostic parent and a DSL sub-interface. I agree that 80/20
 says that Logger should be the name of the interface that has info(),
 warn() and so on. The parent can be called LevelLogger for example since it
 must be called with a Level. I do not like SimpleLogger because it does
 not describe anything and 'simple' feels like a judgment call.

 Gary



 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.orgwrote:

 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.comwrote:

 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

Re: Using Custom Levels with a Custom/Wrapper Interface

2014-01-26 Thread Scott Deboy
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(ClassT loggerClass)
  T extends Logger T getCustomLogger(ClassT loggerClass, Class?)
  T extends Logger T getCustomLogger(ClassT loggerClass, Class?,
 MessageFactory)
  T extends Logger T getCustomLogger(ClassT loggerClass,
 MessageFactory)
  T extends Logger T getCustomLogger(ClassT loggerClass, Object)
  T extends Logger T getCustomLogger(ClassT loggerClass, Object,
 MessageFactory)
  T extends Logger T getCustomLogger(ClassT loggerClass, String)
  T extends Logger T getCustomLogger(ClassT 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 ClassT 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




Re: Using Custom Levels with a Custom/Wrapper Interface

2014-01-26 Thread Nick Williams
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(ClassT loggerClass)
  T extends Logger T getCustomLogger(ClassT loggerClass, Class?)
  T extends Logger T getCustomLogger(ClassT loggerClass, Class?, 
  MessageFactory)
  T extends Logger T getCustomLogger(ClassT loggerClass, MessageFactory)
  T extends Logger T getCustomLogger(ClassT loggerClass, Object)
  T extends Logger T getCustomLogger(ClassT loggerClass, Object, 
  MessageFactory)
  T extends Logger T getCustomLogger(ClassT loggerClass, String)
  T extends Logger T getCustomLogger(ClassT 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 ClassT 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
 



Re: Using Custom Levels with a Custom/Wrapper Interface

2014-01-26 Thread Matt Sicker
The JPA criteria API manages to generate a Foo_ class for the entity class
Foo, and that seems to work out fine.


On 26 January 2014 21:45, Nick Williams nicho...@nicholaswilliams.netwrote:

 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(ClassT loggerClass)
  T extends Logger T getCustomLogger(ClassT loggerClass, Class?)
  T extends Logger T getCustomLogger(ClassT loggerClass, Class?,
 MessageFactory)
  T extends Logger T getCustomLogger(ClassT loggerClass,
 MessageFactory)
  T extends Logger T getCustomLogger(ClassT loggerClass, Object)
  T extends Logger T getCustomLogger(ClassT loggerClass, Object,
 MessageFactory)
  T extends Logger T getCustomLogger(ClassT loggerClass, String)
  T extends Logger T getCustomLogger(ClassT 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 ClassT 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





-- 
Matt Sicker boa...@gmail.com


Re: Using Custom Levels with a Custom/Wrapper Interface

2014-01-26 Thread Ralph Goers
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(ClassT loggerClass)
  T extends Logger T getCustomLogger(ClassT loggerClass, Class?)
  T extends Logger T getCustomLogger(ClassT loggerClass, Class?, 
  MessageFactory)
  T extends Logger T getCustomLogger(ClassT loggerClass, MessageFactory)
  T extends Logger T getCustomLogger(ClassT loggerClass, Object)
  T extends Logger T getCustomLogger(ClassT loggerClass, Object, 
  MessageFactory)
  T extends Logger T getCustomLogger(ClassT loggerClass, String)
  T extends Logger T getCustomLogger(ClassT 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 ClassT 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
 
 



Re: Using Custom Levels with a Custom/Wrapper Interface

2014-01-26 Thread Remko Popma
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
LevelsLevel 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.netjavascript:_e({}, 'cvml', 
 '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.netjavascript:_e({}, 'cvml', 
 '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(ClassT loggerClass)
  T extends Logger T getCustomLogger(ClassT loggerClass, Class?)
  T extends Logger T getCustomLogger(ClassT loggerClass, Class?,
 MessageFactory)
  T extends Logger T getCustomLogger(ClassT loggerClass,
 MessageFactory)
  T extends Logger T getCustomLogger(ClassT loggerClass, Object)
  T extends Logger T getCustomLogger(ClassT loggerClass, Object,
 MessageFactory)
  T extends Logger T getCustomLogger(ClassT loggerClass, String)
  T extends Logger T getCustomLogger(ClassT 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 ClassT 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.orgjavascript:_e({}, 'cvml', 
 'log4j-dev-unsubscr...@logging.apache.org');
 For additional commands, e-mail: 
 log4j-dev-h...@logging.apache.orgjavascript:_e({}, 'cvml', 
 

Re: Using Custom Levels with a Custom/Wrapper Interface

2014-01-26 Thread Ralph Goers
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 
 LevelsLevel 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(ClassT loggerClass)
  T extends Logger T getCustomLogger(ClassT loggerClass, Class?)
  T extends Logger T getCustomLogger(ClassT loggerClass, Class?, 
  MessageFactory)
  T extends Logger T getCustomLogger(ClassT loggerClass, MessageFactory)
  T extends Logger T getCustomLogger(ClassT loggerClass, Object)
  T extends Logger T getCustomLogger(ClassT loggerClass, Object, 
  MessageFactory)
  T extends Logger T getCustomLogger(ClassT loggerClass, String)
  T extends Logger T getCustomLogger(ClassT 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 
  

Re: Using Custom Levels with a Custom/Wrapper Interface

2014-01-26 Thread Scott Deboy
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
 LevelsLevel 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(ClassT loggerClass)
  T extends Logger T getCustomLogger(ClassT loggerClass, Class?)
  T extends Logger T getCustomLogger(ClassT loggerClass, Class?,
  MessageFactory)
  T extends Logger T getCustomLogger(ClassT loggerClass,
  MessageFactory)
  T extends Logger T getCustomLogger(ClassT loggerClass, Object)
  T extends Logger T getCustomLogger(ClassT loggerClass, Object,
  MessageFactory)
  T extends Logger T getCustomLogger(ClassT loggerClass, String)
  T extends Logger T getCustomLogger(ClassT 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 

Re: Using Custom Levels with a Custom/Wrapper Interface

2014-01-26 Thread Remko Popma
Sure, but what's wrong with the idea?
The user provide their own interface, so that interface exists at compile
time.
The interface uses annotations, so it does not need to explicitly refer to
a custom Level instance. Only the /implementation/ needs to know about the
custom Level instances, and the implementation could be generated at
runtime (I hope :-) ).

On Monday, January 27, 2014, 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
 LevelsLevel 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 [met




Re: Using Custom Levels with a Custom/Wrapper Interface

2014-01-26 Thread Remko Popma
In addition to the above, we could provide a tool to generate a MyLogger
interface with 14 method signatures for each custom Level name. This would
be an offline tool that users would use only once.
But this tool is optional...

On Monday, January 27, 2014, Remko Popma remko.po...@gmail.com wrote:

 Sure, but what's wrong with the idea?
 The user provide their own interface, so that interface exists at compile
 time.
 The interface uses annotations, so it does not need to explicitly refer to
 a custom Level instance. Only the /implementation/ needs to know about the
 custom Level instances, and the implementation could be generated at
 runtime (I hope :-) ).

 On Monday, January 27, 2014, 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
 LevelsLevel 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 hypoth




Re: Using Custom Levels with a Custom/Wrapper Interface

2014-01-26 Thread Remko Popma
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
  LevelsLevel 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 


Re: Using Custom Levels with a Custom/Wrapper Interface

2014-01-26 Thread Scott Deboy
Could we leverage Rhino? :)

Scott

On 1/26/14, 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
 LevelsLevel 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(ClassT loggerClass)
 T extends Logger T getCustomLogger(ClassT loggerClass, Class?)
 T extends Logger T getCustomLogger(ClassT loggerClass, Class?,
 MessageFactory)
 T extends Logger T getCustomLogger(ClassT loggerClass,
 MessageFactory)
 T extends Logger T getCustomLogger(ClassT loggerClass, Object)
 T extends Logger T getCustomLogger(ClassT loggerClass, Object,
 MessageFactory)
 T extends Logger T 

Re: Using Custom Levels with a Custom/Wrapper Interface

2014-01-26 Thread Scott Deboy
Of course, they'd have to use rhino, or something else...which doesn't
help.  Where's duck typing when you need it :)

On 1/26/14, Scott Deboy scott.de...@gmail.com wrote:
 Could we leverage Rhino? :)

 Scott

 On 1/26/14, 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
 LevelsLevel 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(ClassT loggerClass)
 T extends Logger T getCustomLogger(ClassT loggerClass,
 Class?)
 T extends Logger T getCustomLogger(ClassT loggerClass,
 Class?,
 MessageFactory)
 T extends Logger T getCustomLogger(ClassT loggerClass,
 

Re: Using Custom Levels with a Custom/Wrapper Interface

2014-01-26 Thread Nicholas Williams
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
  LevelsLevel 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 


Re: Using Custom Levels with a Custom/Wrapper Interface

2014-01-26 Thread Matt Sicker
If we go the run-once tool route, then you might as well use annotation
processing. I think it would support everything necessary to generate the
appropriate custom logger class.


On 26 January 2014 23:00, Scott Deboy scott.de...@gmail.com wrote:

 Of course, they'd have to use rhino, or something else...which doesn't
 help.  Where's duck typing when you need it :)

 On 1/26/14, Scott Deboy scott.de...@gmail.com wrote:
  Could we leverage Rhino? :)
 
  Scott
 
  On 1/26/14, 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
  LevelsLevel 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...)