First-class debugging tools should reduce developers' reliance on bespoke logging, but logging code in applications captures and abstracts information important to developers, and will no doubt remain useful. Pernosco leverages logging by capturing log output and presenting it in a dedicated log view, using built-in knowledge of logging frameworks used by our customers. When log output is categorized by "log modules", Pernosco indexes on those modules to support efficient filtering by module. Clicking on log output jumps to where and when it was produced.
For applications like Firefox, enabling all logging is prohibitively expensive, so most logs are disabled by default and developers opt into collecting subsets of logs. This is cumbersome, often requiring multiple iterations of enabling logs, running tests, and investigating results. Worse, each iteration may behave differently, exhibiting different bugs or no bug at all, either because the application is nondeterministic or because the logging itself perturbs the application. Pernosco fixes this by recording test execution with all logging disabled and then capturing log output during a specially instrumented replay. During this replay, whenever the application tests whether logging is enabled, Pernosco forks the program state and executes ahead as if logging is enabled, capturing any log results. Once control returns to the main execution path, the forked state is discarded and replay continues normally. Each "diversion" needs to be very efficient because they can occur at a very high rate.
This approach is not perfect. For example, sometimes logging code will capture some data (e.g. a timestamp) if logging is enabled, then do some work, and then log results based on the previously captured data. With our approach, after the first step the captured data will be thrown away and the actual log output will fail. Nevertheless it generally works well in practice.