[prev in list] [next in list] [prev in thread] [next in thread] 

List:       log4j-dev
Subject:    [jira] [Commented] (LOG4J2-1278) Garbage-free logging API (no varargs/autoboxing)
From:       Mikael_Ståldal_(JIRA) <jira () apache ! org>
Date:       2016-03-31 8:48:25
Message-ID: JIRA.12939419.1455606286000.98554.1459414105769 () Atlassian ! JIRA
[Download RAW message or body]


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

Mikael Ståldal commented on LOG4J2-1278:
----------------------------------------

Ah, OK.

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


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic