🔊 Implement logger #192

Merged
alexis.drai merged 3 commits from implement-logger into main 3 years ago

@ -6,11 +6,19 @@
<StartWorkingDirectory>$(MSBuildProjectDirectory)</StartWorkingDirectory> <StartWorkingDirectory>$(MSBuildProjectDirectory)</StartWorkingDirectory>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<Content Include="NLog.config">
<BuildAction>Content</BuildAction>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.9"> <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.9">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="NLog" Version="5.0.4" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
throwConfigExceptions="true">
<targets async="true">
<target name="logfile" xsi:type="File" fileName="log.txt" />
<target name="logdebug" xsi:type="Debug" />
</targets>
<rules>
<logger name="*" minlevel="Info" writeTo="logdebug"/>
<logger name="*" minlevel="Warn" writeTo="logfile"/>
</rules>
</nlog>

@ -10,12 +10,17 @@ using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Drawing; using System.Drawing;
using System.Linq; using System.Linq;
using System.Numerics;
using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Xml.Linq;
namespace App namespace App
{ {
internal static class Program internal static class Program
{ {
private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
static async Task Main(string[] args) static async Task Main(string[] args)
{ {
// MODEL stuff // MODEL stuff
@ -27,8 +32,7 @@ namespace App
} }
catch (Exception ex) catch (Exception ex)
{ {
Console.WriteLine(ex.Message); logger.Warn(ex);
Console.WriteLine(ex.StackTrace);
masterOfCeremonies = new(new PlayerManager(), new DiceGroupManager(), null); masterOfCeremonies = new(new PlayerManager(), new DiceGroupManager(), null);
} }
@ -43,22 +47,18 @@ namespace App
PlayerDbManager playerDbManager = new(db); PlayerDbManager playerDbManager = new(db);
IEnumerable<PlayerEntity> entities = await playerDbManager.GetAll(); IEnumerable<PlayerEntity> entities = await playerDbManager.GetAll();
Debug.WriteLine("Loading players");
foreach (PlayerEntity entity in entities) foreach (PlayerEntity entity in entities)
{ {
try try
{ {
// persist them as models ! // persist them as models !
await masterOfCeremonies.GlobalPlayerManager.Add(entity.ToModel()); await masterOfCeremonies.GlobalPlayerManager.Add(entity.ToModel());
Debug.WriteLine($"{entity.ID} -- {entity.Name}");
} }
catch (Exception ex) { Debug.WriteLine($"{ex.Message}\n... Never mind"); } catch (Exception ex) { Console.WriteLine($"{ex.Message}\n... Never mind"); }
} }
} }
} }
catch (Exception ex) { Debug.WriteLine($"{ex.Message}\n... Couldn't use the database"); } catch (Exception ex) { Console.WriteLine($"{ex.Message}\n... Couldn't use the database"); }
string menuChoice = "nothing"; string menuChoice = "nothing";
@ -186,22 +186,21 @@ namespace App
// create a PlayerDbManager (and inject it with the DB) // create a PlayerDbManager (and inject it with the DB)
PlayerDbManager playerDbManager = new(db); PlayerDbManager playerDbManager = new(db);
Debug.WriteLine("Saving players");
foreach (Player model in models) foreach (Player model in models)
{ {
try // to persist them try // to persist them
{ // as entities ! { // as entities !
PlayerEntity entity = model.ToEntity(); PlayerEntity entity = model.ToEntity();
await playerDbManager.Add(entity); await playerDbManager.Add(entity);
Debug.WriteLine($"{entity.ID} -- {entity.Name}");
} }
// what if there's already a player with that name? Exception (see PlayerEntity's annotations) // what if there's already a player with that name? Exception (see PlayerEntity's annotations)
catch (ArgumentException ex) { Debug.WriteLine($"{ex.Message}\n... Never mind"); } catch (ArgumentException ex) { Console.WriteLine($"{ex.Message}\n... Never mind"); }
} }
} }
// flushing and closing NLog before quitting completely
NLog.LogManager.Shutdown();
} }
catch (Exception ex) { Debug.WriteLine($"{ex.Message}\n... Couldn't use the database"); } catch (Exception ex) { Console.WriteLine($"{ex.Message}\n... Couldn't use the database"); }
} }
private static async Task Play(MasterOfCeremonies masterOfCeremonies, string name) private static async Task Play(MasterOfCeremonies masterOfCeremonies, string name)
@ -210,7 +209,7 @@ namespace App
while (menuChoicePlay != "q") while (menuChoicePlay != "q")
{ {
Game game = await masterOfCeremonies.GameManager.GetOneByName(name); Game game = await masterOfCeremonies.GameManager.GetOneByName(name);
Console.WriteLine($"{game.GetWhoPlaysNow()}'s turn\n" + Console.WriteLine($"{PlayerToString(await game.GetWhoPlaysNow())}'s turn\n" +
"q... quit\n" + "q... quit\n" +
"h... show history\n" + "h... show history\n" +
"s... save\n" + "s... save\n" +
@ -221,17 +220,14 @@ namespace App
case "q": case "q":
break; break;
case "h": case "h":
foreach (Turn turn in game.GetHistory()) foreach (Turn turn in game.GetHistory()) { Console.WriteLine(TurnToString(turn)); }
{
Console.WriteLine(turn);
}
break; break;
case "s": case "s":
await masterOfCeremonies.GameManager.Add(game); await masterOfCeremonies.GameManager.Add(game);
break; break;
default: default:
await MasterOfCeremonies.PlayGame(game); await MasterOfCeremonies.PlayGame(game);
Console.WriteLine(game.GetHistory().Last()); Console.WriteLine(TurnToString(game.GetHistory().Last()));
break; break;
} }
} }
@ -243,7 +239,7 @@ namespace App
Console.WriteLine("which of these games?\n(choose by name)\n>"); Console.WriteLine("which of these games?\n(choose by name)\n>");
foreach (Game game in await masterOfCeremonies.GameManager.GetAll()) foreach (Game game in await masterOfCeremonies.GameManager.GetAll())
{ {
Console.WriteLine(game); Console.WriteLine(GameToString(game));
} }
name = Console.ReadLine(); name = Console.ReadLine();
return name; return name;
@ -254,7 +250,7 @@ namespace App
Console.WriteLine("Look at all them players!"); Console.WriteLine("Look at all them players!");
foreach (Player player in await masterOfCeremonies.GlobalPlayerManager.GetAll()) foreach (Player player in await masterOfCeremonies.GlobalPlayerManager.GetAll())
{ {
Console.WriteLine(player); Console.WriteLine(PlayerToString(player));
} }
} }
@ -262,7 +258,7 @@ namespace App
{ {
foreach ((string name, IEnumerable<Die> dice) in await masterOfCeremonies.DiceGroupManager.GetAll()) foreach ((string name, IEnumerable<Die> dice) in await masterOfCeremonies.DiceGroupManager.GetAll())
{ {
Console.WriteLine($"{name} -- {dice}"); Console.WriteLine($"{name} -- {dice}"); // maybe code a quick and dirty DieToString()
} }
} }
@ -335,11 +331,13 @@ namespace App
catch (ArgumentNullException ex) catch (ArgumentNullException ex)
{ {
Console.WriteLine(ex.Message); Console.WriteLine(ex.Message);
logger.Warn(ex);
} }
catch (UriFormatException ex) catch (UriFormatException ex)
{ {
Console.WriteLine("that URI was not valid"); Console.WriteLine("that URI was not valid");
Console.WriteLine(ex.Message); Console.WriteLine(ex.Message);
logger.Warn(ex);
} }
} }
} }
@ -356,7 +354,7 @@ namespace App
if (menuChoice.Equals("ok") && count == 0) if (menuChoice.Equals("ok") && count == 0)
{ {
Console.WriteLine("create at least one valid face"); Console.WriteLine("create at least one valid face");
menuChoice = ""; // persiste en dehors du scope de cette fonction menuChoice = ""; // persists outside the scope of this function
} }
} }
@ -396,7 +394,7 @@ namespace App
Player player = new(menuChoicePlayers); Player player = new(menuChoicePlayers);
if (!(await masterOfCeremonies.GlobalPlayerManager.GetAll()).Contains(player)) if (!(await masterOfCeremonies.GlobalPlayerManager.GetAll()).Contains(player))
{ {
// if the player didn't exist, now it does... this is temporary // if the player didn't exist, now it does...
await masterOfCeremonies.GlobalPlayerManager.Add(player); await masterOfCeremonies.GlobalPlayerManager.Add(player);
} }
// almost no checks, this is temporary // almost no checks, this is temporary
@ -404,12 +402,57 @@ namespace App
{ {
await result.Add(player); await result.Add(player);
} }
catch (ArgumentException ex) { Debug.WriteLine($"{ex.Message}\n... Never mind"); } catch (ArgumentException ex) { Console.WriteLine($"{ex.Message}\n... Never mind"); }
} }
} }
return result; return result;
} }
private static string TurnToString(Turn turn)
{
string[] datetime = turn.When.ToString("s", System.Globalization.CultureInfo.InvariantCulture).Split("T");
string date = datetime[0];
string time = datetime[1];
StringBuilder sb = new();
sb.AppendFormat("{0} {1} -- {2} rolled:",
date,
time,
PlayerToString(turn.Player));
foreach (KeyValuePair<Die, Face> kvp in turn.DiceNFaces)
{
sb.Append(" " + kvp.Value.StringValue);
}
return sb.ToString();
}
private async static Task<string> GameToString(Game game)
{
StringBuilder sb = new();
sb.Append($"Game: {game.Name}");
sb.Append("\nPlayers:");
foreach (Player player in game.PlayerManager.GetAll()?.Result)
{
sb.Append($" {PlayerToString(player)}");
}
sb.Append($"\nNext: {PlayerToString(await game.GetWhoPlaysNow())}");
sb.Append("\nLog:\n");
foreach (Turn turn in game.GetHistory())
{
sb.Append($"\t{TurnToString(turn)}\n");
}
return sb.ToString();
}
private static string PlayerToString(Player player)
{
return player.Name;
}
} }
} }

