< Summary

Information
Class: TELBlazor.Components.OptionalImplementations.Core.Services.HelperServices.SerilogLogLevelSwitcherService
Assembly: TELBlazor.Components
File(s): /home/runner/work/TELBlazor/TELBlazor/TELBlazor.Components/OptionalImplementations/Core/Services/HelperServices/SerilogLogLevelSwitcher.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 99
Coverable lines: 99
Total lines: 165
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 26
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
get_IsInitialized()100%210%
.ctor(...)100%210%
InitializeLogLevelFromAsyncSourceIfAvailable()0%7280%
GetAvailableLogLevels()100%210%
GetCurrentLogLevel()100%210%
SetLogLevel(...)0%2040%
LogAllLevels(...)100%210%
GetStoredLogLevelWithExpiration()0%2040%
StoreLogLevelWithTimestamp()0%110100%

File(s)

/home/runner/work/TELBlazor/TELBlazor/TELBlazor.Components/OptionalImplementations/Core/Services/HelperServices/SerilogLogLevelSwitcher.cs

#LineLine coverage
 1using Microsoft.Extensions.Logging;
 2using Serilog.Core;
 3using Serilog.Events;
 4using TELBlazor.Components.Core.Services.HelperServices;
 5using Blazored.LocalStorage;
 6using TELBlazor.Components.Core.Models.Logging;
 7
 8namespace TELBlazor.Components.OptionalImplementations.Core.Services.HelperServices
 9{
 10    /// <summary>
 11    /// The TELBlazor Component system uses serilog in testing etc, but you can use your own logging system instead
 12    /// </summary>
 13    public class SerilogLogLevelSwitcherService : ILogLevelSwitcherService
 14    {
 15        private readonly LoggingLevelSwitch _loggingLevelSwitch;
 16        private readonly Microsoft.Extensions.Logging.ILogger _logger;
 17        private readonly ILocalStorageService _localStorage;
 18        private const string LogLevelKey = "logLevel";
 19
 20
 021        public bool IsInitialized { get; set; } = false;
 22
 023        public SerilogLogLevelSwitcherService(
 024            LoggingLevelSwitch loggingLevelSwitch,
 025            Microsoft.Extensions.Logging.ILogger<SerilogLogLevelSwitcherService> logger,
 026            ILocalStorageService localStorage)
 027        {
 028            _loggingLevelSwitch = loggingLevelSwitch;
 029            _logger = logger;
 030            _localStorage = localStorage;
 31            //InitializeLogLevelFromAsyncSourceIfAvailable(); Must be called from the component but the component is sup
 32
 033        }
 34        public async Task InitializeLogLevelFromAsyncSourceIfAvailable()
 035        {
 036            if (IsInitialized) return;
 37
 38            try
 039            {
 040                string storedLevel = await GetStoredLogLevelWithExpiration();
 041                if (!string.IsNullOrEmpty(storedLevel))
 042                {
 043                    if (Enum.TryParse(storedLevel, true, out LogEventLevel logLevel) && logLevel > _loggingLevelSwitch.M
 044                    {
 045                        SetLogLevel(logLevel.ToString());
 046                        _logger.LogInformation("Log level initialized from local storage: {Level}", logLevel);
 047                    }
 048                }
 049                IsInitialized = true;
 050            }
 051            catch (Exception ex)
 052            {
 53                //We would do prerender check here if it is serve prerender there is no storage
 054                _logger.LogError(ex, "Error initializing log level from local storage.");
 055            }
 056        }
 57
 058        public List<string> GetAvailableLogLevels() => Enum.GetNames(typeof(LogEventLevel)).ToList();
 59
 60        public string GetCurrentLogLevel()
 061        {
 062            string logLevel = _loggingLevelSwitch.MinimumLevel.ToString();
 063            _logger.LogInformation("Fetching current log level: {Level}", logLevel);
 64
 065            return logLevel;
 066        }
 67
 68        public string SetLogLevel(string level)
 069        {
 070            LogAllLevels("Before Change");
 071            if (string.IsNullOrWhiteSpace(level))
 072            {
 073                _logger.LogWarning("Attempted to set log level with an empty value.");
 074            }
 75
 076            if (!Enum.TryParse(level, true, out LogEventLevel logLevel))
 077            {
 078                _logger.LogWarning("Invalid log level received: {Level}", level);
 79
 080            }
 81
 082            _logger.LogInformation("Changing log level from {OldLevel} to {NewLevel}",
 083                                    _loggingLevelSwitch.MinimumLevel.ToString(), logLevel.ToString());
 84
 085            _loggingLevelSwitch.MinimumLevel = logLevel;
 086            StoreLogLevelWithTimestamp(logLevel.ToString());
 087            LogAllLevels("After Change");
 088            return GetCurrentLogLevel();
 089        }
 90
 91        // Logs a message at all log levels to test visibility
 92        private void LogAllLevels(string phase)
 093        {
 094            _logger.LogTrace("[{Phase}] TRACE level log", phase);
 095            _logger.LogDebug("[{Phase}] DEBUG level log", phase);
 096            _logger.LogInformation("[{Phase}] INFORMATION level log", phase);
 097            _logger.LogWarning("[{Phase}] WARNING level log", phase);
 098            _logger.LogError("[{Phase}] ERROR level log", phase);
 099            _logger.LogCritical("[{Phase}] CRITICAL level log", phase);
 0100        }
 101
 102
 103        private async Task<string> GetStoredLogLevelWithExpiration()
 0104        {
 105            try
 0106            {
 0107                LocalStorageLogLevel? storedItem = await _localStorage.GetItemAsync<LocalStorageLogLevel>(LogLevelKey);
 108
 109
 0110                if (storedItem == null)
 0111                {
 0112                    return null;
 113                }
 114
 115
 0116                if (DateTime.UtcNow > storedItem.Expires)
 0117                {
 0118                    await _localStorage.RemoveItemAsync(LogLevelKey);
 119
 0120                    return null;
 121                }
 122
 0123                return storedItem.Level;
 124            }
 0125            catch (Exception)
 0126            {
 0127                return null; // Return null if local storage access fails
 128            }
 0129        }
 130
 131        private async Task StoreLogLevelWithTimestamp(string level)
 0132        {
 133            try
 0134            {
 0135                LocalStorageLogLevel? storedItem = await _localStorage.GetItemAsync<LocalStorageLogLevel>(LogLevelKey);
 0136                if (storedItem != null && (DateTime.UtcNow < storedItem.Expires || storedItem.Level == level))
 0137                {
 0138                    if (storedItem != null && (DateTime.UtcNow < storedItem.Expires))
 0139                    {
 140                        // Expired or different level: delete
 0141                        await _localStorage.RemoveItemAsync(LogLevelKey); // Remove the old item
 0142                    }
 143
 144                    //its already set and we dont want to extend expiry
 0145                    return;
 146                }
 147                else
 0148                {
 0149                    var newItem = new LocalStorageLogLevel
 0150                    {
 0151                        Level = level,
 0152                        Expires = DateTime.UtcNow.AddHours(24)
 0153                    };
 154
 0155                    await _localStorage.SetItemAsync(LogLevelKey, newItem);
 0156                }
 157
 0158            }
 0159            catch (Exception ex)
 0160            {
 0161                _logger.LogError(ex, "Error storing log level to local storage.");
 0162            }
 0163        }
 164    }
 165}