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
This commit is contained in:
Joseph Milazzo 2021-06-07 17:52:11 -05:00 committed by GitHub
parent 6f124b6f8a
commit 7dae1da92f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 81 additions and 16 deletions

View File

@ -37,6 +37,7 @@ namespace API.Controllers
{ {
var settingsDto = await _unitOfWork.SettingsRepository.GetSettingsDtoAsync(); var settingsDto = await _unitOfWork.SettingsRepository.GetSettingsDtoAsync();
settingsDto.Port = Configuration.GetPort(Program.GetAppSettingFilename()); settingsDto.Port = Configuration.GetPort(Program.GetAppSettingFilename());
settingsDto.LoggingLevel = Configuration.GetLogLevel(Program.GetAppSettingFilename());
return Ok(settingsDto); return Ok(settingsDto);
} }
@ -87,6 +88,7 @@ namespace API.Controllers
if (setting.Key == ServerSettingKey.LoggingLevel && updateSettingsDto.LoggingLevel + "" != setting.Value) if (setting.Key == ServerSettingKey.LoggingLevel && updateSettingsDto.LoggingLevel + "" != setting.Value)
{ {
setting.Value = updateSettingsDto.LoggingLevel + ""; setting.Value = updateSettingsDto.LoggingLevel + "";
Configuration.UpdateLogLevel(Program.GetAppSettingFilename(), updateSettingsDto.LoggingLevel);
_unitOfWork.SettingsRepository.Update(setting); _unitOfWork.SettingsRepository.Update(setting);
} }
} }
@ -120,7 +122,7 @@ namespace API.Controllers
[HttpGet("log-levels")] [HttpGet("log-levels")]
public ActionResult<IEnumerable<string>> GetLogLevels() public ActionResult<IEnumerable<string>> GetLogLevels()
{ {
return Ok(new [] {"Trace", "Debug", "Information", "Warning", "Critical", "None"}); return Ok(new [] {"Trace", "Debug", "Information", "Warning", "Critical"});
} }
} }
} }

View File

@ -6,6 +6,7 @@ using API.Constants;
using API.Entities; using API.Entities;
using API.Entities.Enums; using API.Entities.Enums;
using API.Services; using API.Services;
using Kavita.Common;
using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity;
namespace API.Data namespace API.Data
@ -38,10 +39,10 @@ namespace API.Data
{ {
new() {Key = ServerSettingKey.CacheDirectory, Value = CacheService.CacheDirectory}, new() {Key = ServerSettingKey.CacheDirectory, Value = CacheService.CacheDirectory},
new () {Key = ServerSettingKey.TaskScan, Value = "daily"}, 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.TaskBackup, Value = "weekly"},
new () {Key = ServerSettingKey.BackupDirectory, Value = Path.GetFullPath(Path.Join(Directory.GetCurrentDirectory(), "backups/"))}, 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) foreach (var defaultSetting in defaultSettings)
@ -54,6 +55,16 @@ namespace API.Data
} }
await context.SaveChangesAsync(); 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();
} }
} }
} }

View File

@ -1,9 +1,11 @@
using API.Data; using System;
using API.Data;
using API.Helpers; using API.Helpers;
using API.Interfaces; using API.Interfaces;
using API.Interfaces.Services; using API.Interfaces.Services;
using API.Services; using API.Services;
using API.Services.Tasks; using API.Services.Tasks;
using Kavita.Common;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
@ -34,7 +36,7 @@ namespace API.Extensions
services.AddDbContext<DataContext>(options => services.AddDbContext<DataContext>(options =>
{ {
options.UseSqlite(config.GetConnectionString("DefaultConnection")); options.UseSqlite(config.GetConnectionString("DefaultConnection"));
options.EnableSensitiveDataLogging(env.IsDevelopment()); options.EnableSensitiveDataLogging(env.IsDevelopment() || Configuration.GetLogLevel(Program.GetAppSettingFilename()).Equals("Debug"));
}); });
services.AddLogging(loggingBuilder => services.AddLogging(loggingBuilder =>

View File

@ -64,6 +64,7 @@ namespace API
await context.Database.MigrateAsync(); await context.Database.MigrateAsync();
await Seed.SeedRoles(roleManager); await Seed.SeedRoles(roleManager);
await Seed.SeedSettings(context); await Seed.SeedSettings(context);
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -107,8 +108,16 @@ namespace API
options.BeforeSend = sentryEvent => options.BeforeSend = sentryEvent =>
{ {
if (sentryEvent.Exception != null if (sentryEvent.Exception != null
&& sentryEvent.Exception.Message.Contains("[GetCoverImage] This archive cannot be read:") && sentryEvent.Exception.Message.StartsWith("[GetCoverImage]")
&& sentryEvent.Exception.Message.Contains("[BookService] ")) && 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 return null; // Don't send this event to Sentry
} }

View File

@ -230,7 +230,7 @@ namespace API.Services
} }
catch (Exception ex) 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<byte>(); return Array.Empty<byte>();
@ -407,7 +407,7 @@ namespace API.Services
} }
catch (Exception e) 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; return;
} }
_logger.LogDebug("Extracted archive to {ExtractPath} in {ElapsedMilliseconds} milliseconds", extractPath, sw.ElapsedMilliseconds); _logger.LogDebug("Extracted archive to {ExtractPath} in {ElapsedMilliseconds} milliseconds", extractPath, sw.ElapsedMilliseconds);

View File

@ -7,7 +7,7 @@ namespace Kavita.Common
{ {
public static class Configuration public static class Configuration
{ {
#region JWT Token
public static bool CheckIfJwtTokenSet(string filePath) public static bool CheckIfJwtTokenSet(string filePath)
{ {
try { try {
@ -29,8 +29,6 @@ namespace Kavita.Common
return false; return false;
} }
public static bool UpdateJwtToken(string filePath, string token) public static bool UpdateJwtToken(string filePath, string token)
{ {
try try
@ -44,7 +42,8 @@ namespace Kavita.Common
return false; return false;
} }
} }
#endregion
#region Port
public static bool UpdatePort(string filePath, int port) public static bool UpdatePort(string filePath, int port)
{ {
if (new OsInfo(Array.Empty<IOsVersionAdapter>()).IsDocker) if (new OsInfo(Array.Empty<IOsVersionAdapter>()).IsDocker)
@ -64,7 +63,6 @@ namespace Kavita.Common
return false; return false;
} }
} }
public static int GetPort(string filePath) public static int GetPort(string filePath)
{ {
const int defaultPort = 5000; const int defaultPort = 5000;
@ -89,5 +87,48 @@ namespace Kavita.Common
return defaultPort; 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<dynamic>(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
} }
} }