AyCode.Core/AyCode.Services/docs/LOGGING/README.md

76 lines
4.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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\<TLogItem\>
HTTP POST writer. Extends `AcLogItemWriterBase<TLogItem>` (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<TLogItem> : AcLogItemWriterBase<TLogItem>` — the app supplies its own `TLogItem` (e.g. FruitBank's `LogItemClient : AcLogItemClient` with `[AcBinarySerializable]`, so the generated serializer lives in the app layer and AyCode.Entities stays generator-free). The non-generic `AcSignaRClientLogItemWriter` shim (= `<AcLogItemClient>`, 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<TLogger, TLogItem>`) 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<TLogger>
│ │
│ 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<TLogger, TLogItem>` (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<TLogger>` shim (= `<TLogger, AcLogItem>`) 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` |