using System.Threading.Channels; namespace LifeLab.Client; // One instance per process (server process, or the browser's WebAssembly runtime). // Write() only queues the line, so it never blocks or reorders a lifecycle method; // a single reader sends the queued lines one at a time, in the order they were written, // as POST /api/log. The server numbers them in arrival order. public sealed class LifecycleLog { private readonly HttpClient _http; private readonly Channel _queue = Channel.CreateUnbounded(new UnboundedChannelOptions { SingleReader = true }); public LifecycleLog(HttpClient http) { _http = http; _ = DrainAsync(); } public void Write(string method, bool? firstRender, int counter, string rendererName, bool isInteractive, bool isBrowser, Guid instanceId) { var fr = firstRender is null ? "-" : firstRender.Value.ToString(); var line = $"{method,-20} | firstRender={fr,-5} | Counter={counter} | " + $"Renderer={rendererName,-11} | IsInteractive={isInteractive,-5} | " + $"IsBrowser={isBrowser,-5} | Instance={instanceId.ToString("N")[..8]}"; _queue.Writer.TryWrite(line); } private async Task DrainAsync() { await foreach (var line in _queue.Reader.ReadAllAsync()) { try { using var response = await _http.PostAsync("api/log", new StringContent(line)); } catch (Exception ex) { Console.WriteLine($"LifecycleLog POST failed: {ex.Message}"); } } } }