Skip to main content

Logging System

QWR Utilities provides an enhanced logging system that extends Unity's built-in logging capabilities with features like log categories, filtering, file output, and performance measurement. This page explains how to use and customize the logging system.

Logging System Overview​

The QWR logging system includes:

  • Log levels (Debug, Info, Warning, Error, Fatal)
  • Log categories for better organization
  • File logging capabilities
  • Conditional logging
  • Performance measurement
  • Custom log formatting
  • Editor integration

Basic Logging​

Standard Log Methods​

using QWR.Utilities.Logging;

// Basic logging
QWRLogger.Log("Player initialized");
QWRLogger.LogWarning("Low memory detected");
QWRLogger.LogError("Failed to load asset");
QWRLogger.LogFatal("Critical error occurred");

// With context object (highlights in Unity console)
QWRLogger.Log("Player initialized", gameObject);

Log Levels​

The logging system supports different log levels:

// Set the minimum log level
QWRLogger.SetLogLevel(LogLevel.Info);

// Logs with different levels
QWRLogger.LogDebug("Debug message"); // Won't show if level is Info or higher
QWRLogger.LogInfo("Info message");
QWRLogger.LogWarning("Warning message");
QWRLogger.LogError("Error message");
QWRLogger.LogFatal("Fatal error message");

// Check current log level
LogLevel currentLevel = QWRLogger.CurrentLogLevel;

Log Categories​

You can categorize logs for better organization:

// Log with categories
QWRLogger.Log("Player movement updated", LogCategory.Gameplay);
QWRLogger.LogWarning("Frame time spike detected", LogCategory.Performance);
QWRLogger.LogError("Failed to load texture", LogCategory.AssetLoading);

// Define custom categories
public static class CustomLogCategories
{
public static readonly LogCategory AI = new LogCategory("AI");
public static readonly LogCategory Networking = new LogCategory("Networking");
public static readonly LogCategory UI = new LogCategory("UI");
}

// Use custom categories
QWRLogger.Log("AI agent initialized", CustomLogCategories.AI);

Advanced Logging Features​

Conditional Logging​

Log only when certain conditions are met:

// Only log if condition is true
bool isDebugBuild = Debug.isDebugBuild;
QWRLogger.LogIf(isDebugBuild, "This only logs in debug builds");

// Log with condition and category
QWRLogger.LogIf(health < 20, "Player health critical", LogCategory.Gameplay);

// Conditional warning/error
QWRLogger.LogWarningIf(memory < 100, "Low memory warning");
QWRLogger.LogErrorIf(connection == null, "Connection failed");

Format Logging​

Format logs with variable data:

// Format with parameters
QWRLogger.LogFormat("Player {0} scored {1} points", playerName, score);

// Format with category
QWRLogger.LogFormat(LogCategory.Gameplay, "Level {0} completed in {1} seconds", levelId, time);

// Format warnings and errors
QWRLogger.LogWarningFormat("Object {0} has invalid position {1}", objectName, position);
QWRLogger.LogErrorFormat("Failed to load {0}: {1}", assetName, errorMessage);

Performance Logging​

Measure and log performance metrics:

// Simple performance measurement
using (QWRLogger.LogPerformance("ExpensiveOperation"))
{
// Code to measure
PerformExpensiveOperation();
}
// Outputs: "ExpensiveOperation completed in X.XX ms"

// With custom category
using (QWRLogger.LogPerformance("LoadLevel", LogCategory.Performance))
{
LoadLevel();
}

// With threshold (only log if execution exceeds threshold)
using (QWRLogger.LogPerformance("RenderFrame", threshold: 16.67f)) // 60fps threshold
{
RenderFrame();
}

// Manual performance measurement
QWRPerformanceMarker marker = QWRLogger.BeginPerformanceMeasurement("ComplexOperation");
// ... code to measure ...
marker.End(); // Logs the result

Log Configuration​

Global Settings​

Configure global logging settings:

// Set minimum log level
QWRLogger.SetLogLevel(LogLevel.Info);

// Enable/disable specific log categories
QWRLogger.EnableCategory(LogCategory.Gameplay);
QWRLogger.DisableCategory(LogCategory.Debug);

// Check if category is enabled
bool isEnabled = QWRLogger.IsCategoryEnabled(LogCategory.Performance);

// Enable/disable all logging
QWRLogger.EnableLogging(true);

File Logging​

Log to file for persistent records:

// Enable file logging
QWRLogger.EnableFileLogging(true);

// Configure file logging
QWRLogger.SetLogFilePath("Logs/game_log.txt");
QWRLogger.SetLogFileMaxSize(10 * 1024 * 1024); // 10 MB
QWRLogger.SetLogFileRotationCount(5); // Keep 5 backup files

// Flush logs to file immediately
QWRLogger.FlushLogFile();

Custom Log Handlers​

Register custom log handlers to process logs:

