logger.h
A log a user can send you.
#include <sonore/logger.h>- 1type
- 1other declaration
- Guides: Testing your plugin
On this page
Design notes
Why a plugin needs one more than an application does
An application that misbehaves can be run from a terminal. A plugin cannot: it is loaded into somebody else's process, on somebody else's machine, and the only channel back is the user. "It crashes sometimes when I load a preset" is the entire bug report you get, and without a log it is also the entire evidence.
So this exists to be READ BY SOMEBODY ELSE: appended to a file the user can find, capped so it cannot fill a disk, and readable back so a plugin can put a "copy diagnostics" button in its editor.
The audio thread, which is the whole design problem
The interesting failures are in process(). That is exactly where a logger must not be used: opening a file, formatting a string and taking a mutex are each enough to blow a buffer deadline, and the dropout would be caused by the diagnostic rather than by the bug.
The conventional logger has no answer to that -- a virtual call to a subclass that writes a file, and calling it from an audio callback is simply a mistake. Which means the one place you most want a trace is the one place you cannot have one.
So there are two doors. write() is for any ordinary thread and does the obvious thing. writeFromAudioThread() copies at most kMaxLine bytes into a fixed ring and returns: no allocation, no lock, no syscall, nothing that can block. drain() moves whatever accumulated to the file, and is called from the editor's clock alongside everything else that crosses that boundary.
A message that arrives while the ring is full is DROPPED and counted. Dropped with a number attached is a fact; dropped silently is a lie, and blocking until there is room is the dropout this whole arrangement exists to avoid.
Types 1
The process's log: a capped file a user can send, the last few hundred lines in memory for a "copy diagnostics" button, and a lock-free way in from the audio thread. One instance, from get(); it covers what the reference's Logger and FileLogger do between them. See the file comment for the two doors.
write() from any thread but the audio one; writeFromAudioThread() from audio threads only, several at once included. An audio-thread line reaches the file and recent() only when drain() runs, and nothing calls drain() by itself: its owner calls it from a UI-thread timer. setMaxBytes() and file() take no lock, so they belong to setup, before other threads log.
Functions 1
- fn
inline void logMessage(const std::string& message)Shorthand, so a call site reads as one thing.logger.h:357