Compare commits

..

No commits in common. "41bd9f0eb5e36fdd6ae5844433aaa03443884473" and "b2105178263496c05f12da19495006750db7d8a3" have entirely different histories.

9 changed files with 45 additions and 199 deletions

View File

@ -27,13 +27,6 @@ public abstract class AcLoggerBase : IAcLoggerBase
/// </summary> /// </summary>
public bool ShortenCategoryNames { get; set; } = true; public bool ShortenCategoryNames { get; set; } = true;
/// <summary>
/// If true, ILogger bridge calls without an EventId name resolve the real caller from the stack trace
/// (async state machines unwrapped) instead of showing "Log". Costs a few µs per enabled bridge log;
/// named AC methods (Debug/Info/...) are unaffected. Set false to restore the plain "Log" fallback.
/// </summary>
public bool ResolveBridgeCallerNames { get; set; } = true;
protected AcLoggerBase() : this(null) protected AcLoggerBase() : this(null)
{ {
} }
@ -214,11 +207,8 @@ public abstract class AcLoggerBase : IAcLoggerBase
var fullMessage = message; var fullMessage = message;
var category = ShortenCategoryNames ? GetShortCategoryName(CategoryName) : CategoryName; var category = ShortenCategoryNames ? GetShortCategoryName(CategoryName) : CategoryName;
// Explicit EventId name wins; otherwise resolve the real caller from the stack (opt-out: ResolveBridgeCallerNames). // Use eventId.Name as memberName if available, otherwise null (will show as empty, not "Log")
// EventId.Id 0 means "no id" — show the bare name without the ":0" suffix. var memberName = !string.IsNullOrEmpty(eventId.Name) ? $"{eventId.Name}:{eventId.Id}" : "Log";
var memberName = !string.IsNullOrEmpty(eventId.Name)
? eventId.Id != 0 ? $"{eventId.Name}:{eventId.Id}" : eventId.Name
: ResolveBridgeCallerNames ? ResolveCallerFromStackTrace() : "Log";
switch (logLevel) switch (logLevel)
{ {
@ -259,48 +249,6 @@ public abstract class AcLoggerBase : IAcLoggerBase
return lastDot >= 0 ? categoryName[(lastDot + 1)..] : categoryName; return lastDot >= 0 ? categoryName[(lastDot + 1)..] : categoryName;
} }
/// <summary>
/// Finds the first stack frame outside the logging infrastructure so ILogger bridge calls
/// (LogDebug/LogInformation/... extensions — these cannot carry CallerMemberName) still show
/// the real caller. Async state machines and lambdas are unwrapped (&lt;Method&gt;d__N.MoveNext -> Method).
/// Only runs when the level is enabled and no EventId name was provided.
/// </summary>
private static string ResolveCallerFromStackTrace()
{
var stackTrace = new StackTrace(skipFrames: 1, fNeedFileInfo: false);
var frameCount = Math.Min(stackTrace.FrameCount, 15);
for (var i = 0; i < frameCount; i++)
{
var method = stackTrace.GetFrame(i)?.GetMethod();
var declaringType = method?.DeclaringType;
if (method == null || declaringType == null) continue;
if (declaringType.Namespace?.StartsWith("Microsoft.Extensions.Logging", StringComparison.Ordinal) == true) continue;
if (typeof(AcLoggerBase).IsAssignableFrom(declaringType)) continue;
// Async state machine: compiler-generated "<Method>d__N" type, method is MoveNext.
var typeName = declaringType.Name;
if (typeName.Length > 2 && typeName[0] == '<')
{
var end = typeName.IndexOf('>');
if (end > 1) return typeName[1..end];
}
// Lambda / local function: "<Caller>b__0"-style method name — unwrap to the containing method.
var methodName = method.Name;
if (methodName.Length > 2 && methodName[0] == '<')
{
var end = methodName.IndexOf('>');
if (end > 1) return methodName[1..end];
}
return methodName;
}
return "Log";
}
/// <summary> /// <summary>
/// Maps Microsoft.Extensions.Logging.LogLevel to AyCode.Core.Loggers.LogLevel. /// Maps Microsoft.Extensions.Logging.LogLevel to AyCode.Core.Loggers.LogLevel.
/// </summary> /// </summary>

View File