// Create a custom log handler
public class CustomLogHandler : IQWRLogHandler
{
public void HandleLog(LogLevel level, LogCategory category, string message, UnityEngine.Object context)
{
// Custom log handling (e.g., send to server, store in database)
string formattedMessage = $"[{level}][{category}] {message}";

// Example: Send log to server
NetworkManager.SendLogToServer(formattedMessage);
}
}

// Register the custom handler
QWRLogger.RegisterLogHandler(new CustomLogHandler());

// Unregister when no longer needed
QWRLogger.UnregisterLogHandler(myCustomHandler);

Editor Integration​

QWR Utilities includes editor integration for the logging system:

Log Console Window​

A custom log console window with filtering capabilities:

// This code would be in an Editor script
using QWR.Utilities.Editor.Log;
using UnityEditor;

[MenuItem("QWR/Log Console")]
public static void ShowLogConsole()
{
QWRLogConsoleWindow.ShowWindow();
}

Log Interceptor​

Intercept Unity logs in the editor:

// This code would be in an Editor script
using QWR.Utilities.Editor;
using UnityEditor;

[InitializeOnLoad]
public class LogInterceptorSetup
{
static LogInterceptorSetup()
{
LogInterceptor.EnableLogInterception(true);
LogInterceptor.OnLogIntercepted += HandleLog;
}

private static void HandleLog(string condition, string stackTrace, LogType type)
{
// Process intercepted logs
}
}

Best Practices​

Log Level Guidelines​

  • Debug: Detailed information for debugging
  • Info: General information about application flow
  • Warning: Potential issues that don't stop execution
  • Error: Errors that allow the application to continue
  • Fatal: Critical errors that may cause the application to terminate

Category Organization​

Organize log categories by system or feature:

public static class LogCategories
{
// Core systems
public static readonly LogCategory System = new LogCategory("System");
public static readonly LogCategory Performance = new LogCategory("Performance");

// Game features
public static readonly LogCategory Gameplay = new LogCategory("Gameplay");
public static readonly LogCategory UI = new LogCategory("UI");
public static readonly LogCategory Audio = new LogCategory("Audio");
public static readonly LogCategory Graphics = new LogCategory("Graphics");

// Development
public static readonly LogCategory Debug = new LogCategory("Debug");
public static readonly LogCategory Editor = new LogCategory("Editor");
}

Performance Considerations​

  • Disable debug logs in release builds
  • Use conditional logging to avoid string formatting overhead
  • Be mindful of file logging performance impact
// Efficient conditional logging
if (QWRLogger.IsLoggingEnabled(LogLevel.Debug, LogCategory.AI))
{
// Only format the string if the log will actually be output
string complexMessage = GenerateComplexLogMessage();
QWRLogger.LogDebug(complexMessage, LogCategory.AI);
}

Thread Safety​

The logging system is thread-safe and can be used from background threads:

// Logging from a background thread
System.Threading.Tasks.Task.Run(() => {
QWRLogger.Log("Background thread operation started");

// Perform background work

QWRLogger.Log("Background thread operation completed");
});

Extending the Logging System​

Creating Custom Log Formatters​

You can create custom log formatters:

// Custom log formatter
public class CustomLogFormatter : IQWRLogFormatter
{
public string FormatLogMessage(LogLevel level, LogCategory category, string message)
{
string timestamp = System.DateTime.Now.ToString("HH:mm:ss.fff");
return $"[{timestamp}][{level}][{category}] {message}";
}
}

// Register the custom formatter
QWRLogger.SetLogFormatter(new CustomLogFormatter());

Creating Log Utilities​

You can create utility classes for specific logging needs:

// Example: Network logging utility
public static class NetworkLogger
{
private static readonly LogCategory NetworkCategory = new LogCategory("Network");

public static void LogConnection(string serverId, string status)
{
QWRLogger.LogFormat(NetworkCategory, "Server {0}: {1}", serverId, status);
}

public static void LogPacket(string packetType, int size)
{
QWRLogger.LogDebugFormat(NetworkCategory, "Packet {0}: {1} bytes", packetType, size);
}

public static void LogError(string errorCode, string message)
{
QWRLogger.LogErrorFormat(NetworkCategory, "Error {0}: {1}", errorCode, message);
}
}

// Usage
NetworkLogger.LogConnection("Main", "Connected");
NetworkLogger.LogPacket("PlayerUpdate", 256);

Troubleshooting​

Logs Not Appearing​

If logs aren't appearing:

  • Check that the log level is appropriate (QWRLogger.SetLogLevel(LogLevel.Debug))
  • Verify that the category is enabled (QWRLogger.EnableCategory(myCategory))
  • Ensure logging is enabled globally (QWRLogger.EnableLogging(true))

File Logging Issues​

If file logging isn't working:

  • Check file path permissions
  • Verify the log directory exists
  • Ensure the file isn't locked by another process

Performance Impact​

If logging is impacting performance:

  • Reduce the log level in production builds
  • Use conditional logging to avoid string formatting overhead
  • Consider disabling file logging in performance-critical sections

Next Steps​

Now that you understand the logging system, you can explore: