logging-log4j-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Remko Popma (JIRA)" <j...@apache.org>
Subject [jira] [Updated] (LOG4J2-1278) Garbage-free logging API (no varargs/autoboxing)
Date Tue, 16 Feb 2016 07:06:18 GMT

     [ https://issues.apache.org/jira/browse/LOG4J2-1278?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]

Remko Popma updated LOG4J2-1278:
--------------------------------
    Summary: Garbage-free logging API (no varargs/autoboxing)  (was: Garbage-free logging
API)

> 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-unsubscribe@logging.apache.org
For additional commands, e-mail: log4j-dev-help@logging.apache.org


Mime
View raw message