@ -121,18 +121,3 @@ services.AddAcLoggerFactory<Logger>();
### Why this is a separate TODO from ACCORE-LOG-T-R7L3 ### Why this is a separate TODO from ACCORE-LOG-T-R7L3
ACCORE-LOG-T-R7L3 is about the **framework-level decision** (keep both patterns vs deprecate legacy). ACCORE-LOG-T-W4H9 is the **consumer-level execution** of that decision for the server plugin — independent of whether ACCORE-LOG-T-R7L3 ultimately deprecates the legacy path or keeps it alive. Migrating the server plugin removes ACCORE-LOG-I-K7M2 noise regardless of ACCORE-LOG-T-R7L3's outcome. ACCORE-LOG-T-R7L3 is about the **framework-level decision** (keep both patterns vs deprecate legacy). ACCORE-LOG-T-W4H9 is the **consumer-level execution** of that decision for the server plugin — independent of whether ACCORE-LOG-T-R7L3 ultimately deprecates the legacy path or keeps it alive. Migrating the server plugin removes ACCORE-LOG-I-K7M2 noise regardless of ACCORE-LOG-T-R7L3's outcome.
## ACCORE-LOG-T-D7S3: A SignalR log-feltöltő writer diagnosztikai loggere (szűrt writer-lista) — ⚠️ ÁTGONDOLANDÓ
**Priority:** P3 · **Type:** Feature (döntés függőben) · **Related:** `../../../AyCode.Services/docs/SIGNALR_BINARY_PROTOCOL/SIGNALR_BINARY_PROTOCOL_TODO.md#accore-sbp-t-t5r2`
**Státusz: ÁTGONDOLANDÓ — még kérdéses, kell-e egyáltalán. A jelenlegi megoldás (a hívó süket loggert — `NullLogger.Instance` — ad a writer kapcsolat-protokolljának) alapvetően jó:** a hiba-út már látható (a writer `ReportFailureOnce` Console.Error-jelentése a `SendAsync`-kivételeknél a serializer-hibákat is elkapja), csak a mély diagnosztikai trace néma.
**Cél (ha bevezetjük):** az `AcSignaRClientLogItemWriter<TLogItem>` kapcsolat-diagnosztikája süket logger helyett olyan loggert kapjon, amiből a feltöltő writer **strukturálisan ki van szűrve** — a visszacsatolási hurok (log → sorosítás → diagnosztika-log → feltöltés → …) bekötése így lehetetlen marad, a diagnosztika viszont a host TÖBBI writerére (konzol, fájl, DB — bármi regisztrált) kimegy, és automatikusan követi a jövőbeli writer-regisztrációkat.
**Megbeszélt terv (2026-07):**
1. `IAcSignalRLogWriter` marker-interfész az `AcSignaRClientLogItemWriter<TLogItem>`-re — a szűrés típus-alapú: `writers.Where(w => w is not IAcSignalRLogWriter).ToList()` (saját, materializált lista az új loggernek).
2. A diagnosztikai logger **üresen** születik — a szűrt lista a feltöltő ctorába NEM injektálható (körkörös DI: a feltöltő maga is eleme az `IEnumerable<IAcLogWriterClientBase>`-nek). A host `Build()` után tölti fel: `GetServices<IAcLogWriterClientBase>().Where(…).ToList()``SetWriters(…)`.
3. Keret-kiegészítés kell: `AcLoggerBase.SetWriters`/`AddWriters` (a `LogWriters` jelenleg protected).
4. Default szint: Debug — a soronkénti trace zajszintje protokoll-oldali kérdés, ld. ACCORE-SBP-T-T5R2.
**Ismert apró rés:** a kapcsolat-felépítés első diagnosztika-sorai még az üres loggert látják — elhanyagolható.

File diff suppressed because one or more lines are too long

View File

