Add detailed ride diagnostics to match logging
CI / test (push) Successful in 2m26s
Details
CI / test (push) Successful in 2m26s
Details
This commit is contained in:
parent
5a6e96b678
commit
7ad486f382
|
|
@ -109,6 +109,14 @@ public sealed class MatchGrain : IMatchGrain
|
||||||
|
|
||||||
_engine.Start(setup.FirstPlayer);
|
_engine.Start(setup.FirstPlayer);
|
||||||
RefreshSummary();
|
RefreshSummary();
|
||||||
|
|
||||||
|
_logger.LogInformation(
|
||||||
|
"Match {MatchId}: created {Seat0} vs {Seat1}, first={FirstPlayer}. {State}",
|
||||||
|
_matchId,
|
||||||
|
_seats[0].PlayerId,
|
||||||
|
_seats[1].PlayerId,
|
||||||
|
setup.FirstPlayer,
|
||||||
|
DescribeTurnState());
|
||||||
}
|
}
|
||||||
|
|
||||||
public string MatchId => _matchId;
|
public string MatchId => _matchId;
|
||||||
|
|
@ -172,8 +180,8 @@ public sealed class MatchGrain : IMatchGrain
|
||||||
await SendClockAsync(seat, now);
|
await SendClockAsync(seat, now);
|
||||||
|
|
||||||
_logger.LogInformation(
|
_logger.LogInformation(
|
||||||
"Match {MatchId}: seat {Seat} attached (resume from {Seq}, now {Now}).",
|
"Match {MatchId}: seat {Seat} attached (resume from {Seq}, now {Now}). {State}",
|
||||||
_matchId, seat, resumeFromSeq, to);
|
_matchId, seat, resumeFromSeq, to, DescribeTurnState());
|
||||||
|
|
||||||
await PersistHeaderAsync();
|
await PersistHeaderAsync();
|
||||||
|
|
||||||
|
|
@ -314,6 +322,10 @@ public sealed class MatchGrain : IMatchGrain
|
||||||
|
|
||||||
var decisionBefore = _engine.State.ActivePlayer;
|
var decisionBefore = _engine.State.ActivePlayer;
|
||||||
|
|
||||||
|
_logger.LogInformation(
|
||||||
|
"Match {MatchId}: seat {Seat} intent {IntentType} ({IntentId}) received. {State}",
|
||||||
|
_matchId, seat, DescribeIntent(intent.Intent), intentId, DescribeTurnState());
|
||||||
|
|
||||||
CommandResult result;
|
CommandResult result;
|
||||||
var commandText = string.Empty;
|
var commandText = string.Empty;
|
||||||
|
|
||||||
|
|
@ -349,6 +361,20 @@ public sealed class MatchGrain : IMatchGrain
|
||||||
await SendResultAsync(
|
await SendResultAsync(
|
||||||
seat, intentId, record.Accepted, record.Code, record.Reason, record.EventSeq, duplicate: false);
|
seat, intentId, record.Accepted, record.Code, record.Reason, record.EventSeq, duplicate: false);
|
||||||
|
|
||||||
|
if (record.Accepted)
|
||||||
|
{
|
||||||
|
_logger.LogInformation(
|
||||||
|
"Match {MatchId}: seat {Seat} intent {IntentType} ({IntentId}) accepted. {State}",
|
||||||
|
_matchId, seat, DescribeIntent(intent.Intent), intentId, DescribeTurnState());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.LogWarning(
|
||||||
|
"Match {MatchId}: seat {Seat} intent {IntentType} ({IntentId}) rejected {Code}: {Reason}. {State}",
|
||||||
|
_matchId, seat, DescribeIntent(intent.Intent), intentId, record.Code, record.Reason,
|
||||||
|
DescribeTurnState());
|
||||||
|
}
|
||||||
|
|
||||||
if (!record.Accepted)
|
if (!record.Accepted)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
@ -462,6 +488,10 @@ public sealed class MatchGrain : IMatchGrain
|
||||||
IntentRejectCode code,
|
IntentRejectCode code,
|
||||||
string reason)
|
string reason)
|
||||||
{
|
{
|
||||||
|
_logger.LogWarning(
|
||||||
|
"Match {MatchId}: seat {Seat} intent {IntentId} rejected before execution {Code}: {Reason}. {State}",
|
||||||
|
_matchId, seat, intentId, code, reason, DescribeTurnState());
|
||||||
|
|
||||||
_intents[intentId] = new IntentRecord(false, code, reason, _engine.Events.Count);
|
_intents[intentId] = new IntentRecord(false, code, reason, _engine.Events.Count);
|
||||||
|
|
||||||
await PersistIntentAsync(new PersistedIntent(
|
await PersistIntentAsync(new PersistedIntent(
|
||||||
|
|
@ -510,6 +540,15 @@ public sealed class MatchGrain : IMatchGrain
|
||||||
var from = Math.Max(1, fromSeq);
|
var from = Math.Max(1, fromSeq);
|
||||||
var events = EventProjection.ProjectRange(_engine.Events, seat, from);
|
var events = EventProjection.ProjectRange(_engine.Events, seat, from);
|
||||||
|
|
||||||
|
_logger.LogInformation(
|
||||||
|
"Match {MatchId}: events {FromSeq}..{ToSeq} to seat {Seat}: [{EventTypes}]. {State}",
|
||||||
|
_matchId,
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
seat,
|
||||||
|
string.Join(", ", events.Select(e => e.GetType().Name)),
|
||||||
|
DescribeTurnState());
|
||||||
|
|
||||||
_seats[seat].SentSeq = to;
|
_seats[seat].SentSeq = to;
|
||||||
|
|
||||||
await SendToSeatAsync(seat, new ServerEvents
|
await SendToSeatAsync(seat, new ServerEvents
|
||||||
|
|
@ -524,6 +563,22 @@ public sealed class MatchGrain : IMatchGrain
|
||||||
{
|
{
|
||||||
var to = _engine.Events.Count;
|
var to = _engine.Events.Count;
|
||||||
var view = MatchProjection.ForViewer(_engine, seat, _matchId, to, BuildClock(now));
|
var view = MatchProjection.ForViewer(_engine, seat, _matchId, to, BuildClock(now));
|
||||||
|
var legalRides = string.Join(
|
||||||
|
", ",
|
||||||
|
view.LegalIntents.OfType<RideIntent>().Select(i => i.PrintingId));
|
||||||
|
|
||||||
|
_logger.LogInformation(
|
||||||
|
"Match {MatchId}: snapshot to seat {Seat} at seq {Seq}, you={You}, active={Active}, turn={Turn}, phase={Phase}, legal={LegalCount}, rides=[{Rides}]. {State}",
|
||||||
|
_matchId,
|
||||||
|
seat,
|
||||||
|
to,
|
||||||
|
view.You,
|
||||||
|
view.ActivePlayer,
|
||||||
|
view.TurnNumber,
|
||||||
|
view.Phase,
|
||||||
|
view.LegalIntents.Count,
|
||||||
|
legalRides,
|
||||||
|
DescribeTurnState());
|
||||||
|
|
||||||
_seats[seat].SentSeq = to;
|
_seats[seat].SentSeq = to;
|
||||||
|
|
||||||
|
|
@ -780,6 +835,52 @@ public sealed class MatchGrain : IMatchGrain
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static string DescribeIntent(IntentPayload? intent) =>
|
||||||
|
intent is RideIntent ride
|
||||||
|
? $"Ride({ride.PrintingId})"
|
||||||
|
: intent?.GetType().Name ?? "null";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Diagnostic snapshot for ride issues: active player, phase, vanguard grade,
|
||||||
|
/// hand grades and cards that should be offered for a ride.
|
||||||
|
/// </summary>
|
||||||
|
private string DescribeTurnState()
|
||||||
|
{
|
||||||
|
var state = _engine.State;
|
||||||
|
var active = state.ActivePlayer;
|
||||||
|
var player = state.Players[active];
|
||||||
|
var rideGrade = _engine.VanguardGrade(active);
|
||||||
|
|
||||||
|
var vanguard = player.Vanguard is null
|
||||||
|
? "none"
|
||||||
|
: $"{player.Vanguard.PrintingId}(g{rideGrade})";
|
||||||
|
|
||||||
|
var hand = string.Join(
|
||||||
|
", ",
|
||||||
|
player.Hand.Select(card =>
|
||||||
|
{
|
||||||
|
var grade = state.Catalog.CardOf(card.PrintingId).Grade;
|
||||||
|
return $"{card.PrintingId}(g{grade})";
|
||||||
|
}));
|
||||||
|
|
||||||
|
var rideReady = state.Phase == Phase.Ride
|
||||||
|
? string.Join(
|
||||||
|
", ",
|
||||||
|
player.Hand
|
||||||
|
.Where(card =>
|
||||||
|
{
|
||||||
|
var grade = state.Catalog.CardOf(card.PrintingId).Grade;
|
||||||
|
return grade == rideGrade || grade == rideGrade + 1;
|
||||||
|
})
|
||||||
|
.Select(card => card.PrintingId)
|
||||||
|
.Distinct())
|
||||||
|
: string.Empty;
|
||||||
|
|
||||||
|
return $"active={active} turn={state.TurnNumber} phase={state.Phase} " +
|
||||||
|
$"step={state.Step} vanguard={vanguard} hand=[{hand}] " +
|
||||||
|
$"rideReady=[{rideReady}]";
|
||||||
|
}
|
||||||
|
|
||||||
private void RefreshSummary()
|
private void RefreshSummary()
|
||||||
{
|
{
|
||||||
_summary = new MatchSummary(
|
_summary = new MatchSummary(
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue