Hyper-lightweight logging update
Update to our system for high-volume logging with the goal of having any logging call result in *zero* allocations, not even strings. The core pieces are LogBuffer and LogMessage. LogBuffer is a simple ring buffer that holds instances of LogMessage. LogMessages store data related the thing they're logging, but in a generic way that allows them to be reused across ALL log types. In order to log a message, the caller must supply two things: - The _initializer_, a function that stores data on a LogMessage - The _printer_, a function that converts a LogMessage containing the stored data into a human-readable string. When a message is logged, the initializer is called on a newly-obtained instance of LogMessage. The printer is also stored on the message and the message itself is inserted into the buffer. Later, when the message needs to be dumped, the printer is called on the message instance to create a human-readable string. Using features of Kotlin, we can inline calls to the initializer so the function is effectively erased. The printers cannot be erased (we need to maintain a reference to them) and so each printer requires a (small) classdef. However, because the printers are stateless, we only ever need one instance copy per printer. Advantages of this system: - Lightweight: no-allocation logging (still some overhead, but it's very slight). - Ease of use: easy to add new logs. Log-generating code is easy to read. - Closer match to logcat: system uses TAG and logcat levels (VERBOSE, etc) - Finer-grained control over debugging: Can control which tags and/or buffers log to logcat and at what logging level (VERBOSE, etc). Disadvantages: - Each log type requires the creation of an anonymous class def (the printer function). With a ton of such class defs, our code might get bloated (it's unlikely for us to reach this point, however). - Easy to accidentally write a log message that triggers an allocation (if your printer function captures any outside scope, such as one of the original log parameters, then the system will need to instantiate a new instance of the printer function for each call instead of reusing a singleton static instance). Test: manual Change-Id: I2c7c272cda4ce61d56427ab1d6eb270d9365b325
Loading
Please register or sign in to comment