@ -13,6 +13,7 @@
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="NLog" Version="5.0.4" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

@ -6,13 +6,17 @@ namespace Data.EF.Players
{ {
public sealed class PlayerDbManager : IManager<PlayerEntity> public sealed class PlayerDbManager : IManager<PlayerEntity>
{ {
private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
private readonly DiceAppDbContext db; private readonly DiceAppDbContext db;
public PlayerDbManager(DiceAppDbContext db) public PlayerDbManager(DiceAppDbContext db)
{ {
if (db is null) if (db is null)
{ {
throw new ArgumentNullException(nameof(db), "param should not be null"); ArgumentNullException ex = new(nameof(db), "param should not be null");
logger.Error(ex, "attempted to construct PlayerDbManager with a null context");
throw ex;
} }
this.db = db; this.db = db;
} }
@ -27,11 +31,15 @@ namespace Data.EF.Players
{ {
if (entity is null) if (entity is null)
{ {
throw new ArgumentNullException(nameof(entity), "param should not be null"); ArgumentNullException ex = new(nameof(entity), "param should not be null");
logger.Warn(ex);
throw ex;
} }
if (string.IsNullOrWhiteSpace(entity.Name)) if (string.IsNullOrWhiteSpace(entity.Name))
{ {
throw new ArgumentException("Name property should not be null or whitespace", nameof(entity)); ArgumentException ex = new("Name property should not be null or whitespace", nameof(entity));
logger.Warn(ex);
throw ex;
} }
entity.Name = entity.Name.Trim(); entity.Name = entity.Name.Trim();
} }
@ -49,7 +57,9 @@ namespace Data.EF.Players
if (db.PlayerEntity.Where(entity => entity.Name == toAdd.Name).Any()) if (db.PlayerEntity.Where(entity => entity.Name == toAdd.Name).Any())
{ {
throw new ArgumentException("this username is already taken", nameof(toAdd)); ArgumentException ex = new("this username is already taken", nameof(toAdd));
logger.Warn(ex);
throw ex;
} }
return InternalAdd(toAdd); return InternalAdd(toAdd);
@ -59,6 +69,7 @@ namespace Data.EF.Players
{ {
EntityEntry ee = await db.PlayerEntity.AddAsync(toAdd); EntityEntry ee = await db.PlayerEntity.AddAsync(toAdd);
await db.SaveChangesAsync(); await db.SaveChangesAsync();
logger.Info("Added {0}", ee.Entity.ToString());
return (PlayerEntity)ee.Entity; return (PlayerEntity)ee.Entity;
} }
@ -116,6 +127,7 @@ namespace Data.EF.Players
if (isPresent) if (isPresent)
{ {
db.PlayerEntity.Remove(toRemove); db.PlayerEntity.Remove(toRemove);
logger.Info("Removed {0}", toRemove.ToString());
db.SaveChanges(); db.SaveChanges();
} }
} }
@ -139,11 +151,12 @@ namespace Data.EF.Players
if (before.ID != after.ID) if (before.ID != after.ID)
{ {
throw new ArgumentException("ID cannot be updated", nameof(after)); ArgumentException ex = new("ID cannot be updated", nameof(after));
logger.Warn(ex);
throw ex;
} }
return InternalUpdate(before, after); return InternalUpdate(before, after);
} }
private async Task<PlayerEntity> InternalUpdate(PlayerEntity before, PlayerEntity after) private async Task<PlayerEntity> InternalUpdate(PlayerEntity before, PlayerEntity after)

