Added log view for logging.net. Logging.net injection for microsofts logger. Host system data in system view

This commit is contained in:
Marcel Baumgartner
2023-03-06 03:22:38 +01:00
parent 62cd63f56b
commit 1f44becc74
14 changed files with 546 additions and 7 deletions

View File

@@ -0,0 +1,237 @@
using System.Diagnostics;
using Logging.Net;
using Logging.Net.Loggers.SB;
using Moonlight.App.Models.Misc;
using ILogger = Logging.Net.ILogger;
namespace Moonlight.App.Helpers;
public class CacheLogger : ILogger
{
private SBLogger SbLogger = new();
private List<LogEntry> Messages = new();
public LogEntry[] GetMessages()
{
lock (Messages)
{
var result = new LogEntry[Messages.Count];
Messages.CopyTo(result);
return result;
}
}
public void Clear(int messages)
{
lock (Messages)
{
Messages.RemoveRange(0, Math.Min(messages, Messages.Count));
}
}
public void Info(string s)
{
lock (Messages)
{
Messages.Add(new()
{
Level = "info",
Message = s
});
}
SbLogger.Info(s);
}
public void Debug(string s)
{
lock (Messages)
{
Messages.Add(new()
{
Level = "debug",
Message = s
});
}
SbLogger.Debug(s);
}
public void Warn(string s)
{
lock (Messages)
{
Messages.Add(new()
{
Level = "warn",
Message = s
});
}
SbLogger.Warn(s);
}
public void Error(string s)
{
lock (Messages)
{
Messages.Add(new()
{
Level = "error",
Message = s
});
}
SbLogger.Error(s);
}
public void Fatal(string s)
{
lock (Messages)
{
Messages.Add(new()
{
Level = "fatal",
Message = s
});
}
SbLogger.Fatal(s);
}
public void InfoEx(Exception ex)
{
lock (Messages)
{
Messages.Add(new()
{
Level = "info",
Message = ex.ToStringDemystified()
});
}
SbLogger.InfoEx(ex);
}
public void DebugEx(Exception ex)
{
lock (Messages)
{
Messages.Add(new()
{
Level = "debug",
Message = ex.ToStringDemystified()
});
}
SbLogger.DebugEx(ex);
}
public void WarnEx(Exception ex)
{
lock (Messages)
{
Messages.Add(new()
{
Level = "warn",
Message = ex.ToStringDemystified()
});
}
SbLogger.WarnEx(ex);
}
public void ErrorEx(Exception ex)
{
lock (Messages)
{
Messages.Add(new()
{
Level = "error",
Message = ex.ToStringDemystified()
});
}
SbLogger.ErrorEx(ex);
}
public void FatalEx(Exception ex)
{
lock (Messages)
{
Messages.Add(new()
{
Level = "fatal",
Message = ex.ToStringDemystified()
});
}
SbLogger.FatalEx(ex);
}
public LoggingConfiguration GetErrorConfiguration()
{
return SbLogger.GetErrorConfiguration();
}
public void SetErrorConfiguration(LoggingConfiguration configuration)
{
SbLogger.SetErrorConfiguration(configuration);
}
public LoggingConfiguration GetFatalConfiguration()
{
return SbLogger.GetFatalConfiguration();
}
public void SetFatalConfiguration(LoggingConfiguration configuration)
{
SbLogger.SetFatalConfiguration(configuration);
}
public LoggingConfiguration GetWarnConfiguration()
{
return SbLogger.GetWarnConfiguration();
}
public void SetWarnConfiguration(LoggingConfiguration configuration)
{
SbLogger.SetWarnConfiguration(configuration);
}
public LoggingConfiguration GetInfoConfiguration()
{
return SbLogger.GetInfoConfiguration();
}
public void SetInfoConfiguration(LoggingConfiguration configuration)
{
SbLogger.SetInfoConfiguration(configuration);
}
public LoggingConfiguration GetDebugConfiguration()
{
return SbLogger.GetDebugConfiguration();
}
public void SetDebugConfiguration(LoggingConfiguration configuration)
{
SbLogger.SetDebugConfiguration(configuration);
}
public ILoggingAddition GetAddition()
{
return SbLogger.GetAddition();
}
public void SetAddition(ILoggingAddition addition)
{
SbLogger.SetAddition(addition);
}
public bool LogCallingClass
{
get => SbLogger.LogCallingClass;
set => SbLogger.LogCallingClass = value;
}
}

View File

@@ -0,0 +1,48 @@
using System.Runtime.InteropServices;
using Logging.Net;
namespace Moonlight.App.Helpers;
public class HostSystemHelper
{
public string GetOsName()
{
try
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
// Windows platform detected
var osVersion = Environment.OSVersion.Version;
return $"Windows {osVersion.Major}.{osVersion.Minor}.{osVersion.Build}";
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
// Linux platform detected
var release = System.IO.File.ReadAllText("/etc/os-release");
var version = release.Split('\n')
.FirstOrDefault(x => x.StartsWith("VERSION_ID="))
?.Split('=')[1]
?.Replace("\"", "");
return $"Linux {version ?? release}";
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
// macOS platform detected
var osVersion = Environment.OSVersion.Version;
return $"macOS {osVersion.Major}.{osVersion.Minor}.{osVersion.Build}";
}
else
{
// Unknown platform
return "N/A";
}
}
catch (Exception e)
{
Logger.Warn("Error retrieving os information");
Logger.Warn(e);
return "N/A";
}
}
}

View File

@@ -0,0 +1,47 @@
using Logging.Net;
using ILogger = Microsoft.Extensions.Logging.ILogger;
namespace Moonlight.App.LogMigrator;
// This is used to migrate microsoft logging to logging.net
public class LogMigrator : ILogger
{
private string Name;
public LogMigrator(string name)
{
Name = name;
}
public IDisposable BeginScope<TState>(TState state)
{
return null;
}
public bool IsEnabled(LogLevel logLevel)
{
return true;
}
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter)
{
switch (logLevel)
{
case LogLevel.Critical:
Logger.Fatal($"[{Name}] {formatter(state, exception)}");
break;
case LogLevel.Warning:
Logger.Warn($"[{Name}] {formatter(state, exception)}");
break;
case LogLevel.Debug:
Logger.Debug($"[{Name}] {formatter(state, exception)}");
break;
case LogLevel.Error:
Logger.Error($"[{Name}] {formatter(state, exception)}");
break;
case LogLevel.Information:
Logger.Info($"[{Name}] {formatter(state, exception)}");
break;
}
}
}

View File

@@ -0,0 +1,12 @@
namespace Moonlight.App.LogMigrator;
public static class LogMigratorLoggerFactoryExtensions
{
public static ILoggerFactory AddCustomLogger(
this ILoggerFactory factory, out LogMigratorProvider logProvider)
{
logProvider = new LogMigratorProvider();
factory.AddProvider(logProvider);
return factory;
}
}

View File

@@ -0,0 +1,34 @@
using System.Collections.Concurrent;
namespace Moonlight.App.LogMigrator;
public class LogMigratorProvider : ILoggerProvider
{
public LogMigratorProvider() { }
public LogMigratorProvider(EventHandler onCreateLogger)
{
OnCreateLogger = onCreateLogger;
}
private ConcurrentDictionary<string, App.LogMigrator.LogMigrator> Loggers { get; set; } = new();
public ILogger CreateLogger(string categoryName)
{
App.LogMigrator.LogMigrator customLogger = Loggers.GetOrAdd(categoryName, new App.LogMigrator.LogMigrator(categoryName));
OnCreateLogger?.Invoke(this, new LogMigratorProviderEventArgs(customLogger));
return customLogger;
}
public void Dispose() { }
public event EventHandler OnCreateLogger = delegate { };
private class LogMigratorProviderEventArgs : EventArgs
{
private App.LogMigrator.LogMigrator CustomLogger { get; }
public LogMigratorProviderEventArgs(App.LogMigrator.LogMigrator logger)
{
CustomLogger = logger;
}
}
}

View File

@@ -0,0 +1,8 @@
namespace Moonlight.App.Models.Misc;
public class LogEntry
{
public string Level { get; set; }
public string Message { get; set; }
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
}

View File

