Emulator/GbaLog.cs
namespace sGBA;
[Flags]
public enum LogLevel
{
Fatal = 0x01,
Error = 0x02,
Warn = 0x04,
Info = 0x08,
Debug = 0x10,
Stub = 0x20,
GameError = 0x40,
All = 0x7F
}
public enum LogCategory
{
GBA,
GBADebug,
GBADMA,
GBAMem,
GBAIO,
GBAVideo,
GBAAudio,
GBABIOS,
GBASave,
GBASIO,
GBAState,
GBAHardware,
Status,
Max
}
public static class GbaLog
{
private static readonly string[] CategoryNames =
[
"GBA",
"GBA Debug",
"GBA DMA",
"GBA Memory",
"GBA I/O",
"GBA Video",
"GBA Audio",
"GBA BIOS",
"GBA Savedata",
"GBA SIO",
"GBA State",
"GBA Hardware",
"Status"
];
private static readonly string[] CategoryIds =
[
"gba",
"gba.debug",
"gba.dma",
"gba.memory",
"gba.io",
"gba.video",
"gba.audio",
"gba.bios",
"gba.savedata",
"gba.sio",
"gba.serialize",
"gba.hardware",
"status"
];
private static LogLevel _defaultLevels = LogLevel.Fatal | LogLevel.Error | LogLevel.Warn | LogLevel.Debug;
private static readonly LogLevel[] _levels = new LogLevel[(int)LogCategory.Max];
private static Action<LogCategory, LogLevel, string> _backend;
static GbaLog()
{
for ( int i = 0; i < _levels.Length; i++ )
_levels[i] = _defaultLevels;
}
public static LogLevel DefaultLevels
{
get => _defaultLevels;
set
{
_defaultLevels = value;
for ( int i = 0; i < _levels.Length; i++ )
_levels[i] = value;
}
}
public static void SetBackend( Action<LogCategory, LogLevel, string> backend )
{
_backend = backend;
}
public static void SetCategoryLevels( LogCategory category, LogLevel levels )
{
_levels[(int)category] = levels;
}
public static void ResetCategoryLevels( LogCategory category )
{
_levels[(int)category] = _defaultLevels;
}
public static LogLevel GetCategoryLevels( LogCategory category )
{
return _levels[(int)category];
}
public static bool FilterTest( LogCategory category, LogLevel level )
{
return (_levels[(int)category] & level) != 0;
}
public static string GetCategoryName( LogCategory category )
{
int idx = (int)category;
if ( idx >= 0 && idx < CategoryNames.Length )
return CategoryNames[idx];
return "Unknown";
}
public static string GetCategoryId( LogCategory category )
{
int idx = (int)category;
if ( idx >= 0 && idx < CategoryIds.Length )
return CategoryIds[idx];
return "unknown";
}
public static LogCategory? CategoryById( string id )
{
for ( int i = 0; i < CategoryIds.Length; i++ )
{
if ( string.Equals( CategoryIds[i], id, StringComparison.Ordinal ) )
return (LogCategory)i;
}
return null;
}
public static void Write( LogCategory category, LogLevel level, string message )
{
if ( !FilterTest( category, level ) )
return;
if ( _backend != null )
{
_backend( category, level, message );
}
else
{
DefaultLog( category, level, message );
}
}
public static void Write( LogCategory category, LogLevel level, string format, object arg0 )
{
if ( !FilterTest( category, level ) )
return;
Write( category, level, string.Format( format, arg0 ) );
}
public static void Write( LogCategory category, LogLevel level, string format, object arg0, object arg1 )
{
if ( !FilterTest( category, level ) )
return;
Write( category, level, string.Format( format, arg0, arg1 ) );
}
public static void Write( LogCategory category, LogLevel level, string format, object arg0, object arg1, object arg2 )
{
if ( !FilterTest( category, level ) )
return;
Write( category, level, string.Format( format, arg0, arg1, arg2 ) );
}
public static void Write( LogCategory category, LogLevel level, string format, params object[] args )
{
if ( !FilterTest( category, level ) )
return;
Write( category, level, string.Format( format, args ) );
}
private static void DefaultLog( LogCategory category, LogLevel level, string message )
{
string prefix = GetCategoryName( category );
string levelTag = level switch
{
LogLevel.Fatal => "FATAL",
LogLevel.Error => "ERROR",
LogLevel.Warn => "WARN",
LogLevel.Info => "INFO",
LogLevel.Debug => "DEBUG",
LogLevel.Stub => "STUB",
LogLevel.GameError => "GAME ERROR",
_ => level.ToString()
};
Log.Info( $"[{levelTag}] {prefix}: {message}" );
}
}