@ -6,13 +6,17 @@ namespace Data.EF.Players
{ {
public sealed class PlayerDbManager : IManager<PlayerEntity> public sealed class PlayerDbManager : IManager<PlayerEntity>
{ {
private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
private readonly DiceAppDbContext db; private readonly DiceAppDbContext db;
public PlayerDbManager(DiceAppDbContext db) public PlayerDbManager(DiceAppDbContext db)
{ {
if (db is null) if (db is null)
{ {
throw new ArgumentNullException(nameof(db), "param should not be null"); ArgumentNullException ex = new(nameof(db), "param should not be null");
logger.Error(ex, "attempted to construct PlayerDbManager with a null context");
throw ex;
} }
this.db = db; this.db = db;
} }
@ -27,11 +31,15 @@ namespace Data.EF.Players
{ {
if (entity is null) if (entity is null)
{ {
throw new ArgumentNullException(nameof(entity), "param should not be null"); ArgumentNullException ex = new(nameof(entity), "param should not be null");
logger.Warn(ex);
throw ex;
} }
if (string.IsNullOrWhiteSpace(entity.Name)) if (string.IsNullOrWhiteSpace(entity.Name))
{ {
throw new ArgumentException("Name property should not be null or whitespace", nameof(entity)); ArgumentException ex = new("Name property should not be null or whitespace", nameof(entity));
logger.Warn(ex);
throw ex;
} }
entity.Name = entity.Name.Trim(); entity.Name = entity.Name.Trim();
} }
@ -49,7 +57,9 @@ namespace Data.EF.Players
if (db.PlayerEntity.Where(entity => entity.Name == toAdd.Name).Any()) if (db.PlayerEntity.Where(entity => entity.Name == toAdd.Name).Any())
{ {
throw new ArgumentException("this username is already taken", nameof(toAdd)); ArgumentException ex = new("this username is already taken", nameof(toAdd));
logger.Warn(ex);
throw ex;
} }
return InternalAdd(toAdd); return InternalAdd(toAdd);
@ -59,6 +69,7 @@ namespace Data.EF.Players
{ {
EntityEntry ee = await db.PlayerEntity.AddAsync(toAdd); EntityEntry ee = await db.PlayerEntity.AddAsync(toAdd);
await db.SaveChangesAsync(); await db.SaveChangesAsync();
logger.Info("Added {0}", ee.Entity.ToString());
return (PlayerEntity)ee.Entity; return (PlayerEntity)ee.Entity;
} }
@ -116,6 +127,7 @@ namespace Data.EF.Players
if (isPresent) if (isPresent)
{ {
db.PlayerEntity.Remove(toRemove); db.PlayerEntity.Remove(toRemove);
logger.Info("Removed {0}", toRemove.ToString());
db.SaveChanges(); db.SaveChanges();
} }
} }
@ -139,11 +151,12 @@ namespace Data.EF.Players
if (before.ID != after.ID) if (before.ID != after.ID)
{ {
throw new ArgumentException("ID cannot be updated", nameof(after)); ArgumentException ex = new("ID cannot be updated", nameof(after));
logger.Warn(ex);
throw ex;
} }
return InternalUpdate(before, after); return InternalUpdate(before, after);
} }
private async Task<PlayerEntity> InternalUpdate(PlayerEntity before, PlayerEntity after) private async Task<PlayerEntity> InternalUpdate(PlayerEntity before, PlayerEntity after)

