Files
mxaccessgw/src/ZB.MOM.WW.MxGateway.Tests/TestSupport/RecordingLogger.cs
T
Joseph Doherty 0b4a1682c8 fix(grpc): typed alarm-feed overflow, memoized alarm snapshot, cancellable stream writes, uniform reply correlation id
- StreamAlarms: slow subscribers are completed with
  AlarmFeedSubscriberOverflowException and surface as ResourceExhausted
  (like a StreamEvents overflow) instead of warning-with-stack + Unavailable.
- GatewayAlarmMonitor.StreamAsync reuses the memoized alarm-set projection
  instead of cloning the whole set under the broadcast lock per attach; the
  prefix filter runs outside the lock.
- StreamEvents/StreamAlarms pass the call token to response writes; a write
  failure after client cancel maps to Cancelled without a warning.
- Every MxCommandReply.correlation_id now echoes the request's
  client_correlation_id (previously only constraint-denied replies did;
  normal replies leaked the internal envelope id).
2026-10-22 06:27:36 -04:00

49 lines
1.4 KiB
C#

using Microsoft.Extensions.Logging;
namespace ZB.MOM.WW.MxGateway.Tests.TestSupport;
/// <summary>
/// <see cref="ILogger{TCategoryName}"/> that records every entry's level and formatted message,
/// so a test can assert that a path logs (or does not log) at a given level.
/// </summary>
/// <typeparam name="T">The logger category type.</typeparam>
public sealed class RecordingLogger<T> : ILogger<T>
{
private readonly object _syncRoot = new();
private readonly List<(LogLevel Level, string Message, Exception? Exception)> _entries = [];
/// <summary>Gets a snapshot of the recorded entries, in order.</summary>
public IReadOnlyList<(LogLevel Level, string Message, Exception? Exception)> Entries
{
get
{
lock (_syncRoot)
{
return _entries.ToArray();
}
}
}
/// <inheritdoc />
public IDisposable? BeginScope<TState>(TState state)
where TState : notnull => null;
/// <inheritdoc />
public bool IsEnabled(LogLevel logLevel) => true;
/// <inheritdoc />
public void Log<TState>(
LogLevel logLevel,
EventId eventId,
TState state,
Exception? exception,
Func<TState, Exception?, string> formatter)
{
ArgumentNullException.ThrowIfNull(formatter);
lock (_syncRoot)
{
_entries.Add((logLevel, formatter(state, exception), exception));
}
}
}