Table of Contents

Core Logger

Switchboard includes a logging framework that writes persistent log files to disk, on any hardware platform, with minimal performance impact. With Switchboard you can record log files without allocating a single byte of memory for garbage collection. Most of the logger module is in the Core library, which has no dependencies on Unity. Switchboard's ILogger interface and LogFileWriter can be used in any C# application.

Switchboard implements an ILogger interface that is meant to be essentially interchangeable with the standard .NET ILogger interface. The main implementation of the ILogger interface is the LoggerRoot, which maintains an array of other ILogger implementations, and calls the appropriate log method on each one. These are referred to as log targets, but they have no special definition because they are just other ILogger implementations. Typically, the main ILogger instance that gets injected is a LoggerRoot with a LogFileWriter, and potentially other log targets. Custom log targets can be added to the LoggerRoot, so that logs are sent to multiple targets.

Setting the LogLevel on an ILogger implementation, like the LoggerRoot or LogFileWriter, restricts which log entries are recorded. If a log entry's LogLevel is lower than the target, then it is not recorded.

Log formatting can be customized by implementing the ILogFormatter interface. The LogFileWriter will use the implementation that you pass to its constructor for each new log entry, before it's added to the queue. Custom formatting can be applied based on the log level, the file path, line number, and method that logged the entry, or any other data available to your custom formatter. If LogFileWriter.LogCallerInfo is true, the Format method with caller information will be called, instead of the basic Format method. Append the desired log output to the empty StringMakerHandle result, and it will be written to the log file.

One caveat of the LogFileWriter is that it's designed for a loop based system, as is the case in game development. When a log entry is sent to the LogFileWriter, it is formatted and added to a queue of entries that will be flushed to disk later. This design decouples the log call from the more costly process of opening a FileStream and flushing the appropriate bytes to the disk. Therefore, LogFileWriter.FlushLogs() must be invoked periodically. In Switchboard's standard use case, this method is called at the end of each frame. In your application, you may call this method wherever it seems most appropriate. However, if logs are not flushed regularly, it becomes possible for many logs to build up in the queue, which could cause flushing to take longer.

Opening the FileStream is a costly operation. By default, Switchboard opens the FileStream and keeps it open for the duration of the application. The LogFileWriter OpenNewFile() or Open() methods will open the FileStream, creating a new file if necessary, and keep it open until Close() is called. Flushing logs will also open the FileStream if it is not already open.

Unity Logger

Switchboard includes an ILogger implementation that writes to Unity's default logger. When you use the ILogger interface provided by the BasicInjector, log entries are sent to SwitchboardLogger.Root. SwitchboardLogger.Root is the static LoggerRoot in Unity. It has the UnityLogger target assigned by default, which sends log entries to Unity's default logger. So, ILogger log entries will still be sent to the default Console logs. The BasicInjector disables the UnityLogger in built applications, outside of the Unity editor, if a Switchboard log file is created.

Unity also has an ILogger interface, but it is mostly unused by anyone for anything. So, when using Switchboard.ILogger and UnityEngine, you will have to define the following alias with your using statements: using ILogger = Switchboard.ILogger. That will make it clear that ILogger refers to the Switchboard.ILogger interface.

The SwitchboardLogger can override the default UnityLogHandler with a UnityLogHijacker that routes Debug.Log calls to the SwitchboardLogger.Root instead. The LoggerRoot still sends the hijacked Debug.Log calls to the UnityLogger, but they can also be sent to any other log target as well, like the LogFileWriter and your own custom log targets. So, even Debug.Log calls get routed to Switchboard log files. The static SwitchboardLogger has helper methods for hijacking or restoring the default UnityLogHandler for Debug.Log calls, and for disabling or enabling the UnityLogger target on the Root logger.

FileLogger

Switchboard includes a FileLogger component for Unity. The BasicInjector instantiates a FileLogger component as part of its Activation method. Enabling this component will create a log file with the specified property values, if able. If a log file cannot be opened, the component will automatically disable. FileLogger is set to disable automatically on Awake. This is so you can create a GameObject from script, add a FileLogger component, and configure its properties before attempting to enable it. For a scene or prefab FileLogger you can disable that functionality in the editor. Examine the FileLogger class to see how it uses the lower level LogFileWriter class. FileLogger implements the ILogger interface, so referencing it as an ILogger gives you access all of the expected extension methods. It can be assigned to Switchboard's root logger as a log target, or referenced directly if you prefer.

SwitchboardSettingsMenu

Example Logs

Here is an example log file, which allocates no memory for garbage collection, and performs much faster than Unity's default logs methods.

SwitchboardSettingsMenu