@ -11,7 +11,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Data", "Data\Data.csproj", "{E9683741-E603-4ED3-8088-4099D67FCA6D}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Data", "Data\Data.csproj", "{E9683741-E603-4ED3-8088-4099D67FCA6D}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Utils", "Utils\Utils\Utils.csproj", "{9300910D-9D32-4C79-8868-67D0ED56E2F3}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Utils", "Utils\Utils\Utils.csproj", "{9300910D-9D32-4C79-8868-67D0ED56E2F3}"
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution

@ -16,7 +16,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Data", "Data\Data.csproj", "{E9683741-E603-4ED3-8088-4099D67FCA6D}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Data", "Data\Data.csproj", "{E9683741-E603-4ED3-8088-4099D67FCA6D}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Utils", "Utils\Utils\Utils.csproj", "{9300910D-9D32-4C79-8868-67D0ED56E2F3}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Utils", "Utils\Utils\Utils.csproj", "{9300910D-9D32-4C79-8868-67D0ED56E2F3}"
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution

@ -169,31 +169,5 @@ namespace Model.Games
} }
return faces; return faces;
} }
/// <summary>
/// represents a Game in string format
/// </summary>
/// <returns>a Game in string format</returns>
public override string ToString()
{
StringBuilder sb = new();
sb.Append($"Game: {Name}");
sb.Append("\nPlayers:");
foreach (Player player in PlayerManager.GetAll()?.Result)
{
sb.Append($" {player.ToString()}");
}
sb.Append($"\nNext: {GetWhoPlaysNow()}");
sb.Append("\nLog:\n");
foreach (Turn turn in this.turns)
{
sb.Append($"\t{turn.ToString()}\n");
}
return sb.ToString();
}
} }
} }