@ -1,45 +1,17 @@
using AyCode.Core.Consts; using AyCode.Core.Consts;
using AyCode.Core.Loggers; using AyCode.Core.Loggers;
using AyCode.Entities.Server.LogItems; using AyCode.Entities.Server.LogItems;
using Castle.Core.Logging;
using Microsoft.AspNetCore.SignalR; using Microsoft.AspNetCore.SignalR;
namespace AyCode.Services.Server.SignalRs; namespace AyCode.Services.Server.SignalRs;
/// <summary> public class AcLoggerSignalRHub<TLogger>(TLogger logger) : Hub where TLogger : IAcLoggerBase
/// Back-compat: az eredeti egy-generikusos alak a szerver-oldali <see cref="AcLogItem"/> wire-típussal —
/// a nem-generikus (JSON-os) <c>AcSignaRClientLogItemWriter</c> kliensek párja.
/// </summary>
public class AcLoggerSignalRHub<TLogger>(TLogger logger) : AcLoggerSignalRHub<TLogger, AcLogItem>(logger)
where TLogger : IAcLoggerBase;
/// <summary>
/// Kliens-log fogadó hub, generikus wire-típussal. A <typeparamref name="TLogItem"/>-nek meg kell egyeznie
/// a kliens-oldali <c>AcSignaRClientLogItemWriter&lt;TLogItem&gt;</c> típusparaméterével — a SignalR erre a
/// paraméter-típusra deserializál (AcBinary-nál a generált serializere fut, polymorph-dispatch nélkül).
/// </summary>
public class AcLoggerSignalRHub<TLogger, TLogItem>(TLogger logger) : Hub
where TLogger : IAcLoggerBase
where TLogItem : class, IAcLogItemClient
{ {
private TLogger _logger = logger; private TLogger _logger = logger;
// Kapcsolat-életciklus markerek: enélkül a szerver-konzolból nem látszik, hogy a kliens-log csatorna public void AddLogItem(AcLogItem? logItem)
// egyáltalán felépült-e (a néma loggerHub a "sosem csatlakozott" és a "csatlakozott, de nem küld" esetben ugyanúgy néz ki).
public override async Task OnConnectedAsync()
{
_logger.Info($"Logger client connected; ConnectionId: {Context.ConnectionId}");
await base.OnConnectedAsync();
}
public override async Task OnDisconnectedAsync(Exception? exception)
{
_logger.Info($"Logger client disconnected; ConnectionId: {Context.ConnectionId}{(exception == null ? string.Empty : $"; ex: {exception.GetType().Name}: {exception.Message}")}");
await base.OnDisconnectedAsync(exception);
}
public void AddLogItem(TLogItem? logItem)
{ {
try try
{ {
@ -61,8 +33,7 @@ public class AcLoggerSignalRHub<TLogger, TLogItem>(TLogger logger) : Hub
} }
catch (Exception ex) catch (Exception ex)
{ {
Console.WriteLine($@"ERROR!!! {nameof(AcLoggerSignalRHub<TLogger, TLogItem>)}->AddLogItem; ex: {ex.Message}{AcEnv.NL}{AcEnv.NL}{ex}"); Console.WriteLine($@"ERROR!!! {nameof(AcLoggerSignalRHub<TLogger>)}->AddLogItem; ex: {ex.Message}{AcEnv.NL}{AcEnv.NL}{ex}");
} }
} }
} }

View File

