# Remote Log Writers Client-side log writers sending log data to remote endpoints. Source: `Loggers/`. Core logging framework: `AyCode.Core/AyCode.Core/docs/LOGGING/README.md` | Server-side GlobalLogger: `AyCode.Core.Server/docs/LOGGING/README.md`. ## AcBrowserConsoleLogWriter Blazor browser console writer. Extends `AcTextLogWriterBase` (text branch, not structured). Uses `IJSRuntime` to invoke browser console methods: | LogLevel | JS method | |----------|-----------| | Detail – Suggest | `console.info` | | Warning | `console.warn` | | Error | `console.error` | Implements `IAcLogWriterClientBase` (client-side marker). ## AcHttpClientLogItemWriter\ HTTP POST writer. Extends `AcLogItemWriterBase` (structured branch). Manages its own `HttpClient` + `HttpClientHandler`. Sends log items as JSON: ```csharp _httpClient.PostAsJsonAsync(_url, logItem).Forget(); ``` Note: `Forget()` — fire-and-forget, no await on the HTTP response. HTTP/2 by default. ## AcSignaRClientLogItemWriter SignalR log transport writer, generic in the wire type (2026-07): `AcSignaRClientLogItemWriter : AcLogItemWriterBase` — the consumer supplies its own `TLogItem : AcLogItemClient` (typically marked `[AcBinarySerializable]`, so the generated serializer lives in the consumer layer and AyCode.Entities stays generator-free). The non-generic `AcSignaRClientLogItemWriter` shim (= ``, JSON) keeps existing consumers working. Sends items to a dedicated logger hub. Manages its own `HubConnection`: ```csharp await _hubConnection.SendAsync("AddLogItem", logItem); ``` **Protocol:** default JSON; pass `AcBinaryHubProtocolOptions` in the ctor to switch the connection to AcBinary. ⚠️ **Feedback-loop guard:** the protocol's `Logger` MUST be deaf (`NullLogger.Instance`) and the writer's builder must never get `AddAcDefaults`/`ConfigureLogging` — the protocol's own logs would re-enter this uploader (log → serialize → log → … runaway loop). The server counterpart's `TLogItem` (see `AcLoggerSignalRHub`) must match the client's wire type. **Failure reporting:** never silent — connect failures, dropped items and recovery are reported once per failure state via `Console.Error` (a log channel cannot log its own errors through itself); a `connected; url: …` marker prints once per established connection. **UTC conversion note:** SignalR doesn't transmit `DateTime.Kind`. The writer calls `logItem.TimeStampUtc.ToUniversalTime()` before sending to ensure the server receives actual UTC. Connection lifecycle: `StartConnection()` waits up to 10s for `Connected` state. `StopConnection()` stops and disposes the hub. ## Remote Logging Flow Client applications can send log items to a server via SignalR: ``` Client App Server ────────── ────── AcSignaRClientLogItemWriter AcLoggerSignalRHub │ │ │ logItem.ToUniversalTime() │ │ StartConnection() │ ├──SendAsync("AddLogItem", item)──► │ │ ├─ logItem.TimeStampUtc = UtcNow │ ├─ _logger.Write(logItem) │ │ ├─ Console writer │ │ ├─ DB writer │ │ └─ ... (all server writers) ``` Note: `AcLoggerSignalRHub` overrides client's `TimeStampUtc` with `DateTime.UtcNow` server-side for authoritative timestamps. The hub is a simple `Hub` (not `AcWebSignalRHubBase`) — does NOT use tag-based dispatch. `AcLoggerSignalRHub` (2026-07): the wire type is generic — SignalR deserializes into `TLogItem`, so it must equal the client writer's `TLogItem` (with `[AcBinarySerializable(false)]` there is no polymorph dispatch). The single-generic `AcLoggerSignalRHub` shim (= ``) remains for JSON clients. The hub also logs connection lifecycle (`Logger client connected/disconnected; ConnectionId: …`) so a dead upload channel is visible on the server console. ## Key Source Files | Component | Path | |-----------|------| | Browser writer | `Loggers/AcBrowserConsoleLogWriter.cs` | | HTTP writer | `Loggers/AcHttpClientLogItemWriter.cs` | | SignalR writer | `Loggers/AcSignaRClientLogItemWriter.cs` | | Structured writer base | `AyCode.Entities/AcLogItemWriterBase.cs` | | DB writer | `AyCode.Database/AcDbLogItemWriter.cs` | | Logger hub (server) | `AyCode.Services.Server/SignalRs/AcLoggerSignalRHub.cs` |