@@ -0,0 +1,45 @@
using Logging.Net;
using Moonlight.App.Helpers;
using Moonlight.App.Models.Misc;
namespace Moonlight.App.Services;
public class LogService
{
public LogService()
{
Task.Run(ClearLog);
}
private async Task ClearLog()
{
while (true)
{
await Task.Delay(TimeSpan.FromMinutes(15));
if (GetMessages().Length > 500)
{
if (Logger.UsedLogger is CacheLogger cacheLogger)
{
cacheLogger.Clear(250); //TODO: config
}
else
{
Logger.Warn("Log service cannot access cache. Is Logging.Net using CacheLogger?");
}
}
}
}
public LogEntry[] GetMessages()
{
if (Logger.UsedLogger is CacheLogger cacheLogger)
{
return cacheLogger.GetMessages();
}
Logger.Warn("Log service cannot access cache. Is Logging.Net using CacheLogger?");
return Array.Empty<LogEntry>();
}
}

View File

@@ -3,6 +3,7 @@ using CurrieTechnologies.Razor.SweetAlert2;
using Logging.Net; using Logging.Net;
using Moonlight.App.Database; using Moonlight.App.Database;
using Moonlight.App.Helpers; using Moonlight.App.Helpers;
using Moonlight.App.LogMigrator;
using Moonlight.App.Repositories; using Moonlight.App.Repositories;
using Moonlight.App.Repositories.Domains; using Moonlight.App.Repositories.Domains;
using Moonlight.App.Repositories.LogEntries; using Moonlight.App.Repositories.LogEntries;
@@ -20,12 +21,21 @@ namespace Moonlight
{ {
public class Program public class Program
{ {
// App version. Change for release
public static readonly string AppVersion = $"InDev {Formatter.FormatDateOnly(DateTime.Now.Date)}";
public static void Main(string[] args) public static void Main(string[] args)
{ {
Logger.UsedLogger = new CacheLogger();
Logger.Info($"Working dir: {Directory.GetCurrentDirectory()}"); Logger.Info($"Working dir: {Directory.GetCurrentDirectory()}");
var builder = WebApplication.CreateBuilder(args); var builder = WebApplication.CreateBuilder(args);
// Switch to logging.net injection
builder.Logging.ClearProviders();
builder.Logging.AddProvider(new LogMigratorProvider());
// Add services to the container. // Add services to the container.
builder.Services.AddRazorPages(); builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor(); builder.Services.AddServerSideBlazor();
@@ -85,6 +95,7 @@ namespace Moonlight
builder.Services.AddScoped<SecurityLogService>(); builder.Services.AddScoped<SecurityLogService>();
builder.Services.AddScoped<AuditLogService>(); builder.Services.AddScoped<AuditLogService>();
builder.Services.AddScoped<ErrorLogService>(); builder.Services.AddScoped<ErrorLogService>();
builder.Services.AddScoped<LogService>();
// Support // Support
builder.Services.AddSingleton<SupportServerService>(); builder.Services.AddSingleton<SupportServerService>();
@@ -98,6 +109,7 @@ namespace Moonlight
builder.Services.AddSingleton<WingsJwtHelper>(); builder.Services.AddSingleton<WingsJwtHelper>();
builder.Services.AddScoped<WingsConsoleHelper>(); builder.Services.AddScoped<WingsConsoleHelper>();
builder.Services.AddSingleton<PaperApiHelper>(); builder.Services.AddSingleton<PaperApiHelper>();
builder.Services.AddSingleton<HostSystemHelper>();
// Third party services // Third party services

View File

@@ -10,7 +10,12 @@
</a> </a>
</li> </li>
<li class="nav-item mt-2"> <li class="nav-item mt-2">
<a class="nav-link text-active-primary ms-0 me-10 py-5 @(Index == 1 ? "active" : "")" href="/admin/system/auditlog"> <a class="nav-link text-active-primary ms-0 me-10 py-5 @(Index == 1 ? "active" : "")" href="/admin/system/logs">
Logs
</a>
</li>
<li class="nav-item mt-2">
<a class="nav-link text-active-primary ms-0 me-10 py-5 @(Index == 2 ? "active" : "")" href="/admin/system/auditlog">
AuditLog AuditLog
</a> </a>
</li> </li>

View File

@@ -12,7 +12,7 @@
@inject AuditLogEntryRepository AuditLogEntryRepository @inject AuditLogEntryRepository AuditLogEntryRepository
<OnlyAdmin> <OnlyAdmin>
<AdminSystemNavigation Index="1"/> <AdminSystemNavigation Index="2"/>
<div class="card"> <div class="card">
<div class="card-header card-header-stretch"> <div class="card-header card-header-stretch">

View File

@@ -1,9 +1,43 @@
@page "/admin/system" @page "/admin/system"
@using Moonlight.Shared.Components.Navigations @using Moonlight.Shared.Components.Navigations
@using Moonlight.App.Helpers
@inject HostSystemHelper HostSystemHelper
<OnlyAdmin> <OnlyAdmin>
<AdminSystemNavigation Index="0" /> <AdminSystemNavigation Index="0"/>
<div class="row">
<div class="col-xxl-6">
<div class="card">
<div class="card-header">
<span class="card-title">
<TL>Version</TL>
</span>
</div>
<div class="card-body">
<span class="fs-5">
<TL>You are running moonlight version</TL>
<span class="text-primary">@(Program.AppVersion)</span>
</span>
</div>
</div>
</div>
<div class="col-xxl-6">
<div class="card">
<div class="card-header">
<span class="card-title">
<TL>Operating system</TL>
</span>
</div>
<div class="card-body">
<span class="fs-5">
<TL>Moonlight is running on</TL>
<span class="text-primary">@(HostSystemHelper.GetOsName())</span>
</span>
</div>
</div>
</div>
</div>
</OnlyAdmin> </OnlyAdmin>

View File

@@ -0,0 +1,38 @@
@page "/admin/system/logs"
@using BlazorTable
@using Moonlight.App.Models.Misc
@using Moonlight.App.Services
@using Moonlight.Shared.Components.Navigations
@inject LogService LogService
@inject SmartTranslateService SmartTranslateService
<OnlyAdmin>
<AdminSystemNavigation Index="1"/>
<div class="card">
<div class="card-body">
<LazyLoader Load="Load">
<Table TableItem="LogEntry" Items="LogEntries" PageSize="25" TableHeadClass="border-bottom border-gray-200 fs-6 text-gray-600 fw-bold bg-light bg-opacity-75">
<Column TableItem="LogEntry" Title="@(SmartTranslateService.Translate("Time"))" Field="@(x => x.CreatedAt)" Sortable="true" Filterable="false"></Column>
<Column TableItem="LogEntry" Title="@(SmartTranslateService.Translate("Log level"))" Field="@(x => x.Level)" Sortable="true" Filterable="false"></Column>
<Column TableItem="LogEntry" Title="@(SmartTranslateService.Translate("Log message"))" Field="@(x => x.Message)" Sortable="false" Filterable="true"></Column>
<Pager ShowPageNumber="true" ShowTotalCount="true"/>
</Table>
</LazyLoader>
</div>
</div>
</OnlyAdmin>
@code
{
private LogEntry[] LogEntries;
private Task Load(LazyLoader arg)
{
LogEntries = LogService.GetMessages();
return Task.CompletedTask;
}
}

View File

@@ -31,10 +31,22 @@ build_metadata.AdditionalFiles.CssScope =
build_metadata.AdditionalFiles.TargetPath = U2hhcmVkXENvbXBvbmVudHNcQWxlcnRzXFNldHVwQ29tcGxldGVkQWxlcnQucmF6b3I= build_metadata.AdditionalFiles.TargetPath = U2hhcmVkXENvbXBvbmVudHNcQWxlcnRzXFNldHVwQ29tcGxldGVkQWxlcnQucmF6b3I=
build_metadata.AdditionalFiles.CssScope = build_metadata.AdditionalFiles.CssScope =
[C:/Users/marce/GitHub/Moonlight-Panel/Moonlight/Moonlight/Shared/Components/AuditLogEntrys/AuditLogEntryChangePassword.razor]
build_metadata.AdditionalFiles.TargetPath = U2hhcmVkXENvbXBvbmVudHNcQXVkaXRMb2dFbnRyeXNcQXVkaXRMb2dFbnRyeUNoYW5nZVBhc3N3b3JkLnJhem9y
build_metadata.AdditionalFiles.CssScope =
[C:/Users/marce/GitHub/Moonlight-Panel/Moonlight/Moonlight/Shared/Components/AuditLogEntrys/AuditLogEntryChangePowerState.razor]
build_metadata.AdditionalFiles.TargetPath = U2hhcmVkXENvbXBvbmVudHNcQXVkaXRMb2dFbnRyeXNcQXVkaXRMb2dFbnRyeUNoYW5nZVBvd2VyU3RhdGUucmF6b3I=
build_metadata.AdditionalFiles.CssScope =
[C:/Users/marce/GitHub/Moonlight-Panel/Moonlight/Moonlight/Shared/Components/AuditLogEntrys/AuditLogEntryLogin.razor] [C:/Users/marce/GitHub/Moonlight-Panel/Moonlight/Moonlight/Shared/Components/AuditLogEntrys/AuditLogEntryLogin.razor]
build_metadata.AdditionalFiles.TargetPath = U2hhcmVkXENvbXBvbmVudHNcQXVkaXRMb2dFbnRyeXNcQXVkaXRMb2dFbnRyeUxvZ2luLnJhem9y build_metadata.AdditionalFiles.TargetPath = U2hhcmVkXENvbXBvbmVudHNcQXVkaXRMb2dFbnRyeXNcQXVkaXRMb2dFbnRyeUxvZ2luLnJhem9y
build_metadata.AdditionalFiles.CssScope = build_metadata.AdditionalFiles.CssScope =
[C:/Users/marce/GitHub/Moonlight-Panel/Moonlight/Moonlight/Shared/Components/AuditLogEntrys/AuditLogEntryRegister.razor]
build_metadata.AdditionalFiles.TargetPath = U2hhcmVkXENvbXBvbmVudHNcQXVkaXRMb2dFbnRyeXNcQXVkaXRMb2dFbnRyeVJlZ2lzdGVyLnJhem9y
build_metadata.AdditionalFiles.CssScope =
[C:/Users/marce/GitHub/Moonlight-Panel/Moonlight/Moonlight/Shared/Components/Auth/Login.razor] [C:/Users/marce/GitHub/Moonlight-Panel/Moonlight/Moonlight/Shared/Components/Auth/Login.razor]
build_metadata.AdditionalFiles.TargetPath = U2hhcmVkXENvbXBvbmVudHNcQXV0aFxMb2dpbi5yYXpvcg== build_metadata.AdditionalFiles.TargetPath = U2hhcmVkXENvbXBvbmVudHNcQXV0aFxMb2dpbi5yYXpvcg==
build_metadata.AdditionalFiles.CssScope = build_metadata.AdditionalFiles.CssScope =
@@ -243,8 +255,8 @@ build_metadata.AdditionalFiles.CssScope =
build_metadata.AdditionalFiles.TargetPath = U2hhcmVkXFZpZXdzXEFkbWluXFN5c1xJbmRleC5yYXpvcg== build_metadata.AdditionalFiles.TargetPath = U2hhcmVkXFZpZXdzXEFkbWluXFN5c1xJbmRleC5yYXpvcg==
build_metadata.AdditionalFiles.CssScope = build_metadata.AdditionalFiles.CssScope =
[C:/Users/marce/GitHub/Moonlight-Panel/Moonlight/Moonlight/Shared/Views/Admin/Sys/Logging.razor] [C:/Users/marce/GitHub/Moonlight-Panel/Moonlight/Moonlight/Shared/Views/Admin/Sys/Logs.razor]
build_metadata.AdditionalFiles.TargetPath = U2hhcmVkXFZpZXdzXEFkbWluXFN5c1xMb2dnaW5nLnJhem9y build_metadata.AdditionalFiles.TargetPath = U2hhcmVkXFZpZXdzXEFkbWluXFN5c1xMb2dzLnJhem9y
build_metadata.AdditionalFiles.CssScope = build_metadata.AdditionalFiles.CssScope =
[C:/Users/marce/GitHub/Moonlight-Panel/Moonlight/Moonlight/Shared/Views/Domains.razor] [C:/Users/marce/GitHub/Moonlight-Panel/Moonlight/Moonlight/Shared/Views/Domains.razor]

View File

@@ -267,3 +267,10 @@ Server installation is currently running;Server installation is currently runnin
Selected;Selected Selected;Selected
Move deleted;Move deleted Move deleted;Move deleted
Delete selected;Delete selected Delete selected;Delete selected
Log level;Log level
Log message;Log message
Time;Time
Version;Version
You are running moonlight version;You are running moonlight version
Operating system;Operating system
Moonlight is running on;Moonlight is running on