@ -87,30 +87,6 @@ namespace Model.Games
return CreateWithSpecifiedTime(DateTime.UtcNow, player, diceNFaces); return CreateWithSpecifiedTime(DateTime.UtcNow, player, diceNFaces);
} }
/// <summary>
/// represents a turn in string format
/// </summary>
/// <returns>a turn in string format</returns>
public override string ToString()
{
string[] datetime = When.ToString("s", System.Globalization.CultureInfo.InvariantCulture).Split("T");
string date = datetime[0];
string time = datetime[1];
StringBuilder sb = new();
sb.AppendFormat("{0} {1} -- {2} rolled:",
date,
time,
Player.ToString());
foreach (Face face in this.diceNFaces.Values)
{
sb.Append(" " + face.StringValue);
}
return sb.ToString();
}
public bool Equals(Turn other) public bool Equals(Turn other)
{ {
return Player.Equals(other.Player) return Player.Equals(other.Player)

@ -4,4 +4,8 @@
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<PackageReference Include="NLog" Version="5.0.4" />
</ItemGroup>
</Project> </Project>

@ -30,11 +30,6 @@ namespace Model.Players
: this(player?.Name) // passes the player's name if player exists, else null : this(player?.Name) // passes the player's name if player exists, else null
{ } { }
public override string ToString()
{
return Name;
}
public bool Equals(Player other) public bool Equals(Player other)
{ {
return other is not null && Name.ToUpper() == other.Name.ToUpper(); // equality is case insensitive return other is not null && Name.ToUpper() == other.Name.ToUpper(); // equality is case insensitive

@ -142,8 +142,6 @@ namespace Tests.Model_UTs.Games
await game.PrepareNextPlayer(currentPlayer); await game.PrepareNextPlayer(currentPlayer);
} }
Debug.WriteLine(game);
// Act // Act
int actual = game.GetHistory().Count(); int actual = game.GetHistory().Count();
int expected = n; int expected = n;

@ -65,20 +65,6 @@ namespace Tests.Model_UTs.Players
Assert.Throws<ArgumentException>(action); Assert.Throws<ArgumentException>(action);
} }
[Fact]
public void TestToStringCorrectName()
{
// Arrange
string expected = "Bob";
Player player = new(expected);
// Act
string actual = player.ToString();
// Assert
Assert.Equal(expected, actual);
}
[Fact] [Fact]
public void TestEqualsFalseIfNotPlayer() public void TestEqualsFalseIfNotPlayer()
{ {

Loading…
Cancel
Save