Add logging functionality with ILogger interface and implementations

This commit is contained in:
2025-10-29 01:50:42 +01:00
parent 5d86013239
commit bf15fad9ce
8 changed files with 151 additions and 1 deletions

View File

@@ -34,6 +34,7 @@ public class WeaponSystem : ISystem
if (!cost.CanAfford(context)) if (!cost.CanAfford(context))
{ {
canFire = false; canFire = false;
world.Logger.Warn("Weapon fire failed due to insufficient resources.");
world.PublishEvent(new WeaponFireFailedEvent()); world.PublishEvent(new WeaponFireFailedEvent());
break; break;
} }

View File

@@ -3,4 +3,5 @@ namespace GameCore.Config;
public class SimulationConfig public class SimulationConfig
{ {
public float GravityStrength { get; set; } = 9.81f; public float GravityStrength { get; set; } = 9.81f;
public bool LoggingEnabled { get; set; } = true;
} }

View File

@@ -3,6 +3,7 @@ using GameCore.ECS.Interfaces;
using GameCore.Events; using GameCore.Events;
using GameCore.Events.Interfaces; using GameCore.Events.Interfaces;
using GameCore.Input.Interfaces; using GameCore.Input.Interfaces;
using GameCore.Logging.Interfaces;
namespace GameCore.ECS; namespace GameCore.ECS;
@@ -11,7 +12,7 @@ namespace GameCore.ECS;
/// It manages all entities, components, and systems, and orchestrates the main game loop. /// It manages all entities, components, and systems, and orchestrates the main game loop.
/// This class is the primary point of interaction for the Engine/Presentation layer. /// This class is the primary point of interaction for the Engine/Presentation layer.
/// </summary> /// </summary>
public class World(IInputService inputService, IWorldQuery worldQuery, SimulationConfig config) public class World(IInputService inputService, IWorldQuery worldQuery, SimulationConfig config, ILogger logger)
{ {
private readonly Dictionary<int, List<IComponent>> _componentsByEntityId = new(); private readonly Dictionary<int, List<IComponent>> _componentsByEntityId = new();
private readonly EventBus _eventBus = new(); private readonly EventBus _eventBus = new();
@@ -19,6 +20,7 @@ public class World(IInputService inputService, IWorldQuery worldQuery, Simulatio
public readonly SimulationConfig Config = config; public readonly SimulationConfig Config = config;
public readonly IInputService InputService = inputService; public readonly IInputService InputService = inputService;
public readonly ILogger Logger = logger;
public readonly IWorldQuery WorldQuery = worldQuery; public readonly IWorldQuery WorldQuery = worldQuery;
private int _nextEntityId; private int _nextEntityId;

View File

@@ -0,0 +1,33 @@
using GameCore.Logging.Interfaces;
namespace GameCore.Logging;
public class CompositeLogger : ILogger
{
private readonly List<ILogger> _loggers = [];
public CompositeLogger(params ILogger[] loggers)
{
_loggers.AddRange(loggers);
}
public void Debug(string message)
{
foreach (var logger in _loggers) logger.Debug(message);
}
public void Info(string message)
{
foreach (var logger in _loggers) logger.Info(message);
}
public void Warn(string message)
{
foreach (var logger in _loggers) logger.Warn(message);
}
public void Error(string message, Exception ex = null)
{
foreach (var logger in _loggers) logger.Error(message, ex);
}
}

View File

@@ -0,0 +1,73 @@
using System.Text;
using GameCore.Logging.Interfaces;
namespace GameCore.Logging;
public class FileLogger : ILogger, IDisposable
{
private readonly object _lock = new();
private readonly LogLevel _minLogLevel = LogLevel.Debug;
private readonly StreamWriter _streamWriter;
public FileLogger(string filePath, LogLevel minLogLevel = LogLevel.Debug)
{
_minLogLevel = minLogLevel;
var stream = new FileStream(filePath, FileMode.Append, FileAccess.Write, FileShare.Read);
_streamWriter = new StreamWriter(stream, Encoding.UTF8);
_streamWriter.AutoFlush = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
public void Debug(string message)
{
Log(LogLevel.Debug, message);
}
public void Info(string message)
{
Log(LogLevel.Info, message);
}
public void Warn(string message)
{
Log(LogLevel.Warn, message);
}
public void Error(string message, Exception? ex = null)
{
Log(LogLevel.Error, message, ex);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
lock (_lock)
{
_streamWriter?.Dispose();
}
}
~FileLogger()
{
Dispose(false);
}
private void Log(LogLevel level, string message, Exception? ex = null)
{
if (level < _minLogLevel) return;
var logMessage = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss.ffff}] [{level.ToString().ToUpper()}] {message}";
lock (_lock)
{
_streamWriter.WriteLine(logMessage);
if (ex != null) _streamWriter.WriteLine(ex.ToString());
}
}
}

View File

@@ -0,0 +1,9 @@
namespace GameCore.Logging.Interfaces;
public interface ILogger
{
void Debug(string message);
void Info(string message);
void Warn(string message);
void Error(string message, Exception? ex = null);
}

View File

@@ -0,0 +1,9 @@
namespace GameCore.Logging;
public enum LogLevel
{
Debug,
Info,
Warn,
Error
}

View File

@@ -0,0 +1,22 @@
using GameCore.Logging.Interfaces;
namespace GameCore.Logging;
public class NullLogger : ILogger
{
public void Debug(string message)
{
}
public void Info(string message)
{
}
public void Warn(string message)
{
}
public void Error(string message, Exception ex = null)
{
}
}