1 of 13

Flogger:�A Fluent Java Logging API

Use it in Gerrit?

(Edwin Kempin)

2 of 13

Outline

  1. The state of logging in Gerrit
  2. Flogger, a fluent logging API
  3. Benefits
  4. Migration Cost
  5. Request Tracing

3 of 13

The state of logging in Gerrit

  • Simple Logging Facade for Java (SLF4J)�(abstraction for various logging frameworks)
  • Log4j backend�(at Google: java.util.logging backend)
  • SSH commands to list/set log levels�(supported for log4j backend only)

4 of 13

Logging with SLF4J

log.error("Error in {} {}", req.getMethod(), uri, err);�Problems:

  • Features are not easily discoverable due to too many overloads�(e.g. error method exists 10 times)
  • Adding features causes combinatorial explosion
  • Hidden costs even for disabled log statements
  • Not everything is supported with SLF4J (e.g. listing/setting log levels is implemented on LOG4J level)

5 of 13

Flogger, a fluent logging API

6 of 13

Flogger, a fluent logging API

SLF4J:�log.error("Error in {} {}", req.getMethod(), uri, err);

Flogger:�logger.atSevere()� .withCause(err)� .log("Error in %s %s", req.getMethod(), uri);�⇒ More readable, less prone to confusion about parameter ordering,� more discoverable in IDE

7 of 13

Flogger: Initialization of Logger

SLF4J:�private static final Logger log = � LoggerFactory.getLogger(PublicKeyChecker.class);

Flogger:�private static final FluentLogger logger = � FluentLogger.forEnclosingClass();

8 of 13

Flogger Benefits

  • Better readability�(less prone to confusion about parameter ordering, more discoverable in IDE)
  • Better Performance�(logging at disabled levels is effectively free)
  • Extensible API�(a fluent API accommodates a variety of present and future features without combinatorial explosion, and without requiring separate logging facades)

9 of 13

Flogger Performance

Logging at disabled levels is effectively free:(https://google.github.io/flogger/benefits#cheap-disabled-logging)

The simple log.info(String, Object...) approach to logging is concise at the source code level, but can introduce surprising cost in bytecode. Vararg methods require a new Object[] to be allocated and filled before the method can be invoked. Additionally any fundamental types passed in must be auto-boxed. This all costs additional bytecode and latency at the call site and is particularly unfortunate if the log statement isn’t actually enabled.”

10 of 13

Flogger Extensibility

  • Build-in features (examples):��a) logger.atInfo().atMostEvery(1, TimeUnit.HOURS).log(...)��b) logger.atInfo().every(100).log(...)��c) logger.atInfo().withStackTrace(StackSize.FULL).log(...)�

11 of 13

Migration Cost

  • Migrate all log statements to Flogger�(migration tool exists at Google, but it doesn’t support migrating from SLF4J, however within Google we may be able to do a contribution to the migration tool to get most of our log statements migrated automatically)
  • Flogger currently only has a java.util.logging Backend�(we are welcome to contribute a log4j backend, estimated effort 2 weeks)
  • Format of log messages may slightly change

12 of 13

Request Tracing

  • Request ID in each log statement�(the generated request ID is returned to the client and an admin can use it to easily find all logs that correspond to the request)
  • Enforce debug logs when a trace is requested�(write out all logs for this one request regardless of the configured log level)
  • Enable traces across multiple requests�(allow the client to provide a trace ID that is included into all logs that correspond to the request)

⇒ All this is possible to implement when we use Flogger.

13 of 13

Questions & Feedback

  • Concerns?
  • Is it worth doing it?
  • Who wants to help with implementing it?�

Flogger Resources

https://github.com/google/flogger