Compare commits
4 Commits
b210517826
...
41bd9f0eb5
| Author | SHA1 | Date |
|---|---|---|
|
|
41bd9f0eb5 | |
|
|
a6bd024d17 | |
|
|
2bb9e3a77e | |
|
|
f2c636bb1c |
|
|
@ -27,6 +27,13 @@ public abstract class AcLoggerBase : IAcLoggerBase
|
|||
/// </summary>
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
|
@ -207,8 +214,11 @@ public abstract class AcLoggerBase : IAcLoggerBase
|
|||
var fullMessage = message;
|
||||
var category = ShortenCategoryNames ? GetShortCategoryName(CategoryName) : CategoryName;
|
||||
|
||||
// Use eventId.Name as memberName if available, otherwise null (will show as empty, not "Log")
|
||||
var memberName = !string.IsNullOrEmpty(eventId.Name) ? $"{eventId.Name}:{eventId.Id}" : "Log";
|
||||
// Explicit EventId name wins; otherwise resolve the real caller from the stack (opt-out: ResolveBridgeCallerNames).
|
||||
// EventId.Id 0 means "no id" — show the bare name without the ":0" suffix.
|
||||
var memberName = !string.IsNullOrEmpty(eventId.Name)
|
||||
? eventId.Id != 0 ? $"{eventId.Name}:{eventId.Id}" : eventId.Name
|
||||
: ResolveBridgeCallerNames ? ResolveCallerFromStackTrace() : "Log";
|
||||
|
||||
switch (logLevel)
|
||||
{
|
||||
|
|
@ -249,6 +259,48 @@ public abstract class AcLoggerBase : IAcLoggerBase
|
|||
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 (<Method>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>
|
||||
/// Maps Microsoft.Extensions.Logging.LogLevel to AyCode.Core.Loggers.LogLevel.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -121,3 +121,18 @@ services.AddAcLoggerFactory<Logger>();
|
|||
|
||||
### 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-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
|
|
@ -1,17 +1,45 @@
|
|||
using AyCode.Core.Consts;
|
||||
using AyCode.Core.Consts;
|
||||
using AyCode.Core.Loggers;
|
||||
using AyCode.Entities.Server.LogItems;
|
||||
using Castle.Core.Logging;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
|
||||
namespace AyCode.Services.Server.SignalRs;
|
||||
|
||||
|
||||
public class AcLoggerSignalRHub<TLogger>(TLogger logger) : Hub where TLogger : IAcLoggerBase
|
||||
/// <summary>
|
||||
/// 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<TLogItem></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;
|
||||
|
||||
public void AddLogItem(AcLogItem? logItem)
|
||||
// Kapcsolat-életciklus markerek: enélkül a szerver-konzolból nem látszik, hogy a kliens-log csatorna
|
||||
// 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
|
||||
{
|
||||
|
|
@ -33,7 +61,8 @@ public class AcLoggerSignalRHub<TLogger>(TLogger logger) : Hub where TLogger : I
|
|||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($@"ERROR!!! {nameof(AcLoggerSignalRHub<TLogger>)}->AddLogItem; ex: {ex.Message}{AcEnv.NL}{AcEnv.NL}{ex}");
|
||||
Console.WriteLine($@"ERROR!!! {nameof(AcLoggerSignalRHub<TLogger, TLogItem>)}->AddLogItem; ex: {ex.Message}{AcEnv.NL}{AcEnv.NL}{ex}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,13 +1,33 @@
|
|||
using AyCode.Core.Enums;
|
||||
using AyCode.Core.Enums;
|
||||
using AyCode.Core.Helpers;
|
||||
using AyCode.Core.Loggers;
|
||||
using AyCode.Entities;
|
||||
using AyCode.Entities.LogItems;
|
||||
using AyCode.Services.SignalRs;
|
||||
using Microsoft.AspNetCore.SignalR.Client;
|
||||
|
||||
namespace AyCode.Services.Loggers
|
||||
{
|
||||
public class AcSignaRClientLogItemWriter : AcLogItemWriterBase<AcLogItemClient>, IAcLogWriterClientBase
|
||||
/// <summary>
|
||||
/// Nem-generikus, JSON-protokollos alak — back-compat a meglévő fogyasztóknak
|
||||
/// (wire-típus: AcLogItemClient; a szerver-oldali párja az AcLoggerSignalRHub<TLogger> 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 string _fullHubName;
|
||||
|
|
@ -16,29 +36,52 @@ namespace AyCode.Services.Loggers
|
|||
// 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.)
|
||||
private bool _failureReported;
|
||||
private bool _connectedReported;
|
||||
private long _droppedCount;
|
||||
|
||||
public AcSignaRClientLogItemWriter(string fullHubName, AppType appType = AppType.Web, LogLevel logLevel = LogLevel.Detail, string? categoryName = null) : base(appType, logLevel, categoryName)
|
||||
public AcSignaRClientLogItemWriter(string fullHubName, AppType appType = AppType.Web, LogLevel logLevel = LogLevel.Detail, string? categoryName = null, AcBinaryHubProtocolOptions? acBinaryProtocolOptions = null) : base(appType, logLevel, categoryName)
|
||||
{
|
||||
_fullHubName = fullHubName;
|
||||
|
||||
_hubConnection = new HubConnectionBuilder()
|
||||
.WithUrl(fullHubName)
|
||||
// VISSZACSATOLÁS-VÉDELEM: erre a builderre TILOS app-loggert kötni (AddAcDefaults / ConfigureLogging) —
|
||||
// a protokoll saját logja a feltöltőn át újra ide érkezne (log → sorosítás → log → … robbanó hurok).
|
||||
// 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()
|
||||
//.AddMessagePackProtocol(options => options.SerializerOptions = MessagePackSerializerOptions.Standard.WithSecurity(MessagePackSecurity.UntrustedData))
|
||||
.Build();
|
||||
|
||||
// A .Forget() logger nélkül elnyelné az induló kapcsolat hibáját → jelentő wrapper.
|
||||
StartConnectionReportedAsync().Forget();
|
||||
StartConnection().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()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_hubConnection.State == HubConnectionState.Disconnected)
|
||||
await _hubConnection.StartAsync();
|
||||
|
||||
if (_hubConnection.State != HubConnectionState.Connected)
|
||||
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()
|
||||
|
|
@ -50,7 +93,7 @@ namespace AyCode.Services.Loggers
|
|||
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));
|
||||
|
||||
protected override async void WriteLogItemCallback(AcLogItemClient logItem)
|
||||
protected override async void WriteLogItemCallback(TLogItem logItem)
|
||||
{
|
||||
// Teljes try/catch: async void — egy StartAsync/SendAsync-kivétel különben kezeletlenül szökne el.
|
||||
try
|
||||
|
|
@ -79,15 +122,11 @@ 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>
|
||||
private void ReportFailureOnce(string message, Exception? ex)
|
||||
{
|
||||
_connectedReported = false; // a következő sikeres felépülés újra jelentkezhessen
|
||||
|
||||
if (_failureReported) return;
|
||||
_failureReported = true;
|
||||
|
||||
|
|
@ -104,4 +143,6 @@ namespace AyCode.Services.Loggers
|
|||
_droppedCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -762,30 +762,32 @@ public class AcBinaryHubProtocol : IHubProtocol
|
|||
[Obsolete("Use ILogger via constructor parameter instead. This property will be removed in a future version.")]
|
||||
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")]
|
||||
private void LogDiagnostic(string message) => _logger?.LogDebug(message);
|
||||
private void LogDiagnostic(string message, [CallerMemberName] string? caller = null) => _logger?.LogDebug(new EventId(0, caller), message);
|
||||
|
||||
[Conditional("DEBUG")]
|
||||
private void LogReadSingleArgument(ReadOnlySequence<byte> argSlice, int argLength, Type targetType)
|
||||
private void LogReadSingleArgument(ReadOnlySequence<byte> argSlice, int argLength, Type targetType, [CallerMemberName] string? caller = null)
|
||||
{
|
||||
if (_logger == null || !_logger.IsEnabled(LogLevel.Debug)) return;
|
||||
|
||||
var segmentCount = 0;
|
||||
foreach (var _ in argSlice) segmentCount++;
|
||||
|
||||
_logger.LogDebug("[AcBinaryHubProtocol] ReadSingleArgument: argLength={ArgLength}, isSingleSegment={IsSingleSegment}, segments={SegmentCount}, type={TypeName}",
|
||||
_logger.LogDebug(new EventId(0, caller), "ReadSingleArgument: argLength={ArgLength}, isSingleSegment={IsSingleSegment}, segments={SegmentCount}, type={TypeName}",
|
||||
argLength, argSlice.IsSingleSegment, segmentCount, targetType.Name);
|
||||
}
|
||||
|
||||
[Conditional("DEBUG")]
|
||||
private void LogParseInvocation(string target, IReadOnlyList<Type> paramTypes, long remaining)
|
||||
private void LogParseInvocation(string target, IReadOnlyList<Type> paramTypes, long remaining, [CallerMemberName] string? caller = null)
|
||||
{
|
||||
if (_logger == null || !_logger.IsEnabled(LogLevel.Debug)) return;
|
||||
|
||||
var typeNames = new string[paramTypes.Count];
|
||||
for (var i = 0; i < paramTypes.Count; i++) typeNames[i] = paramTypes[i].Name;
|
||||
|
||||
_logger.LogDebug("[AcBinaryHubProtocol] ParseInvocation target='{Target}'; paramTypes.Count={ParamCount}; types=[{Types}]; remaining={Remaining}",
|
||||
_logger.LogDebug(new EventId(0, caller), "ParseInvocation target='{Target}'; paramTypes.Count={ParamCount}; types=[{Types}]; remaining={Remaining}",
|
||||
target, paramTypes.Count, string.Join(", ", typeNames), remaining);
|
||||
}
|
||||
|
||||
|
|
@ -1383,7 +1385,7 @@ public class AcBinaryHubProtocol : IHubProtocol
|
|||
}
|
||||
|
||||
[Conditional("DEBUG")]
|
||||
protected void DebugLogArgument(Type runtimeType, int argBytes, object? value)
|
||||
protected void DebugLogArgument(Type runtimeType, int argBytes, object? value, [CallerMemberName] string? caller = null)
|
||||
{
|
||||
var kind = value switch
|
||||
{
|
||||
|
|
@ -1393,22 +1395,20 @@ public class AcBinaryHubProtocol : IHubProtocol
|
|||
_ => "scalar"
|
||||
};
|
||||
|
||||
_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}");
|
||||
_logger?.LogDebug(new EventId(0, caller), "WriteArgument runtimeType={RuntimeType} argBytes={ArgBytes} valueIsNull={ValueIsNull} valueTypeKind={Kind}", runtimeType.FullName, argBytes, value == null, kind);
|
||||
}
|
||||
|
||||
[Conditional("DEBUG")]
|
||||
protected void DebugLogArgument(Type targetType, int argLength, long remaining)
|
||||
protected void DebugLogArgument(Type targetType, int argLength, long remaining, [CallerMemberName] string? caller = null)
|
||||
{
|
||||
_logger?.LogDebug("ReadSingleArgument targetType={TargetType} argLength={ArgLength} remaining={Remaining}", targetType.FullName, argLength, remaining);
|
||||
Console.WriteLine($"[DEBUG] ReadSingleArgument targetType={targetType.FullName} argLength={argLength} remaining={remaining}");
|
||||
_logger?.LogDebug(new EventId(0, caller), "ReadSingleArgument targetType={TargetType} argLength={ArgLength} remaining={Remaining}", targetType.FullName, argLength, remaining);
|
||||
}
|
||||
|
||||
private object?[] ReadArguments(ref SequenceReader<byte> r, IReadOnlyList<Type> paramTypes, object? headerContext)
|
||||
{
|
||||
var count = (int)ReadVarUInt(ref r);
|
||||
|
||||
LogDiagnostic($"[AcBinaryHubProtocol] ReadArguments count={count}; remaining={r.Remaining}");
|
||||
LogDiagnostic($"ReadArguments count={count}; remaining={r.Remaining}");
|
||||
|
||||
var args = new object?[count];
|
||||
|
||||
|
|
@ -1416,7 +1416,7 @@ public class AcBinaryHubProtocol : IHubProtocol
|
|||
{
|
||||
var targetType = i < paramTypes.Count ? paramTypes[i] : typeof(object);
|
||||
|
||||
LogDiagnostic($"[AcBinaryHubProtocol] arg[{i}] targetType={targetType.Name}; remaining={r.Remaining}");
|
||||
LogDiagnostic($"arg[{i}] targetType={targetType.Name}; remaining={r.Remaining}");
|
||||
|
||||
args[i] = ReadSingleArgument(ref r, targetType, headerContext);
|
||||
OnArgumentRead(args[i], i);
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -89,7 +89,7 @@ See `SIGNALR_TODO.md#accore-sig-t-m5l6`.
|
|||
### Related
|
||||
- `../../../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)
|
||||
- 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.
|
||||
- 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).
|
||||
|
||||
## Client-side Setup & DI
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,17 @@
|
|||
|
||||
---
|
||||
|
||||
## 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 ~4–8 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
|
||||
**Priority:** P2 · **Type:** Feature
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue