Verbosables (The Verbosable Pattern) - edcasillas/unity-common-utils GitHub Wiki
Intent
Selectively log the activity of any individual component instance to improve meaningfulness of the console messages.
Motivation
Consider a scenario where you have several instances of a prefab, for example an enemy, and this prefab has a component attached to it you want to debug. For this scenario, imagine you want to log a message to the console when something in the Update method of this component happens; just adding a Debug.Log
will lead to a polluted console showing tens or hundreds of messages, which will be hard to read and debug.
In order to isolate issues with this component and make debugging it easier, you need to filter these log messages to shown only those generated by one single instance out of the several others that exist in the scene.
We can approach this problem by defining a flag to check before sending the message to the log, so that we can selectively turn on and off log messages for individual instances of the component. We call this the verbosable flag, because it allows making the component verbose or not; we also know components making use of this flag as verbosables.
Implementation
A typical implementation of this pattern involves creating a serialized bool field to act as the verbosable flag (``), and then creating a method to filter calls to Debug.Log
, and replace usages of the letter with the new filtering method.
[SerializeField] private bool verbose;
private void debugLog(string message) {
if (verbose) Debug.Log(message);
}
This code can quickly become tedious and repetitive as you make your components verbosable. You might also end up in a situation where the code has different definitions in different components. To alleviate this, the Common Utils package includes an IVerbosable
interface defining a property (IsVerbose
) to indicate when the instance must send log messages to the console. Once the interface is implemented, the implementor can use the this.DebugLog
extension to write filtered logs. As an added benefit, log messages written using this.DebugLog
will:
- Be tagged with the name of the class and game object logging the message.
- Set into the context of the game object writing the message, so clicking on the message in Unity's console highlights the appropriate game object.
Sample Code
To make a component verbosable:
- Implement the
IVerbosable
interface - Define a source for the verbosable flag, usually a serialized field OR a property setter.
- Use the
this.DebugLog
extension method.
public class Player : MonoBehaviour, IVerbosable { // Implementation of the interface
[SerializeField] private bool verbose; // This is the source of the verbosable flag; a serialized field is optional, the source can also be a setter in the IsVerbose property.
public bool IsVerbose => verbose; // Implementation of the interface
private void Awake() => this.DebugLog("Called Awake"); // Usage of the extension method
}
When attached to a game object called LocalPlayer
, if the verbose
field is checked in the Inspector view, this component will produce the following message on Awake:
[Player:LocalPlayer] Called Awake
You can also spare this boilerplate code by inheriting your component from EnhancedMonoBehaviour
, which already implements IVerbosable
and includes a serialized field for the verbosable flag:
public class Player : EnhancedMonoBehaviour {
private void Awake() => this.DebugLog("Called Awake");
}
This code will produce the exact same result as the former.