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

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

Of all of these I like the "LevelLogger" the best, although I dislike user's 
having to do box(2). Again, I am not sure it is worth it to worry about 
autoboxing of user's parameters.  The main concern I have here is how custom 
levels will be supported. Wouldn't it require a method for each custom level to 
be added to the Logger interface?

That said, when I run the varargs benchmark the results I get are:
{code}
Benchmark                                          Mode  Samples   Score   
Error  Units
o.a.l.l.p.j.VarargsBenchmark.baseline            sample   471192  37.993 ± 
0.946  ns/op
o.a.l.l.p.j.VarargsBenchmark.individualParams    sample   366978  52.913 ± 
1.235  ns/op
o.a.l.l.p.j.VarargsBenchmark.varargParams        sample   409879  49.163 ± 
1.631  ns/op
{code}
Is this difference really meaningful enough to worry about?


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