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();
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<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.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();
}
}
}

View File

@ -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<IBackupService, BackupService>();
services.AddScoped<ICleanupService, CleanupService>();
services.AddScoped<IBookService, BookService>();
services.AddDbContext<DataContext>(options =>
{
options.UseSqlite(config.GetConnectionString("DefaultConnection"));
options.EnableSensitiveDataLogging(env.IsDevelopment());
options.EnableSensitiveDataLogging(env.IsDevelopment() || Configuration.GetLogLevel(Program.GetAppSettingFilename()).Equals("Debug"));
});
services.AddLogging(loggingBuilder =>

View File

@ -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
}

View File

@ -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<byte>();
@ -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);

View File

@ -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<IOsVersionAdapter>()).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<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
}
}