From 7dae1da92f131a372126fe6972e037e429048c1a Mon Sep 17 00:00:00 2001 From: Joseph Milazzo Date: Mon, 7 Jun 2021 17:52:11 -0500 Subject: [PATCH] Logging Enhancements (#285) * If the user is on Debug, allow logging DB params to the logger. Implemented the ability to change logger from UI and to keep the DB settings of LogLevel and Port in sync with appsettings. * Exclude a lot more clutter from hitting Sentry * Removed github action * Small cleanup --- API/Controllers/SettingsController.cs | 4 +- API/Data/Seed.cs | 17 +++++-- .../ApplicationServiceExtensions.cs | 8 +-- API/Program.cs | 13 ++++- API/Services/ArchiveService.cs | 4 +- Kavita.Common/Configuration.cs | 51 +++++++++++++++++-- 6 files changed, 81 insertions(+), 16 deletions(-) diff --git a/API/Controllers/SettingsController.cs b/API/Controllers/SettingsController.cs index 7ceb0443a..b0bc941af 100644 --- a/API/Controllers/SettingsController.cs +++ b/API/Controllers/SettingsController.cs @@ -37,6 +37,7 @@ namespace API.Controllers { var settingsDto = await _unitOfWork.SettingsRepository.GetSettingsDtoAsync(); settingsDto.Port = Configuration.GetPort(Program.GetAppSettingFilename()); + settingsDto.LoggingLevel = Configuration.GetLogLevel(Program.GetAppSettingFilename()); return Ok(settingsDto); } @@ -87,6 +88,7 @@ namespace API.Controllers if (setting.Key == ServerSettingKey.LoggingLevel && updateSettingsDto.LoggingLevel + "" != setting.Value) { setting.Value = updateSettingsDto.LoggingLevel + ""; + Configuration.UpdateLogLevel(Program.GetAppSettingFilename(), updateSettingsDto.LoggingLevel); _unitOfWork.SettingsRepository.Update(setting); } } @@ -120,7 +122,7 @@ namespace API.Controllers [HttpGet("log-levels")] public ActionResult> GetLogLevels() { - return Ok(new [] {"Trace", "Debug", "Information", "Warning", "Critical", "None"}); + return Ok(new [] {"Trace", "Debug", "Information", "Warning", "Critical"}); } } } \ No newline at end of file diff --git a/API/Data/Seed.cs b/API/Data/Seed.cs index a80cba4bd..511fb8c1c 100644 --- a/API/Data/Seed.cs +++ b/API/Data/Seed.cs @@ -6,6 +6,7 @@ using API.Constants; using API.Entities; using API.Entities.Enums; using API.Services; +using Kavita.Common; using Microsoft.AspNetCore.Identity; namespace API.Data @@ -38,12 +39,12 @@ namespace API.Data { new() {Key = ServerSettingKey.CacheDirectory, Value = CacheService.CacheDirectory}, new () {Key = ServerSettingKey.TaskScan, Value = "daily"}, - //new () {Key = ServerSettingKey.LoggingLevel, Value = "Information"}, + new () {Key = ServerSettingKey.LoggingLevel, Value = "Information"}, // Not used from DB, but DB is sync with appSettings.json new () {Key = ServerSettingKey.TaskBackup, Value = "weekly"}, new () {Key = ServerSettingKey.BackupDirectory, Value = Path.GetFullPath(Path.Join(Directory.GetCurrentDirectory(), "backups/"))}, - //new () {Key = ServerSettingKey.Port, Value = "5000"}, // TODO: Remove ServerSettingKey + new () {Key = ServerSettingKey.Port, Value = "5000"}, // Not used from DB, but DB is sync with appSettings.json }; - + foreach (var defaultSetting in defaultSettings) { var existing = context.ServerSetting.FirstOrDefault(s => s.Key == defaultSetting.Key); @@ -54,6 +55,16 @@ namespace API.Data } await context.SaveChangesAsync(); + + // Port and LoggingLevel are managed in appSettings.json. Update the DB values to match + var configFile = Program.GetAppSettingFilename(); + context.ServerSetting.FirstOrDefault(s => s.Key == ServerSettingKey.Port).Value = + Configuration.GetPort(configFile) + ""; + context.ServerSetting.FirstOrDefault(s => s.Key == ServerSettingKey.LoggingLevel).Value = + Configuration.GetLogLevel(configFile); + + await context.SaveChangesAsync(); + } } } \ No newline at end of file diff --git a/API/Extensions/ApplicationServiceExtensions.cs b/API/Extensions/ApplicationServiceExtensions.cs index 2169aeb67..b611cf4d6 100644 --- a/API/Extensions/ApplicationServiceExtensions.cs +++ b/API/Extensions/ApplicationServiceExtensions.cs @@ -1,9 +1,11 @@ -using API.Data; +using System; +using API.Data; using API.Helpers; using API.Interfaces; using API.Interfaces.Services; using API.Services; using API.Services.Tasks; +using Kavita.Common; using Microsoft.AspNetCore.Hosting; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; @@ -29,12 +31,12 @@ namespace API.Extensions services.AddScoped(); services.AddScoped(); services.AddScoped(); - + services.AddDbContext(options => { options.UseSqlite(config.GetConnectionString("DefaultConnection")); - options.EnableSensitiveDataLogging(env.IsDevelopment()); + options.EnableSensitiveDataLogging(env.IsDevelopment() || Configuration.GetLogLevel(Program.GetAppSettingFilename()).Equals("Debug")); }); services.AddLogging(loggingBuilder => diff --git a/API/Program.cs b/API/Program.cs index 8b43951a1..b084c2ef3 100644 --- a/API/Program.cs +++ b/API/Program.cs @@ -64,6 +64,7 @@ namespace API await context.Database.MigrateAsync(); await Seed.SeedRoles(roleManager); await Seed.SeedSettings(context); + } catch (Exception ex) { @@ -107,8 +108,16 @@ namespace API options.BeforeSend = sentryEvent => { if (sentryEvent.Exception != null - && sentryEvent.Exception.Message.Contains("[GetCoverImage] This archive cannot be read:") - && sentryEvent.Exception.Message.Contains("[BookService] ")) + && sentryEvent.Exception.Message.StartsWith("[GetCoverImage]") + && sentryEvent.Exception.Message.StartsWith("[BookService]") + && sentryEvent.Exception.Message.StartsWith("[ExtractArchive]") + && sentryEvent.Exception.Message.StartsWith("[GetSummaryInfo]") + && sentryEvent.Exception.Message.StartsWith("[GetSummaryInfo]") + && sentryEvent.Exception.Message.StartsWith("[GetNumberOfPagesFromArchive]") + && sentryEvent.Exception.Message.Contains("EPUB parsing error") + && sentryEvent.Exception.Message.Contains("Unsupported EPUB version") + && sentryEvent.Exception.Message.Contains("Incorrect EPUB") + && sentryEvent.Exception.Message.Contains("Access is Denied")) { return null; // Don't send this event to Sentry } diff --git a/API/Services/ArchiveService.cs b/API/Services/ArchiveService.cs index 4cd25d2d9..1f99334b7 100644 --- a/API/Services/ArchiveService.cs +++ b/API/Services/ArchiveService.cs @@ -230,7 +230,7 @@ namespace API.Services } catch (Exception ex) { - _logger.LogWarning(ex, "There was an error and prevented thumbnail generation on {EntryName}. Defaulting to no cover image", entryName); + _logger.LogWarning(ex, "[GetCoverImage] There was an error and prevented thumbnail generation on {EntryName}. Defaulting to no cover image", entryName); } return Array.Empty(); @@ -407,7 +407,7 @@ namespace API.Services } catch (Exception e) { - _logger.LogWarning(e, "There was a problem extracting {ArchivePath} to {ExtractPath}",archivePath, extractPath); + _logger.LogWarning(e, "[ExtractArchive] There was a problem extracting {ArchivePath} to {ExtractPath}",archivePath, extractPath); return; } _logger.LogDebug("Extracted archive to {ExtractPath} in {ElapsedMilliseconds} milliseconds", extractPath, sw.ElapsedMilliseconds); diff --git a/Kavita.Common/Configuration.cs b/Kavita.Common/Configuration.cs index 46b23cf77..755e57743 100644 --- a/Kavita.Common/Configuration.cs +++ b/Kavita.Common/Configuration.cs @@ -7,7 +7,7 @@ namespace Kavita.Common { public static class Configuration { - + #region JWT Token public static bool CheckIfJwtTokenSet(string filePath) { try { @@ -29,8 +29,6 @@ namespace Kavita.Common return false; } - - public static bool UpdateJwtToken(string filePath, string token) { try @@ -44,7 +42,8 @@ namespace Kavita.Common return false; } } - + #endregion + #region Port public static bool UpdatePort(string filePath, int port) { if (new OsInfo(Array.Empty()).IsDocker) @@ -64,7 +63,6 @@ namespace Kavita.Common return false; } } - public static int GetPort(string filePath) { const int defaultPort = 5000; @@ -89,5 +87,48 @@ namespace Kavita.Common return defaultPort; } + #endregion + #region LogLevel + public static bool UpdateLogLevel(string filePath, string logLevel) + { + try + { + var currentLevel = GetLogLevel(filePath); + var json = File.ReadAllText(filePath).Replace($"\"Default\": \"{currentLevel}\"", $"\"Default\": \"{logLevel}\""); + File.WriteAllText(filePath, json); + return true; + } + catch (Exception) + { + return false; + } + } + public static string GetLogLevel(string filePath) + { + try { + var json = File.ReadAllText(filePath); + var jsonObj = JsonSerializer.Deserialize(json); + if (jsonObj.TryGetProperty("Logging", out JsonElement tokenElement)) + { + foreach (var property in tokenElement.EnumerateObject()) + { + if (!property.Name.Equals("LogLevel")) continue; + foreach (var logProperty in property.Value.EnumerateObject()) + { + if (logProperty.Name.Equals("Default")) + { + return logProperty.Value.GetString(); + } + } + } + } + } + catch (Exception ex) { + Console.WriteLine("Error writing app settings: " + ex.Message); + } + + return "Information"; + } + #endregion } } \ No newline at end of file