During the development of our game, we realized that having a centralized debug system would greatly improve our workflow. Instead of scattering debug logs across multiple scripts, we built a Debug Console that not only logs messages but also provides real-time performance metrics. This helps us monitor game performance and quickly identify bottlenecks.
Implementing a Centralized Debug Console

Goals
- Replace standard
Debug.Log
,Debug.LogWarning
, andDebug.LogError
with our own toggleable logging system. - Display logs in a GUI console within the game.
- Integrate performance monitoring for:
- FPS
- CPU & GPU usage
- RAM & VRAM usage
- Active game objects
- Draw calls
- Physics objects
- Audio sources
- Network latency (ping)
Refactoring Debug Logging
Instead of using Debug.Log
everywhere, we now use our DebugConsole
class. The logging system includes two levels of control:
- Enable/Disable all logging globally
- Choose whether logs should appear in the on-screen debug console
[SerializeField] bool logEnabled = true;
[SerializeField] bool logToGUI = false;
public static void Log(string message, Object context = default)
{
if (!instance.logEnabled)
return;
Debug.Log(message, context);
if (instance.logToGUI)
LogToGUI(message);
}
This allows us to disable logs in production builds while keeping them visible in development.
Displaying Performance Metrics
To better understand how our game performs in real-time, we integrated various performance metrics into the GUI.
Key Features
- FPS Monitoring:
Helps track frame rate drops and performance stability. - CPU and GPU Time:
Uses Unity’sRecorder
API to measure time per frame. - Memory Usage:
Profiler.GetTotalAllocatedMemoryLong()
for RAMSystemInfo.graphicsMemorySize
for VRAM
- Game Objects & Draw Calls:
Object.FindObjectsByType<GameObject>()
for active objectsUnityEngine.Rendering.OnDemandRendering.effectiveRenderFrameRate
for draw calls
- Physics and Audio Statistics:
Object.FindObjectsByType<Rigidbody>()
for physics bodiesObject.FindObjectsByType<AudioSource>()
for active sounds
- Network Ping:
Retrieves round-trip time (RTT) from Fusion’sGetPlayerRtt()
.
Optimized GUI Rendering
Instead of manually positioning each stat with hardcoded y
offsets, we use a dynamic spacing system:
float y = Screen.height - 120;
int line = 0; // Line counter for spacing
if (showFPS)
GUI.Label(new Rect(x, y - lineSpacing * line++, width, height), $"FPS: {Mathf.CeilToInt(1.0f / deltaTime)}", style);
if (showCPUTime)
GUI.Label(new Rect(x, y - lineSpacing * line++, width, height), $"CPU: {cpuTime:F2} ms", style);
if (showGPUTime)
GUI.Label(new Rect(x, y - lineSpacing * line++, width, height), $"GPU: {(gpuTime > 0 ? gpuTime.ToString("F2") : "N/A")} ms", style);
This makes it easy to add/remove stats without manually adjusting positions.

With this Debug Console, we now have real-time insights into our game’s performance, reducing debugging time and helping us optimize early. The ability to toggle logging and performance metrics individually ensures flexibility during development.
This system will be continuously improved as we integrate more network-related statistics and potential error tracking.