@ -1,33 +1,13 @@
using AyCode.Core.Enums; using AyCode.Core.Enums;
using AyCode.Core.Helpers; using AyCode.Core.Helpers;
using AyCode.Core.Loggers; using AyCode.Core.Loggers;
using AyCode.Entities; using AyCode.Entities;
using AyCode.Entities.LogItems; using AyCode.Entities.LogItems;
using AyCode.Services.SignalRs;
using Microsoft.AspNetCore.SignalR.Client; using Microsoft.AspNetCore.SignalR.Client;
namespace AyCode.Services.Loggers namespace AyCode.Services.Loggers
{ {
/// <summary> public class AcSignaRClientLogItemWriter : AcLogItemWriterBase<AcLogItemClient>, IAcLogWriterClientBase
/// Nem-generikus, JSON-protokollos alak — back-compat a meglévő fogyasztóknak
/// (wire-típus: AcLogItemClient; a szerver-oldali párja az AcLoggerSignalRHub&lt;TLogger&gt; shim).
/// </summary>
public class AcSignaRClientLogItemWriter : AcSignaRClientLogItemWriter<AcLogItemClient>
{
public AcSignaRClientLogItemWriter(string fullHubName, AppType appType = AppType.Web, LogLevel logLevel = LogLevel.Detail, string? categoryName = null)
: base(fullHubName, appType, logLevel, categoryName)
{ }
}
/// <summary>
/// SignalR log-item feltöltő writer, generikus wire-típussal. A <typeparamref name="TLogItem"/>-et a fogyasztó
/// adja (tipikusan egy [AcBinarySerializable]-lel jelölt AcLogItemClient-leszármazott — így a csatorna
/// AcBinary-protokollal mehet; a generált serializer a fogyasztó rétegében él, az AyCode.Entities generator-mentes marad).
/// Az opcionális acBinaryProtocolOptions-szel a kapcsolat az AcBinary protokollt használja;
/// enélkül a SignalR default JSON-ja megy (back-compat).
/// </summary>
public class AcSignaRClientLogItemWriter<TLogItem> : AcLogItemWriterBase<TLogItem>, IAcLogWriterClientBase
where TLogItem : class, IAcLogItemClient
{ {
private readonly HubConnection _hubConnection; private readonly HubConnection _hubConnection;
private readonly string _fullHubName; private readonly string _fullHubName;
@ -36,52 +16,29 @@ namespace AyCode.Services.Loggers
// Spam-védelem: hiba-állapotonként EGY jelentés; sikeres küldés után a kapu újraélesedik, és // Spam-védelem: hiba-állapotonként EGY jelentés; sikeres küldés után a kapu újraélesedik, és
// helyreálláskor kiírjuk, hány log-item veszett el. (Egyszerű mezők — a torz dupla-jelentés ártalmatlan.) // helyreálláskor kiírjuk, hány log-item veszett el. (Egyszerű mezők — a torz dupla-jelentés ártalmatlan.)
private bool _failureReported; private bool _failureReported;
private bool _connectedReported;
private long _droppedCount; private long _droppedCount;
public AcSignaRClientLogItemWriter(string fullHubName, AppType appType = AppType.Web, LogLevel logLevel = LogLevel.Detail, string? categoryName = null, AcBinaryHubProtocolOptions? acBinaryProtocolOptions = null) : base(appType, logLevel, categoryName) public AcSignaRClientLogItemWriter(string fullHubName, AppType appType = AppType.Web, LogLevel logLevel = LogLevel.Detail, string? categoryName = null) : base(appType, logLevel, categoryName)
{ {
_fullHubName = fullHubName; _fullHubName = fullHubName;
// VISSZACSATOLÁS-VÉDELEM: erre a builderre TILOS app-loggert kötni (AddAcDefaults / ConfigureLogging) — _hubConnection = new HubConnectionBuilder()
// a protokoll saját logja a feltöltőn át újra ide érkezne (log → sorosítás → log → … robbanó hurok). .WithUrl(fullHubName)
// AcBinary-nál ezért a hívó az opciókban EXPLICIT süket loggert adjon (pl. NullLogger.Instance),
// hogy az AddAcBinaryProtocol ??= DI-fallbackje se tölthesse fel.
var hubBuilder = new HubConnectionBuilder().WithUrl(fullHubName);
if (acBinaryProtocolOptions != null) hubBuilder.AddAcBinaryProtocol(acBinaryProtocolOptions);
_hubConnection = hubBuilder
//.WithAutomaticReconnect() //.WithAutomaticReconnect()
//.AddMessagePackProtocol(options => options.SerializerOptions = MessagePackSerializerOptions.Standard.WithSecurity(MessagePackSecurity.UntrustedData))
.Build(); .Build();
StartConnection().Forget(); // A .Forget() logger nélkül elnyelné az induló kapcsolat hibáját → jelentő wrapper.
StartConnectionReportedAsync().Forget();
} }
/// <summary>NEM dob: a kapcsolódási hibát maga jelenti (ReportFailureOnce) — a hívók (ctor fire-and-forget,
/// WriteLogItemCallback) a State-ből látják az eredményt.</summary>
public async Task StartConnection() public async Task StartConnection()
{ {
try if (_hubConnection.State == HubConnectionState.Disconnected)
{ await _hubConnection.StartAsync();
if (_hubConnection.State == HubConnectionState.Disconnected)
await _hubConnection.StartAsync();
if (_hubConnection.State != HubConnectionState.Connected) if (_hubConnection.State != HubConnectionState.Connected)
await TaskHelper.WaitToAsync(() => _hubConnection.State == HubConnectionState.Connected, 10000, 10, 25); await TaskHelper.WaitToAsync(() => _hubConnection.State == HubConnectionState.Connected, 10000, 10, 25);
// Felépülés-marker (kapcsolatonként egyszer) — enélkül a „minden csendben OK" és a „soha el sem indult"
// megkülönböztethetetlen a konzolból.
if (_hubConnection.State == HubConnectionState.Connected && !_connectedReported)
{
_connectedReported = true;
Console.WriteLine($"[{nameof(AcSignaRClientLogItemWriter)}] connected; url: {_fullHubName}");
}
}
catch (Exception ex)
{
ReportFailureOnce("connect failed", ex);
}
} }
public async Task StopConnection() public async Task StopConnection()
@ -93,7 +50,7 @@ namespace AyCode.Services.Loggers
public override void Write(AppType appType, LogLevel logLevel, string? logText, string? callerMemberName, string? categoryName, string? errorType, string? exMessage) public override void Write(AppType appType, LogLevel logLevel, string? logText, string? callerMemberName, string? categoryName, string? errorType, string? exMessage)
=> WriteLogItem(CreateLogItem(DateTime.UtcNow, appType, Environment.CurrentManagedThreadId, logLevel, logText, callerMemberName, categoryName, errorType, exMessage)); => WriteLogItem(CreateLogItem(DateTime.UtcNow, appType, Environment.CurrentManagedThreadId, logLevel, logText, callerMemberName, categoryName, errorType, exMessage));
protected override async void WriteLogItemCallback(TLogItem logItem) protected override async void WriteLogItemCallback(AcLogItemClient logItem)
{ {
// Teljes try/catch: async void — egy StartAsync/SendAsync-kivétel különben kezeletlenül szökne el. // Teljes try/catch: async void — egy StartAsync/SendAsync-kivétel különben kezeletlenül szökne el.
try try
@ -122,11 +79,15 @@ namespace AyCode.Services.Loggers
} }
} }
private async Task StartConnectionReportedAsync()
{
try { await StartConnection(); }
catch (Exception ex) { ReportFailureOnce("initial connect failed", ex); }
}
/// <summary>Hiba-állapotonként EGYSZER ír a Console.Error-ra (nem spamel) — a következő sikeres küldés élesíti újra.</summary> /// <summary>Hiba-állapotonként EGYSZER ír a Console.Error-ra (nem spamel) — a következő sikeres küldés élesíti újra.</summary>
private void ReportFailureOnce(string message, Exception? ex) private void ReportFailureOnce(string message, Exception? ex)
{ {
_connectedReported = false; // a következő sikeres felépülés újra jelentkezhessen
if (_failureReported) return; if (_failureReported) return;
_failureReported = true; _failureReported = true;
@ -143,6 +104,4 @@ namespace AyCode.Services.Loggers
_droppedCount = 0; _droppedCount = 0;
} }
} }
} }

