[ https://issues.apache.org/jira/browse/LOG4J2-1278?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15150525#comment-15150525 ]
Remko Popma edited comment on LOG4J2-1278 at 2/17/16 2:11 PM: -------------------------------------------------------------- Using {{Unboxer.box()}} may only be of interest to people who really care about latency. The alternative is to have separate methods for all combinations of {{double}}, {{long}}, {{Object}} at the least, which quickly becomes intractable (1^3 + 2^3 + 3^3 + 4^3 = 100 methods for 4 params...) How to support custom log levels: on the Logger interface we'd have these methods: {code} trace() : LevelLogger debug() : LevelLogger info() : LevelLogger ... level(Level) : LevelLogger {code} Custom loggers or Extended loggers generated by the org.apache.logging.log4j.core.tools.Generate tool can provide convenience methods named after the custom level. was (Author: rem...@yahoo.com): Using {{Unboxer.box()}} may only be of interest to people who really care about latency. The alternative is to support all combinations of {{double}}, {{long}}, {{Object}} at the least, which quickly becomes intractable (1^3 + 2^3 + 3^3 + 4^3 = 100 methods for 4 params...) How to support custom log levels: on the Logger interface we'd have these methods: {code} trace() : LevelLogger debug() : LevelLogger info() : LevelLogger ... level(Level) : LevelLogger {code} Custom loggers or Extended loggers generated by the org.apache.logging.log4j.core.tools.Generate tool can provide convenience methods named after the custom level. > 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