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

Reply via email to