namespace decePubClient.Services; public interface ILoggingService { ValueTask ProcessError(Exception exception, string where, CancellationToken cancellationToken = default); ValueTask ProcessError(string message, string where, CancellationToken cancellationToken = default); ValueTask ProcessWarning(string message, string where, CancellationToken cancellationToken = default); void Process(string message, string where = default, LogLevel level = LogLevel.Information); } /// /// Writes to the browser console through ILogger and keeps errors and warnings in the IndexedDB client log, so they /// survive a reload. Never throws: logging must not break the code that is reporting a failure. /// public class LoggingService(IStorage storage, ILogger logger) : ILoggingService { public void Process(string message, string where = default, LogLevel level = LogLevel.Information) => logger.Log(level, "[{Where}] {Message}", where ?? "N/A", message); public async ValueTask ProcessError(Exception exception, string where, CancellationToken cancellationToken = default) { try { logger.LogError(exception, "[{Where}]", where); await storage.AddLog(exception, where, cancellationToken); } catch (Exception ex) { logger.LogError(ex, $"{nameof(LoggingService)}.{nameof(ProcessError)}"); } } public async ValueTask ProcessError(string message, string where, CancellationToken cancellationToken = default) { try { logger.LogError("[{Where}] {Message}", where, message); await storage.AddLog(message, where, cancellationToken); } catch (Exception ex) { logger.LogError(ex, $"{nameof(LoggingService)}.{nameof(ProcessError)}"); } } public async ValueTask ProcessWarning(string message, string where, CancellationToken cancellationToken = default) { try { logger.LogWarning("[{Where}] {Message}", where, message); await storage.AddLog(message, where, cancellationToken); } catch (Exception ex) { logger.LogError(ex, $"{nameof(LoggingService)}.{nameof(ProcessWarning)}"); } } }