[ 
https://issues.apache.org/jira/browse/LOG4J2-1278?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15155955#comment-15155955
 ] 

Gary Gregory commented on LOG4J2-1278:
--------------------------------------

WRT to level logger declaration, in the {{level-logger}} branch I have this in 
{{LogManager}}:

    public static LevelLoggers getLevelLoggers(final String name) {
        return new LevelLoggers(getLogger(name));
    }

Which is basically what you have, not a big deal IMO, you just need the factory 
method to make the use case 'pretty'.

I think that we are boiling down to: 

- We are just going to grow {{Logger}} until it becomes unmanageable for users: 
"When I use content assist, I get 1,000 methods, ahhhh!", but will be a 
non-issue at runtime as you mention. Adding to {{Logger}} is just the KISS 
approach and I'm fine with it.
- We could introduce a logger level API as a different way to do things, 
perhaps in a new module or a new package in the current API module. It could 
also go in a samples module to show how to extend log4j in some creative way, 
but at that point, I'd rather do it in a new API module or in a new package in 
the current API module, or in the same package, YMMV depending on whether you 
want to 'show' or 'hide' it from the current solution.

> Garbage-free logging API (no varargs/autoboxing)
> ------------------------------------------------
>
>                 Key: LOG4J2-1278
>                 URL: https://issues.apache.org/jira/browse/LOG4J2-1278
>             Project: Log4j 2
>          Issue Type: Improvement
>          Components: API
>    Affects Versions: 2.5
>            Reporter: Remko Popma
>            Assignee: Remko Popma
>
> Looking at the current Logger API, there are a few methods (for each log 
> level) that take a vararg parameter:
> {code}
> // org.apache.logging.log4j.Logger
> debug(String, Object...) // arguably this method is used the most
> debug(String, Supplier<?>...)
> debug(Marker, String, Object...)
> debug(Marker, String, Supplier<?>...)
> {code}
> This ticket is to explore options for providing similar functionality without 
> creating temporary objects (see LOG4J2-1270 for motivation).
> Here are some of the options I can think of:
> *1. Thread-local StringBuilderMessage*
> One option is that we provide a new MessageFactory that always returns the 
> same Message object (cached in a ThreadLocal). This Message exposes its 
> StringBuilder. Users build the log message text by appending to the 
> StringBuilder. When the Logger.log method is called, and the Message is 
> enqueued in the RingBufferLogEvent, the StringBuilder text is copied to the 
> RingBufferLogEvent.
> Pros: feasible, low effort, no Logger API changes
> Cons: not the nicest user-facing API
> *2. Logger with unrolled varargs*
> Another way to avoid the varargs is adding extra methods to the Logger 
> interface that take a varying number of parameters. For example:
> {code}
> // add methods to org.apache.logging.log4j.Logger
> trace(String, Object)
> trace(String, Object, Object)
> trace(String, Object, Object, Object)
> trace(String, Object, Object, Object, Object)
> trace(String, Object, Object, Object, Object, Object)
> trace(String, Object, Object, Object, Object, Object, Object)
> trace(String, Object...) // fallback to vararg if 7 parameters or more
> ...
> // same for DEBUG, INFO, WARN, ERROR, FATAL, and LOG(Level)
> {code}
> Pros: transparent to users
> Cons: grows Logger interface from 200+ methods\(!) to an even larger number
> *3. New interface (LevelLogger) with unrolled varargs*
> Another option that avoids the method explosion is providing a new interface 
> (e.g. LevelLogger). This interface has extra methods for a varying number of 
> parameters. For example:
> {code}
> // new interface LevelLogger
> log(String, Object)
> log(String, Object, Object)
> log(String, Object, Object, Object)
> log(String, Object, Object, Object, Object)
> log(String, Object, Object, Object, Object, Object)
> log(String, Object, Object, Object, Object, Object, Object)
> log(String, Object...) // fallback to vararg if 7 parameters or more
> {code}
> For each log level, the same interface can be used, so the number of methods 
> can stay small. There are several ways in which client code could obtain a 
> LevelLogger. One option is from the Logger, but other things are possible too.
> {code}
> Logger logger = LogManager.getLogger(MyClass.class);
> logger.info().log("This a {} message with {} params", "vararg-free", 2);
> {code}
> *Avoiding Autoboxing*
> To avoid auto-boxing of primitive parameters (like the integer in the above 
> example), one option is to provide a utility method. Client code would look 
> like this:
> {code}
> // static import Unboxer.*;
> logger.info().log("This a {} message with {} params", "GC-free", box(2));
> {code}
> {{Unboxer.box(int)}} returns a StringBuilder containing the primitive value 
> converted to text. Unboxer internally can be implemented with a cached ring 
> buffer of StringBuilders, with as many slots as there are unrolled varargs.
> *4. LevelLogger with method chaining*
> A different way to avoid auto-boxing is method chaining.
> Client code would look like this:
> {code}
> String type = "GC-free";
> int count = 2;
> logger.info().log("This a ").add(type).add(" message with ").add(count).add(" 
> params").commit();
> {code}
> Pros: feasible, medium effort
> Cons: API very similar to StringBuilder, but more fragile since users must 
> remember to call commit()



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

---------------------------------------------------------------------
To unsubscribe, e-mail: log4j-dev-unsubscr...@logging.apache.org
For additional commands, e-mail: log4j-dev-h...@logging.apache.org

Reply via email to