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

Ralph Goers commented on LOG4J2-1278:
-------------------------------------

I haven't had a chance to look at it. Can I let you know tomorrow?

> 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