[
https://issues.apache.org/jira/browse/LOG4J2-1278?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15219397#comment-15219397
]
Ralph Goers edited comment on LOG4J2-1278 at 3/31/16 5:47 AM:
--------------------------------------------------------------
In general, I am OK with this changes but I do have some concerns:
1. When I tried to run a build it failed with
GcFreeLoggingTest.testNoAllocationDuringSteadyStateLogging:60 expected:<[]>
but was:<[objc[2524]
2. I believe it is a problem to have the ThreadLocals in ReusableMessageFactory
be static. That needs to be addressed before we can release. I tried modifying
the ThreadLocalRegistry to not have to check for null but I haven't been able
to get it to work yet.
was (Author: [email protected]):
In general, I am OK with this changes but I do have some concerns:
1. When I tried to run a build it failed with
GcFreeLoggingTest.testNoAllocationDuringSteadyStateLogging:60 expected:<[]>
but was:<[objc[2524]
2. I believet it is a problem to have the ThreadLocals in
ReusableMessageFactory be static. That needs to be addressed before we can
release. I tried modifying the ThreadLocalRegistry to not have to check for
null but I haven't been able to get it to work yet.
> 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
> Attachments: Latency.png, Throughput.png
>
>
> 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: [email protected]
For additional commands, e-mail: [email protected]