diff --git a/Moonlight/App/Helpers/CacheLogger.cs b/Moonlight/App/Helpers/CacheLogger.cs new file mode 100644 index 00000000..b8feb5ad --- /dev/null +++ b/Moonlight/App/Helpers/CacheLogger.cs @@ -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 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; + } +} \ No newline at end of file diff --git a/Moonlight/App/Helpers/HostSystemHelper.cs b/Moonlight/App/Helpers/HostSystemHelper.cs new file mode 100644 index 00000000..344bed5a --- /dev/null +++ b/Moonlight/App/Helpers/HostSystemHelper.cs @@ -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"; + } + } +} \ No newline at end of file diff --git a/Moonlight/App/LogMigrator/LogMigrator.cs b/Moonlight/App/LogMigrator/LogMigrator.cs new file mode 100644 index 00000000..0df9501d --- /dev/null +++ b/Moonlight/App/LogMigrator/LogMigrator.cs @@ -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 state) + { + return null; + } + + public bool IsEnabled(LogLevel logLevel) + { + return true; + } + + public void Log(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func 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; + } + } +} \ No newline at end of file diff --git a/Moonlight/App/LogMigrator/LogMigratorLoggerFactoryExtension.cs b/Moonlight/App/LogMigrator/LogMigratorLoggerFactoryExtension.cs new file mode 100644 index 00000000..caa78e8a --- /dev/null +++ b/Moonlight/App/LogMigrator/LogMigratorLoggerFactoryExtension.cs @@ -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; + } +} \ No newline at end of file diff --git a/Moonlight/App/LogMigrator/LogMigratorProvider.cs b/Moonlight/App/LogMigrator/LogMigratorProvider.cs new file mode 100644 index 00000000..8b7ac313 --- /dev/null +++ b/Moonlight/App/LogMigrator/LogMigratorProvider.cs @@ -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 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; + } + } +} \ No newline at end of file diff --git a/Moonlight/App/Models/Misc/LogEntry.cs b/Moonlight/App/Models/Misc/LogEntry.cs new file mode 100644 index 00000000..09258f4a --- /dev/null +++ b/Moonlight/App/Models/Misc/LogEntry.cs @@ -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; +} \ No newline at end of file diff --git a/Moonlight/App/Services/LogService.cs b/Moonlight/App/Services/LogService.cs new file mode 100644 index 00000000..87a30a5f --- /dev/null +++ b/Moonlight/App/Services/LogService.cs @@ -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(); + } +} \ No newline at end of file diff --git a/Moonlight/Program.cs b/Moonlight/Program.cs index 6abba75c..4b2a5992 100644 --- a/Moonlight/Program.cs +++ b/Moonlight/Program.cs @@ -3,6 +3,7 @@ using CurrieTechnologies.Razor.SweetAlert2; using Logging.Net; using Moonlight.App.Database; using Moonlight.App.Helpers; +using Moonlight.App.LogMigrator; using Moonlight.App.Repositories; using Moonlight.App.Repositories.Domains; using Moonlight.App.Repositories.LogEntries; @@ -20,11 +21,20 @@ namespace Moonlight { 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) { + Logger.UsedLogger = new CacheLogger(); + Logger.Info($"Working dir: {Directory.GetCurrentDirectory()}"); var builder = WebApplication.CreateBuilder(args); + + // Switch to logging.net injection + builder.Logging.ClearProviders(); + builder.Logging.AddProvider(new LogMigratorProvider()); // Add services to the container. builder.Services.AddRazorPages(); @@ -85,6 +95,7 @@ namespace Moonlight builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); + builder.Services.AddScoped(); // Support builder.Services.AddSingleton(); @@ -98,6 +109,7 @@ namespace Moonlight builder.Services.AddSingleton(); builder.Services.AddScoped(); builder.Services.AddSingleton(); + builder.Services.AddSingleton(); // Third party services diff --git a/Moonlight/Shared/Components/Navigations/AdminSystemNavigation.razor b/Moonlight/Shared/Components/Navigations/AdminSystemNavigation.razor index 3719a5ea..0d0af9f0 100644 --- a/Moonlight/Shared/Components/Navigations/AdminSystemNavigation.razor +++ b/Moonlight/Shared/Components/Navigations/AdminSystemNavigation.razor @@ -10,7 +10,12 @@ + diff --git a/Moonlight/Shared/Views/Admin/Sys/AuditLog.razor b/Moonlight/Shared/Views/Admin/Sys/AuditLog.razor index 48a60ceb..bf6a4f28 100644 --- a/Moonlight/Shared/Views/Admin/Sys/AuditLog.razor +++ b/Moonlight/Shared/Views/Admin/Sys/AuditLog.razor @@ -12,7 +12,7 @@ @inject AuditLogEntryRepository AuditLogEntryRepository - +
diff --git a/Moonlight/Shared/Views/Admin/Sys/Index.razor b/Moonlight/Shared/Views/Admin/Sys/Index.razor index 8fbe9c92..fc10ea0e 100644 --- a/Moonlight/Shared/Views/Admin/Sys/Index.razor +++ b/Moonlight/Shared/Views/Admin/Sys/Index.razor @@ -1,9 +1,43 @@ @page "/admin/system" @using Moonlight.Shared.Components.Navigations +@using Moonlight.App.Helpers + +@inject HostSystemHelper HostSystemHelper - - - + + +
+
+
+
+ + Version + +
+
+ + You are running moonlight version + @(Program.AppVersion) + +
+
+
+
+
+
+ + Operating system + +
+
+ + Moonlight is running on + @(HostSystemHelper.GetOsName()) + +
+
+
+
\ No newline at end of file diff --git a/Moonlight/Shared/Views/Admin/Sys/Logs.razor b/Moonlight/Shared/Views/Admin/Sys/Logs.razor new file mode 100644 index 00000000..ad0ad4f0 --- /dev/null +++ b/Moonlight/Shared/Views/Admin/Sys/Logs.razor @@ -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 + + + + +
+
+ + + + + + +
+
+
+
+
+ +@code +{ + private LogEntry[] LogEntries; + + private Task Load(LazyLoader arg) + { + LogEntries = LogService.GetMessages(); + + return Task.CompletedTask; + } +} \ No newline at end of file diff --git a/Moonlight/obj/Debug/net6.0/Moonlight.GeneratedMSBuildEditorConfig.editorconfig b/Moonlight/obj/Debug/net6.0/Moonlight.GeneratedMSBuildEditorConfig.editorconfig index 136c3a08..f6afa011 100644 --- a/Moonlight/obj/Debug/net6.0/Moonlight.GeneratedMSBuildEditorConfig.editorconfig +++ b/Moonlight/obj/Debug/net6.0/Moonlight.GeneratedMSBuildEditorConfig.editorconfig @@ -31,10 +31,22 @@ build_metadata.AdditionalFiles.CssScope = build_metadata.AdditionalFiles.TargetPath = U2hhcmVkXENvbXBvbmVudHNcQWxlcnRzXFNldHVwQ29tcGxldGVkQWxlcnQucmF6b3I= 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] build_metadata.AdditionalFiles.TargetPath = U2hhcmVkXENvbXBvbmVudHNcQXVkaXRMb2dFbnRyeXNcQXVkaXRMb2dFbnRyeUxvZ2luLnJhem9y 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] build_metadata.AdditionalFiles.TargetPath = U2hhcmVkXENvbXBvbmVudHNcQXV0aFxMb2dpbi5yYXpvcg== build_metadata.AdditionalFiles.CssScope = @@ -243,8 +255,8 @@ build_metadata.AdditionalFiles.CssScope = build_metadata.AdditionalFiles.TargetPath = U2hhcmVkXFZpZXdzXEFkbWluXFN5c1xJbmRleC5yYXpvcg== build_metadata.AdditionalFiles.CssScope = -[C:/Users/marce/GitHub/Moonlight-Panel/Moonlight/Moonlight/Shared/Views/Admin/Sys/Logging.razor] -build_metadata.AdditionalFiles.TargetPath = U2hhcmVkXFZpZXdzXEFkbWluXFN5c1xMb2dnaW5nLnJhem9y +[C:/Users/marce/GitHub/Moonlight-Panel/Moonlight/Moonlight/Shared/Views/Admin/Sys/Logs.razor] +build_metadata.AdditionalFiles.TargetPath = U2hhcmVkXFZpZXdzXEFkbWluXFN5c1xMb2dzLnJhem9y build_metadata.AdditionalFiles.CssScope = [C:/Users/marce/GitHub/Moonlight-Panel/Moonlight/Moonlight/Shared/Views/Domains.razor] diff --git a/Moonlight/resources/lang/de_de.lang b/Moonlight/resources/lang/de_de.lang index 7bcedc68..afa1303a 100644 --- a/Moonlight/resources/lang/de_de.lang +++ b/Moonlight/resources/lang/de_de.lang @@ -267,3 +267,10 @@ Server installation is currently running;Server installation is currently runnin Selected;Selected Move deleted;Move deleted 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