View File

@ -762,32 +762,30 @@ public class AcBinaryHubProtocol : IHubProtocol
[Obsolete("Use ILogger via constructor parameter instead. This property will be removed in a future version.")] [Obsolete("Use ILogger via constructor parameter instead. This property will be removed in a future version.")]
public static Action<string>? DiagnosticLogger { get; set; } public static Action<string>? DiagnosticLogger { get; set; }
// A caller-t EventId.Name-ként adjuk tovább (az AyCode logger onnan veszi a CallerName-et) — enélkül
// ez a wrapper saját magát bélyegzi be (pl. [->LogDiagnostic]) a valódi hívó helyett. Ld. DebugLogArgument.
[Conditional("DEBUG")] [Conditional("DEBUG")]
private void LogDiagnostic(string message, [CallerMemberName] string? caller = null) => _logger?.LogDebug(new EventId(0, caller), message); private void LogDiagnostic(string message) => _logger?.LogDebug(message);
[Conditional("DEBUG")] [Conditional("DEBUG")]
private void LogReadSingleArgument(ReadOnlySequence<byte> argSlice, int argLength, Type targetType, [CallerMemberName] string? caller = null) private void LogReadSingleArgument(ReadOnlySequence<byte> argSlice, int argLength, Type targetType)
{ {
if (_logger == null || !_logger.IsEnabled(LogLevel.Debug)) return; if (_logger == null || !_logger.IsEnabled(LogLevel.Debug)) return;
var segmentCount = 0; var segmentCount = 0;
foreach (var _ in argSlice) segmentCount++; foreach (var _ in argSlice) segmentCount++;
_logger.LogDebug(new EventId(0, caller), "ReadSingleArgument: argLength={ArgLength}, isSingleSegment={IsSingleSegment}, segments={SegmentCount}, type={TypeName}", _logger.LogDebug("[AcBinaryHubProtocol] ReadSingleArgument: argLength={ArgLength}, isSingleSegment={IsSingleSegment}, segments={SegmentCount}, type={TypeName}",
argLength, argSlice.IsSingleSegment, segmentCount, targetType.Name); argLength, argSlice.IsSingleSegment, segmentCount, targetType.Name);
} }
[Conditional("DEBUG")] [Conditional("DEBUG")]
private void LogParseInvocation(string target, IReadOnlyList<Type> paramTypes, long remaining, [CallerMemberName] string? caller = null) private void LogParseInvocation(string target, IReadOnlyList<Type> paramTypes, long remaining)
{ {
if (_logger == null || !_logger.IsEnabled(LogLevel.Debug)) return; if (_logger == null || !_logger.IsEnabled(LogLevel.Debug)) return;
var typeNames = new string[paramTypes.Count]; var typeNames = new string[paramTypes.Count];
for (var i = 0; i < paramTypes.Count; i++) typeNames[i] = paramTypes[i].Name; for (var i = 0; i < paramTypes.Count; i++) typeNames[i] = paramTypes[i].Name;
_logger.LogDebug(new EventId(0, caller), "ParseInvocation target='{Target}'; paramTypes.Count={ParamCount}; types=[{Types}]; remaining={Remaining}", _logger.LogDebug("[AcBinaryHubProtocol] ParseInvocation target='{Target}'; paramTypes.Count={ParamCount}; types=[{Types}]; remaining={Remaining}",
target, paramTypes.Count, string.Join(", ", typeNames), remaining); target, paramTypes.Count, string.Join(", ", typeNames), remaining);
} }
@ -1385,7 +1383,7 @@ public class AcBinaryHubProtocol : IHubProtocol
} }
[Conditional("DEBUG")] [Conditional("DEBUG")]
protected void DebugLogArgument(Type runtimeType, int argBytes, object? value, [CallerMemberName] string? caller = null) protected void DebugLogArgument(Type runtimeType, int argBytes, object? value)
{ {
var kind = value switch var kind = value switch
{ {
@ -1395,20 +1393,22 @@ public class AcBinaryHubProtocol : IHubProtocol
_ => "scalar" _ => "scalar"
}; };
_logger?.LogDebug(new EventId(0, caller), "WriteArgument runtimeType={RuntimeType} argBytes={ArgBytes} valueIsNull={ValueIsNull} valueTypeKind={Kind}", runtimeType.FullName, argBytes, value == null, kind); _logger?.LogDebug("WriteArgument runtimeType={RuntimeType} argBytes={ArgBytes} valueIsNull={ValueIsNull} valueTypeKind={Kind}", runtimeType.FullName, argBytes, value == null, kind);
Console.WriteLine($"[DEBUG] WriteArgument runtimeType={runtimeType.FullName} argBytes={argBytes} valueIsNull={value == null} kind={kind}");
} }
[Conditional("DEBUG")] [Conditional("DEBUG")]
protected void DebugLogArgument(Type targetType, int argLength, long remaining, [CallerMemberName] string? caller = null) protected void DebugLogArgument(Type targetType, int argLength, long remaining)
{ {
_logger?.LogDebug(new EventId(0, caller), "ReadSingleArgument targetType={TargetType} argLength={ArgLength} remaining={Remaining}", targetType.FullName, argLength, remaining); _logger?.LogDebug("ReadSingleArgument targetType={TargetType} argLength={ArgLength} remaining={Remaining}", targetType.FullName, argLength, remaining);
Console.WriteLine($"[DEBUG] ReadSingleArgument targetType={targetType.FullName} argLength={argLength} remaining={remaining}");
} }
private object?[] ReadArguments(ref SequenceReader<byte> r, IReadOnlyList<Type> paramTypes, object? headerContext) private object?[] ReadArguments(ref SequenceReader<byte> r, IReadOnlyList<Type> paramTypes, object? headerContext)
{ {
var count = (int)ReadVarUInt(ref r); var count = (int)ReadVarUInt(ref r);
LogDiagnostic($"ReadArguments count={count}; remaining={r.Remaining}"); LogDiagnostic($"[AcBinaryHubProtocol] ReadArguments count={count}; remaining={r.Remaining}");
var args = new object?[count]; var args = new object?[count];
@ -1416,7 +1416,7 @@ public class AcBinaryHubProtocol : IHubProtocol
{ {
var targetType = i < paramTypes.Count ? paramTypes[i] : typeof(object); var targetType = i < paramTypes.Count ? paramTypes[i] : typeof(object);
LogDiagnostic($"arg[{i}] targetType={targetType.Name}; remaining={r.Remaining}"); LogDiagnostic($"[AcBinaryHubProtocol] arg[{i}] targetType={targetType.Name}; remaining={r.Remaining}");
args[i] = ReadSingleArgument(ref r, targetType, headerContext); args[i] = ReadSingleArgument(ref r, targetType, headerContext);
OnArgumentRead(args[i], i); OnArgumentRead(args[i], i);

File diff suppressed because one or more lines are too long

View File

@ -89,7 +89,7 @@ See `SIGNALR_TODO.md#accore-sig-t-m5l6`.
### Related ### Related
- `../../../AyCode.Core/docs/LOGGING/LOGGING_ISSUES.md#accore-log-i-m4c9` (sibling gap — same plugin, logger setup) - `../../../AyCode.Core/docs/LOGGING/LOGGING_ISSUES.md#accore-log-i-m4c9` (sibling gap — same plugin, logger setup)
- `ACCORE-SIG-I-K6F1` (client-side equivalent — `HubConnectionBuilder.Services` inner DI isolation forces a different workaround) - `ACCORE-SIG-I-K6F1` (client-side equivalent — `HubConnectionBuilder.Services` inner DI isolation forces a different workaround)
- Plugin doc drift: `Nop.Plugin.Misc.AIPlugin/docs/SIGNALR/README.md:22` documents `services.AddSingleton<IHubProtocol>(new AcBinaryHubProtocol())` — the actual code uses `.AddAcBinaryProtocol(opts => {...})`. **Resolved 2026-07-13** — plugin-README rewritten (AddAcBinaryProtocol; json+acbinary side-by-side registration; hub list corrected). - Plugin doc drift: `Nop.Plugin.Misc.AIPlugin/docs/SIGNALR/README.md:22` documents `services.AddSingleton<IHubProtocol>(new AcBinaryHubProtocol())` — the actual code uses `.AddAcBinaryProtocol(opts => {...})`. Doc needs a rewrite.
## Client-side Setup & DI ## Client-side Setup & DI

View File

@ -8,17 +8,6 @@
--- ---
## ACCORE-SBP-T-T5R2: Per-üzenet diagnosztikai sorok átsorolása Trace szintre
**Priority:** P2 · **Type:** Behaviour / zajcsökkentés · **Related:** `../../../AyCode.Core/docs/LOGGING/LOGGING_TODO.md#accore-log-t-d7s3`
**Probléma:** a protokoll soronkénti diagnosztikája túl magas szinten logol — `Serialize/Deserialize start/end` = **Info**, `WriteArgument`/`ReadSingleArgument`/`ReadArguments`/`ParseInvocation`/`TryParseMessage` = **Debug/Trace**. Következmény: minden hub-üzenet ~48 diagnosztika-sort termel a protokoll-loggerrel rendelkező oldalon — nagy forgalomnál konzol-áradat, és egy mindig-bekötött diagnosztikai logger (ld. ACCORE-LOG-T-D7S3) default szinten spammelne.
**Megoldás:** a per-üzenet sorok `LogTrace`-re; hiba/anomália marad Warning/Error. A `Serialize end totalSentSize=…` jellegű összegző sorok szintje mérlegelendő (Debug-on hagyva olcsó forgalmi áttekintést adnak).
**Ellenőrzendő:** az MS→AyCode szint-megfeleltetés az `AddAcLogger` hídban — a konzol-kimenet alapján MS `Trace` jelenleg Ac `Detail(0)`-ra képződik (a TryParseMessage-sorok `[Detail]`-lel jelennek meg), az Ac-enumban pedig `Detail(0) < Trace(5)`, tehát egy Detail-szintű writer a Trace-t IS átengedi. A „csend default szinten" célhoz a fogyasztó loggerek Debug(10)+ szintje és/vagy a mapping tisztázása kell.
**Érintett:** `AcBinaryHubProtocol` `Log*` segédmetódusai + `DebugLogArgument`.
## ACCORE-SBP-T-Y2R8: Per-message protocol mode selection ## ACCORE-SBP-T-Y2R8: Per-message protocol mode selection
**Priority:** P2 · **Type:** Feature **Priority:** P2 · **Type:** Feature