Implement cuddle logger

This commit is contained in:
jvyden 2022-05-01 17:37:58 -04:00
parent 9c57d15671
commit 9fa4ffbc90
No known key found for this signature in database
GPG key ID: 18BCF2BE0262B278
41 changed files with 508 additions and 317 deletions

View file

@ -3,7 +3,6 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Threading.Tasks; using System.Threading.Tasks;
using Kettu;
using LBPUnion.ProjectLighthouse.Helpers; using LBPUnion.ProjectLighthouse.Helpers;
using LBPUnion.ProjectLighthouse.Logging; using LBPUnion.ProjectLighthouse.Logging;
using LBPUnion.ProjectLighthouse.Types; using LBPUnion.ProjectLighthouse.Types;
@ -46,14 +45,14 @@ public class LoginController : ControllerBase
if (npTicket == null) if (npTicket == null)
{ {
Logger.Log("npTicket was null, rejecting login", LoggerLevelLogin.Instance); Logger.LogWarn("npTicket was null, rejecting login", "Login");
return this.BadRequest(); return this.BadRequest();
} }
IPAddress? remoteIpAddress = this.HttpContext.Connection.RemoteIpAddress; IPAddress? remoteIpAddress = this.HttpContext.Connection.RemoteIpAddress;
if (remoteIpAddress == null) if (remoteIpAddress == null)
{ {
Logger.Log("unable to determine ip, rejecting login", LoggerLevelLogin.Instance); Logger.LogWarn("unable to determine ip, rejecting login", "Login");
return this.StatusCode(403, ""); // 403 probably isnt the best status code for this, but whatever return this.StatusCode(403, ""); // 403 probably isnt the best status code for this, but whatever
} }
@ -69,7 +68,7 @@ public class LoginController : ControllerBase
token = await this.database.AuthenticateUser(npTicket, ipAddress); token = await this.database.AuthenticateUser(npTicket, ipAddress);
if (token == null) if (token == null)
{ {
Logger.Log($"Unable to find/generate a token for username {npTicket.Username}", LoggerLevelLogin.Instance); Logger.LogWarn($"Unable to find/generate a token for username {npTicket.Username}", "Login");
return this.StatusCode(403, ""); // If not, then 403. return this.StatusCode(403, ""); // If not, then 403.
} }
} }
@ -78,7 +77,7 @@ public class LoginController : ControllerBase
if (user == null || user.Banned) if (user == null || user.Banned)
{ {
Logger.Log($"Unable to find user {npTicket.Username} from token", LoggerLevelLogin.Instance); Logger.LogError($"Unable to find user {npTicket.Username} from token", "Login");
return this.StatusCode(403, ""); return this.StatusCode(403, "");
} }
@ -95,7 +94,7 @@ public class LoginController : ControllerBase
DeniedAuthenticationHelper.AddAttempt(ipAddressAndName); DeniedAuthenticationHelper.AddAttempt(ipAddressAndName);
await this.database.SaveChangesAsync(); await this.database.SaveChangesAsync();
Logger.Log($"Too many recent denied logins from user {user.Username}, rejecting login", LoggerLevelLogin.Instance); Logger.LogWarn($"Too many recent denied logins from user {user.Username}, rejecting login", "Login");
return this.StatusCode(403, ""); return this.StatusCode(403, "");
} }
} }
@ -127,11 +126,11 @@ public class LoginController : ControllerBase
if (!token.Approved) if (!token.Approved)
{ {
Logger.Log($"Token unapproved for user {user.Username}, rejecting login", LoggerLevelLogin.Instance); Logger.LogWarn($"Token unapproved for user {user.Username}, rejecting login", "Login");
return this.StatusCode(403, ""); return this.StatusCode(403, "");
} }
Logger.Log($"Successfully logged in user {user.Username} as {token.GameVersion} client", LoggerLevelLogin.Instance); Logger.LogSuccess($"Successfully logged in user {user.Username} as {token.GameVersion} client", "Login");
// After this point we are now considering this session as logged in. // After this point we are now considering this session as logged in.
// We just logged in with the token. Mark it as used so someone else doesnt try to use it, // We just logged in with the token. Mark it as used so someone else doesnt try to use it,

View file

@ -5,7 +5,6 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Text.Json; using System.Text.Json;
using System.Threading.Tasks; using System.Threading.Tasks;
using Kettu;
using LBPUnion.ProjectLighthouse.Helpers; using LBPUnion.ProjectLighthouse.Helpers;
using LBPUnion.ProjectLighthouse.Helpers.Extensions; using LBPUnion.ProjectLighthouse.Helpers.Extensions;
using LBPUnion.ProjectLighthouse.Logging; using LBPUnion.ProjectLighthouse.Logging;
@ -48,7 +47,7 @@ public class MatchController : ControllerBase
if (bodyString.Length == 0 || bodyString[0] != '[') return this.BadRequest(); if (bodyString.Length == 0 || bodyString[0] != '[') return this.BadRequest();
Logger.Log("Received match data: " + bodyString, LoggerLevelMatch.Instance); Logger.LogInfo("Received match data: " + bodyString, "Match");
IMatchData? matchData; IMatchData? matchData;
try try
@ -57,20 +56,19 @@ public class MatchController : ControllerBase
} }
catch(Exception e) catch(Exception e)
{ {
Logger.Log("Exception while parsing matchData: ", LoggerLevelMatch.Instance); Logger.LogError("Exception while parsing matchData: ", "Match");
string[] lines = e.ToDetailedException().Split("\n"); Logger.LogError(e.ToDetailedException(), "Match");
foreach (string line in lines) Logger.Log(line, LoggerLevelMatch.Instance);
return this.BadRequest(); return this.BadRequest();
} }
if (matchData == null) if (matchData == null)
{ {
Logger.Log("Could not parse match data: matchData is null", LoggerLevelMatch.Instance); Logger.LogError($"Could not parse match data: {nameof(matchData)} is null", "Match");
return this.BadRequest(); return this.BadRequest();
} }
Logger.Log($"Parsed match from {user.Username} (type: {matchData.GetType()})", LoggerLevelMatch.Instance); Logger.LogError($"Parsed match from {user.Username} (type: {matchData.GetType()})", "Match");
#endregion #endregion

View file

@ -1,7 +1,6 @@
#nullable enable #nullable enable
using System.IO; using System.IO;
using System.Threading.Tasks; using System.Threading.Tasks;
using Kettu;
using LBPUnion.ProjectLighthouse.Helpers; using LBPUnion.ProjectLighthouse.Helpers;
using LBPUnion.ProjectLighthouse.Logging; using LBPUnion.ProjectLighthouse.Logging;
using LBPUnion.ProjectLighthouse.Types; using LBPUnion.ProjectLighthouse.Types;
@ -99,7 +98,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.";
string scannedText = CensorHelper.ScanMessage(response); string scannedText = CensorHelper.ScanMessage(response);
Logger.Log($"{user.Username}: {response} / {scannedText}", LoggerLevelFilter.Instance); Logger.LogInfo($"{user.Username}: {response} / {scannedText}", "Filter");
return this.Ok(scannedText); return this.Ok(scannedText);
} }

View file

@ -6,7 +6,6 @@ using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Xml.Serialization; using System.Xml.Serialization;
using Discord; using Discord;
using Kettu;
using LBPUnion.ProjectLighthouse.Helpers; using LBPUnion.ProjectLighthouse.Helpers;
using LBPUnion.ProjectLighthouse.Logging; using LBPUnion.ProjectLighthouse.Logging;
using LBPUnion.ProjectLighthouse.Serialization; using LBPUnion.ProjectLighthouse.Serialization;
@ -68,7 +67,7 @@ public class PhotosController : ControllerBase
if (subject.User == null) continue; if (subject.User == null) continue;
subject.UserId = subject.User.UserId; subject.UserId = subject.User.UserId;
Logger.Log($"Adding PhotoSubject (userid {subject.UserId}) to db", LoggerLevelPhotos.Instance); Logger.LogDebug($"Adding PhotoSubject (userid {subject.UserId}) to db", "Photos");
this.database.PhotoSubjects.Add(subject); this.database.PhotoSubjects.Add(subject);
} }
@ -88,7 +87,7 @@ public class PhotosController : ControllerBase
// photo.Slot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == photo.SlotId); // photo.Slot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == photo.SlotId);
Logger.Log($"Adding PhotoSubjectCollection ({photo.PhotoSubjectCollection}) to photo", LoggerLevelPhotos.Instance); Logger.LogDebug($"Adding PhotoSubjectCollection ({photo.PhotoSubjectCollection}) to photo", "Photos");
this.database.Photos.Add(photo); this.database.Photos.Add(photo);
@ -168,4 +167,4 @@ public class PhotosController : ControllerBase
await this.database.SaveChangesAsync(); await this.database.SaveChangesAsync();
return this.Ok(); return this.Ok();
} }
} }

View file

@ -3,7 +3,6 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Xml.Serialization; using System.Xml.Serialization;
using Kettu;
using LBPUnion.ProjectLighthouse.Helpers; using LBPUnion.ProjectLighthouse.Helpers;
using LBPUnion.ProjectLighthouse.Logging; using LBPUnion.ProjectLighthouse.Logging;
using LBPUnion.ProjectLighthouse.Serialization; using LBPUnion.ProjectLighthouse.Serialization;
@ -97,27 +96,23 @@ public class ResourcesController : ControllerBase
// lbp treats code 409 as success and as an indicator that the file is already present // lbp treats code 409 as success and as an indicator that the file is already present
if (FileHelper.ResourceExists(hash)) this.Conflict(); if (FileHelper.ResourceExists(hash)) this.Conflict();
Logger.Log($"Processing resource upload (hash: {hash})", LoggerLevelResources.Instance); Logger.LogInfo($"Processing resource upload (hash: {hash})", "Resources");
LbpFile file = new(await BinaryHelper.ReadFromPipeReader(this.Request.BodyReader)); LbpFile file = new(await BinaryHelper.ReadFromPipeReader(this.Request.BodyReader));
if (!FileHelper.IsFileSafe(file)) if (!FileHelper.IsFileSafe(file))
{ {
Logger.Log($"File is unsafe (hash: {hash}, type: {file.FileType})", LoggerLevelResources.Instance); Logger.LogWarn($"File is unsafe (hash: {hash}, type: {file.FileType})", "Resources");
return this.Conflict(); return this.Conflict();
} }
string calculatedHash = file.Hash; string calculatedHash = file.Hash;
if (calculatedHash != hash) if (calculatedHash != hash)
{ {
Logger.Log Logger.LogWarn($"File hash does not match the uploaded file! (hash: {hash}, calculatedHash: {calculatedHash}, type: {file.FileType})", "Resources");
(
$"File hash does not match the uploaded file! (hash: {hash}, calculatedHash: {calculatedHash}, type: {file.FileType})",
LoggerLevelResources.Instance
);
return this.Conflict(); return this.Conflict();
} }
Logger.Log($"File is OK! (hash: {hash}, type: {file.FileType})", LoggerLevelResources.Instance); Logger.LogSuccess($"File is OK! (hash: {hash}, type: {file.FileType})", "Resources");
await IOFile.WriteAllBytesAsync(path, file.Data); await IOFile.WriteAllBytesAsync(path, file.Data);
return this.Ok(); return this.Ok();
} }

View file

@ -2,7 +2,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Kettu;
using LBPUnion.ProjectLighthouse.Helpers; using LBPUnion.ProjectLighthouse.Helpers;
using LBPUnion.ProjectLighthouse.Logging; using LBPUnion.ProjectLighthouse.Logging;
using LBPUnion.ProjectLighthouse.Serialization; using LBPUnion.ProjectLighthouse.Serialization;
@ -85,7 +84,7 @@ public class CollectionController : ControllerBase
Category? category = CollectionHelper.Categories.FirstOrDefault(c => c.Endpoint == endpointName); Category? category = CollectionHelper.Categories.FirstOrDefault(c => c.Endpoint == endpointName);
if (category == null) return this.NotFound(); if (category == null) return this.NotFound();
Logger.Log("Found category " + category, LoggerLevelCategory.Instance); Logger.LogDebug("Found category " + category, "Category");
List<Slot> slots; List<Slot> slots;
int totalSlots; int totalSlots;

View file

@ -1,6 +1,5 @@
#nullable enable #nullable enable
using System.Threading.Tasks; using System.Threading.Tasks;
using Kettu;
using LBPUnion.ProjectLighthouse.Helpers; using LBPUnion.ProjectLighthouse.Helpers;
using LBPUnion.ProjectLighthouse.Logging; using LBPUnion.ProjectLighthouse.Logging;
using LBPUnion.ProjectLighthouse.Types; using LBPUnion.ProjectLighthouse.Types;
@ -45,14 +44,14 @@ public class SlotPageController : ControllerBase
if (msg == null) if (msg == null)
{ {
Logger.Log($"Refusing to post comment from {user.UserId} on user {id}, {nameof(msg)} is null", LoggerLevelComments.Instance); Logger.LogError($"Refusing to post comment from {user.UserId} on user {id}, {nameof(msg)} is null", "Comments");
return this.Redirect("~/slot/" + id); return this.Redirect("~/slot/" + id);
} }
msg = SanitizationHelper.SanitizeString(msg); msg = SanitizationHelper.SanitizeString(msg);
await this.database.PostComment(user, id, CommentType.Level, msg); await this.database.PostComment(user, id, CommentType.Level, msg);
Logger.Log($"Posted comment from {user.UserId}: \"{msg}\" on user {id}", LoggerLevelComments.Instance); Logger.LogSuccess($"Posted comment from {user.UserId}: \"{msg}\" on user {id}", "Comments");
return this.Redirect("~/slot/" + id); return this.Redirect("~/slot/" + id);
} }

View file

@ -1,9 +1,8 @@
#nullable enable #nullable enable
using System.Threading.Tasks; using System.Threading.Tasks;
using Kettu; using LBPUnion.ProjectLighthouse.Helpers;
using LBPUnion.ProjectLighthouse.Logging; using LBPUnion.ProjectLighthouse.Logging;
using LBPUnion.ProjectLighthouse.Types; using LBPUnion.ProjectLighthouse.Types;
using LBPUnion.ProjectLighthouse.Helpers;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
@ -39,14 +38,14 @@ public class UserPageController : ControllerBase
if (msg == null) if (msg == null)
{ {
Logger.Log($"Refusing to post comment from {user.UserId} on user {id}, {nameof(msg)} is null", LoggerLevelComments.Instance); Logger.LogError($"Refusing to post comment from {user.UserId} on user {id}, {nameof(msg)} is null", "Comments");
return this.Redirect("~/user/" + id); return this.Redirect("~/user/" + id);
} }
msg = SanitizationHelper.SanitizeString(msg); msg = SanitizationHelper.SanitizeString(msg);
await this.database.PostComment(user, id, CommentType.Profile, msg); await this.database.PostComment(user, id, CommentType.Profile, msg);
Logger.Log($"Posted comment from {user.UserId}: \"{msg}\" on user {id}", LoggerLevelComments.Instance); Logger.LogSuccess($"Posted comment from {user.UserId}: \"{msg}\" on user {id}", "Comments");
return this.Redirect("~/user/" + id); return this.Redirect("~/user/" + id);
} }

View file

@ -0,0 +1,22 @@
using LBPUnion.ProjectLighthouse.Logging;
using AspLogLevel = Microsoft.Extensions.Logging.LogLevel;
namespace LBPUnion.ProjectLighthouse.Helpers.Extensions;
public static class AspLogLevelExtensions
{
public static LogLevel ToLighthouseLevel(this AspLogLevel level)
{
return level switch
{
AspLogLevel.Trace => LogLevel.Debug,
AspLogLevel.Debug => LogLevel.Debug,
AspLogLevel.Information => LogLevel.Info,
AspLogLevel.Warning => LogLevel.Warning,
AspLogLevel.Error => LogLevel.Error,
AspLogLevel.Critical => LogLevel.Error,
AspLogLevel.None => LogLevel.Info,
_ => LogLevel.Info,
};
}
}

View file

@ -0,0 +1,20 @@
using System;
namespace LBPUnion.ProjectLighthouse.Helpers.Extensions;
internal static class ConsoleColorExtensions
{
internal static ConsoleColor ToDark(this ConsoleColor color)
=> color switch
{
ConsoleColor.Blue => ConsoleColor.DarkBlue,
ConsoleColor.Cyan => ConsoleColor.DarkCyan,
ConsoleColor.Green => ConsoleColor.DarkGreen,
ConsoleColor.Gray => ConsoleColor.DarkGray,
ConsoleColor.Magenta => ConsoleColor.DarkMagenta,
ConsoleColor.Red => ConsoleColor.DarkRed,
ConsoleColor.White => ConsoleColor.Gray,
ConsoleColor.Yellow => ConsoleColor.DarkYellow,
_ => color,
};
}

View file

@ -0,0 +1,18 @@
using System;
using LBPUnion.ProjectLighthouse.Logging;
namespace LBPUnion.ProjectLighthouse.Helpers.Extensions;
public static class LogLevelExtensions
{
public static ConsoleColor ToColor(this LogLevel level)
=> level switch
{
LogLevel.Debug => ConsoleColor.Magenta,
LogLevel.Error => ConsoleColor.Red,
LogLevel.Warning => ConsoleColor.Yellow,
LogLevel.Info => ConsoleColor.White,
LogLevel.Success => ConsoleColor.Green,
_ => ConsoleColor.White,
};
}

View file

@ -6,7 +6,6 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Kettu;
using LBPUnion.ProjectLighthouse.Logging; using LBPUnion.ProjectLighthouse.Logging;
using LBPUnion.ProjectLighthouse.Types.Files; using LBPUnion.ProjectLighthouse.Types.Files;
using LBPUnion.ProjectLighthouse.Types.Settings; using LBPUnion.ProjectLighthouse.Types.Settings;
@ -115,8 +114,7 @@ public static class FileHelper
EnsureDirectoryCreated(Path.Combine(Environment.CurrentDirectory, "png")); EnsureDirectoryCreated(Path.Combine(Environment.CurrentDirectory, "png"));
if (Directory.Exists("r")) if (Directory.Exists("r"))
{ {
Logger.Log Logger.LogInfo("Converting all textures to PNG. This may take a while if this is the first time running this operation...", "Startup");
("Converting all textures to PNG. This may take a while if this is the first time running this operation...", LoggerLevelStartup.Instance);
ConcurrentQueue<string> fileQueue = new(); ConcurrentQueue<string> fileQueue = new();

View file

@ -5,7 +5,7 @@ using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using InfluxDB.Client; using InfluxDB.Client;
using InfluxDB.Client.Writes; using InfluxDB.Client.Writes;
using Kettu; using LBPUnion.ProjectLighthouse.Helpers.Extensions;
using LBPUnion.ProjectLighthouse.Logging; using LBPUnion.ProjectLighthouse.Logging;
using LBPUnion.ProjectLighthouse.Types; using LBPUnion.ProjectLighthouse.Types;
using LBPUnion.ProjectLighthouse.Types.Settings; using LBPUnion.ProjectLighthouse.Types.Settings;
@ -49,9 +49,8 @@ public static class InfluxHelper
} }
catch(Exception e) catch(Exception e)
{ {
Logger.Log("Exception while logging: ", LoggerLevelInflux.Instance); Logger.LogError("Exception while logging: ", "InfluxDB");
Logger.LogError(e.ToDetailedException(), "InfluxDB");
foreach (string line in e.ToString().Split("\n")) Logger.Log(line, LoggerLevelInflux.Instance);
} }
} }
@ -59,7 +58,7 @@ public static class InfluxHelper
public static async Task StartLogging() public static async Task StartLogging()
{ {
await Client.ReadyAsync(); await Client.ReadyAsync();
Logger.Log("InfluxDB is now ready.", LoggerLevelInflux.Instance); Logger.LogSuccess("InfluxDB is now ready.", "InfluxDB");
Thread t = new Thread t = new
( (
delegate() delegate()
@ -72,9 +71,8 @@ public static class InfluxHelper
} }
catch(Exception e) catch(Exception e)
{ {
Logger.Log("Exception while running log thread: ", LoggerLevelInflux.Instance); Logger.LogError("Exception while running log thread: ", "InfluxDB");
Logger.LogError(e.ToDetailedException(), "InfluxDB");
foreach (string line in e.ToString().Split("\n")) Logger.Log(line, LoggerLevelInflux.Instance);
} }
Thread.Sleep(60000); Thread.Sleep(60000);

View file

@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Kettu;
using LBPUnion.ProjectLighthouse.Logging; using LBPUnion.ProjectLighthouse.Logging;
using LBPUnion.ProjectLighthouse.Types; using LBPUnion.ProjectLighthouse.Types;
using LBPUnion.ProjectLighthouse.Types.Levels; using LBPUnion.ProjectLighthouse.Types.Levels;
@ -46,7 +45,7 @@ public class RoomHelper
{ {
if (roomVersion == GameVersion.LittleBigPlanet1 || roomVersion == GameVersion.LittleBigPlanetPSP) if (roomVersion == GameVersion.LittleBigPlanet1 || roomVersion == GameVersion.LittleBigPlanetPSP)
{ {
Logger.Log($"Returning null for FindBestRoom, game ({roomVersion}) does not support dive in (should never happen?)", LoggerLevelMatch.Instance); Logger.LogError($"Returning null for FindBestRoom, game ({roomVersion}) does not support dive in (should never happen?)", "Match");
return null; return null;
} }
@ -140,7 +139,7 @@ public class RoomHelper
}, },
}; };
Logger.Log($"Found a room (id: {room.RoomId}) for user {user?.Username ?? "null"} (id: {user?.UserId ?? -1})", LoggerLevelMatch.Instance); Logger.LogSuccess($"Found a room (id: {room.RoomId}) for user {user?.Username ?? "null"} (id: {user?.UserId ?? -1})", "Match");
return response; return response;
} }
@ -173,7 +172,7 @@ public class RoomHelper
CleanupRooms(room.Host, room); CleanupRooms(room.Host, room);
lock(Rooms) Rooms.Add(room); lock(Rooms) Rooms.Add(room);
Logger.Log($"Created room (id: {room.RoomId}) for host {room.Host.Username} (id: {room.Host.UserId})", LoggerLevelMatch.Instance); Logger.LogInfo($"Created room (id: {room.RoomId}) for host {room.Host.Username} (id: {room.Host.UserId})", "Match");
return room; return room;
} }
@ -238,7 +237,7 @@ public class RoomHelper
if (roomCountBeforeCleanup != roomCountAfterCleanup) if (roomCountBeforeCleanup != roomCountAfterCleanup)
{ {
Logger.Log($"Cleaned up {roomCountBeforeCleanup - roomCountAfterCleanup} rooms.", LoggerLevelMatch.Instance); Logger.LogDebug($"Cleaned up {roomCountBeforeCleanup - roomCountAfterCleanup} rooms.", "Match");
} }
} }
} }

View file

@ -5,6 +5,14 @@ using Swashbuckle.AspNetCore.SwaggerGen;
namespace LBPUnion.ProjectLighthouse.Helpers; namespace LBPUnion.ProjectLighthouse.Helpers;
/// <summary>
/// <para>
/// A filter for the swagger documentation endpoint.
/// </para>
/// <para>
/// Makes sure that only endpoints under <c>/api/v1</c> show up.
/// </para>
/// </summary>
public class SwaggerFilter : IDocumentFilter public class SwaggerFilter : IDocumentFilter
{ {
public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context) public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)

View file

@ -1,5 +1,4 @@
using System.Linq; using System.Linq;
using Kettu;
using LBPUnion.ProjectLighthouse.Logging; using LBPUnion.ProjectLighthouse.Logging;
using LBPUnion.ProjectLighthouse.Types.Settings; using LBPUnion.ProjectLighthouse.Types.Settings;
@ -30,11 +29,11 @@ public static class VersionHelper
} }
catch catch
{ {
Logger.Log Logger.LogError
( (
"Project Lighthouse was built incorrectly. Please make sure git is available when building. " + "Project Lighthouse was built incorrectly. Please make sure git is available when building. " +
"Because of this, you will not be notified of updates.", "Because of this, you will not be notified of updates.",
LoggerLevelStartup.Instance "Startup"
); );
CommitHash = "invalid"; CommitHash = "invalid";
Branch = "invalid"; Branch = "invalid";
@ -43,11 +42,11 @@ public static class VersionHelper
if (IsDirty) if (IsDirty)
{ {
Logger.Log Logger.LogWarn
( (
"This is a modified version of Project Lighthouse. " + "This is a modified version of Project Lighthouse. " +
"Please make sure you are properly disclosing the source code to any users who may be using this instance.", "Please make sure you are properly disclosing the source code to any users who may be using this instance.",
LoggerLevelStartup.Instance "Startup"
); );
CanCheckForUpdates = false; CanCheckForUpdates = false;
} }
@ -67,6 +66,6 @@ public static class VersionHelper
#elif RELEASE #elif RELEASE
"Release"; "Release";
#else #else
"Unknown"; "Unknown";
#endif #endif
} }

View file

@ -1,23 +0,0 @@
using System;
using Kettu;
using LBPUnion.ProjectLighthouse.Helpers.Extensions;
using Microsoft.Extensions.Logging;
namespace LBPUnion.ProjectLighthouse.Logging;
public class AspNetToKettuLogger : ILogger
{
public IDisposable BeginScope<TState>(TState state) => NullScope.Instance;
public bool IsEnabled(LogLevel logLevel) => true;
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
LoggerLevel loggerLevel = new LoggerLevelAspNet(logLevel);
Logger.Log(state.ToString(), loggerLevel);
if (exception == null) return;
string[] lines = exception.ToDetailedException().Replace("\r", "").Split("\n");
foreach (string line in lines) Logger.Log(line, loggerLevel);
}
}

View file

@ -1,15 +0,0 @@
using System;
using Microsoft.Extensions.Logging;
namespace LBPUnion.ProjectLighthouse.Logging;
[ProviderAlias("Kettu")]
public class AspNetToKettuLoggerProvider : ILoggerProvider, IDisposable
{
public void Dispose()
{
GC.SuppressFinalize(this);
}
public ILogger CreateLogger(string categoryName) => new AspNetToKettuLogger();
}

View file

@ -1,31 +0,0 @@
using System;
using System.IO;
using Kettu;
using LBPUnion.ProjectLighthouse.Helpers;
using LBPUnion.ProjectLighthouse.Helpers.Extensions;
namespace LBPUnion.ProjectLighthouse.Logging;
public class LighthouseFileLogger : LoggerBase
{
private static readonly string logsDirectory = Path.Combine(Environment.CurrentDirectory, "logs");
public override bool AllowMultiple => false;
public override void Send(LoggerLine line)
{
FileHelper.EnsureDirectoryCreated(logsDirectory);
string channel = string.IsNullOrEmpty(line.LoggerLevel.Channel) ? "" : $"[{line.LoggerLevel.Channel}] ";
string contentFile = $"{channel}{line.LineData}\n";
string contentAll = $"[{$"{line.LoggerLevel.Name} {channel}".TrimEnd()}] {line.LineData}\n";
try
{
File.AppendAllText(Path.Combine(logsDirectory, line.LoggerLevel.Name.ToFileName() + ".log"), contentFile);
File.AppendAllText(Path.Combine(logsDirectory, "all.log"), contentAll);
}
catch(IOException) {} // windows, ya goofed
}
}

View file

@ -0,0 +1,10 @@
namespace LBPUnion.ProjectLighthouse.Logging;
public enum LogLevel
{
Success = 0,
Info = 1,
Warning = 2,
Error = 3,
Debug = 4,
}

View file

@ -0,0 +1,9 @@
namespace LBPUnion.ProjectLighthouse.Logging;
public struct LogLine
{
public LogTrace Trace;
public LogLevel Level;
public string Area;
public string Message;
}

View file

@ -0,0 +1,7 @@
namespace LBPUnion.ProjectLighthouse.Logging;
public struct LogTrace
{
public string Name;
public short Line;
}

View file

@ -0,0 +1,174 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace LBPUnion.ProjectLighthouse.Logging;
// TODO: make into singleton, but with ability to also have instances
// Logger.LogSuccess() should still work and all, but ideally i'm also able to have another instance and do:
// Logger logger = new();
// logger.LogSuccess();
// I should also be able to access the log queue.
// This functionality is going to be used in the admin panel to get the output of commands.
public static class Logger
{
#region Internals
/// <summary>
/// A list of custom loggers to use.
/// </summary>
private static readonly List<ILogger> loggers = new();
public static void AddLogger(ILogger logger)
{
loggers.Add(logger);
LogSuccess("Initialized " + logger.GetType().Name, "Logger");
}
private static LogTrace getTrace()
{
const int depth = 6;
const int skipDepth = depth - 2;
// Get the stacktrace for logging...
string trace = Environment.StackTrace.Split('\n', depth, StringSplitOptions.RemoveEmptyEntries).Skip(skipDepth).First();
trace = trace.TrimEnd('\r');
trace = trace.Substring(trace.LastIndexOf(Path.DirectorySeparatorChar) + 1);
trace = trace.Replace(".cs:line ", ":");
string[] traceSplit = trace.Split(':'); // Split for formatting!
short lineNumber;
try
{
lineNumber = short.Parse(traceSplit[1]);
}
catch
{
lineNumber = -1;
}
return new LogTrace
{
Name = traceSplit[0],
Line = lineNumber,
};
}
#endregion
#region Queue
/// <summary>
/// <para>A queue for the logger.</para>
/// <para>
/// We use a queue because if two threads try to log something at the time they'll mess each other's printing up.
/// </para>
/// </summary>
private static readonly ConcurrentQueue<LogLine> logQueue = new();
/// <summary>
/// Adds a <see cref="LogLine"/> to the queue. Only used internally.
/// </summary>
/// <param name="logLine">The logLine to send to the queue.</param>
private static void queueLog(LogLine logLine)
{
logQueue.Enqueue(logLine);
}
[SuppressMessage("ReSharper", "FunctionNeverReturns")]
static Logger() // Start queue thread on first Logger access
{
Task.Factory.StartNew
(
() =>
{
while (true)
{
bool logged = queueLoop();
Thread.Sleep(logged ? 10 : 100);
// We wait 100ms if we dont log since it's less likely that the program logged again.
// If we did log, wait 10ms before looping again.
// This is all so we use as little CPU as possible. This is an endless while loop, after all.
}
}
);
}
/// <summary>
/// A function used by the queue thread
/// </summary>
/// <returns></returns>
private static bool queueLoop()
{
bool logged = false;
if (logQueue.TryDequeue(out LogLine line))
{
logged = true;
foreach (ILogger logger in loggers)
{
logger.Log(line);
}
}
return logged;
}
#endregion
#region Logging functions
public static void LogDebug(string text, string area = "")
{
#if DEBUG
Log(text, area, LogLevel.Debug);
#endif
}
public static void LogSuccess(string text, string area = "")
{
Log(text, area, LogLevel.Success);
}
public static void LogInfo(string text, string area = "")
{
Log(text, area, LogLevel.Info);
}
public static void LogWarn(string text, string area = "")
{
Log(text, area, LogLevel.Warning);
}
public static void LogError(string text, string area = "")
{
Log(text, area, LogLevel.Error);
}
public static void Log(string text, string area, LogLevel level)
{
queueLog
(
new LogLine
{
Level = level,
Message = text,
Area = area,
Trace = getTrace(),
}
);
}
#endregion
}

View file

@ -0,0 +1,6 @@
namespace LBPUnion.ProjectLighthouse.Logging;
public interface ILogger
{
public void Log(LogLine line);
}

View file

@ -1,86 +0,0 @@
using Kettu;
using Microsoft.Extensions.Logging;
namespace LBPUnion.ProjectLighthouse.Logging;
public class LoggerLevelStartup : LoggerLevel
{
public static readonly LoggerLevelStartup Instance = new();
public override string Name => "Startup";
}
public class LoggerLevelDatabase : LoggerLevel
{
public static readonly LoggerLevelDatabase Instance = new();
public override string Name => "Database";
}
public class LoggerLevelHttp : LoggerLevel
{
public static readonly LoggerLevelHttp Instance = new();
public override string Name => "HTTP";
}
public class LoggerLevelFilter : LoggerLevel
{
public static readonly LoggerLevelFilter Instance = new();
public override string Name => "Filter";
}
public class LoggerLevelLogin : LoggerLevel
{
public static readonly LoggerLevelLogin Instance = new();
public override string Name => "Login";
}
public class LoggerLevelResources : LoggerLevel
{
public static readonly LoggerLevelResources Instance = new();
public override string Name => "Resources";
}
public class LoggerLevelMatch : LoggerLevel
{
public static readonly LoggerLevelMatch Instance = new();
public override string Name => "Match";
}
public class LoggerLevelPhotos : LoggerLevel
{
public static readonly LoggerLevelPhotos Instance = new();
public override string Name => "Photos";
}
public class LoggerLevelConfig : LoggerLevel
{
public static readonly LoggerLevelConfig Instance = new();
public override string Name => "Config";
}
public class LoggerLevelInflux : LoggerLevel
{
public static readonly LoggerLevelInflux Instance = new();
public override string Name => "Influx";
}
public class LoggerLevelComments : LoggerLevel
{
public static readonly LoggerLevelComments Instance = new();
public override string Name => "Comments";
}
public class LoggerLevelAspNet : LoggerLevel
{
public LoggerLevelAspNet(LogLevel level)
{
this.Channel = level.ToString();
}
public override string Name => "AspNet";
}
public class LoggerLevelCategory : LoggerLevel
{
public static readonly LoggerLevelCategory Instance = new();
public override string Name => "Category";
}

View file

@ -0,0 +1,30 @@
using System;
using LBPUnion.ProjectLighthouse.Helpers.Extensions;
using Microsoft.Extensions.Logging;
using AspLogLevel = Microsoft.Extensions.Logging.LogLevel;
namespace LBPUnion.ProjectLighthouse.Logging.Loggers.AspNet;
public class AspNetToLighthouseLogger : Microsoft.Extensions.Logging.ILogger
{
public IDisposable BeginScope<TState>(TState state) => NullScope.Instance;
public bool IsEnabled(AspLogLevel logLevel) => true;
public string Category { get; init; }
public AspNetToLighthouseLogger(string category)
{
this.Category = category;
}
public void Log<TState>(AspLogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
LogLevel level = logLevel.ToLighthouseLevel();
Logger.Log(state.ToString(), this.Category, level);
if (exception == null) return;
Logger.Log(exception.ToDetailedException(), this.Category, level);
}
}

View file

@ -0,0 +1,16 @@
using System;
using Microsoft.Extensions.Logging;
using IAspLogger = Microsoft.Extensions.Logging.ILogger;
namespace LBPUnion.ProjectLighthouse.Logging.Loggers.AspNet;
[ProviderAlias("Kettu")]
public class AspNetToLighthouseLoggerProvider : ILoggerProvider, IDisposable
{
public void Dispose()
{
GC.SuppressFinalize(this);
}
public IAspLogger CreateLogger(string category) => new AspNetToLighthouseLogger(category);
}

View file

@ -0,0 +1,44 @@
using System;
using LBPUnion.ProjectLighthouse.Helpers.Extensions;
namespace LBPUnion.ProjectLighthouse.Logging.Loggers;
public class ConsoleLogger : ILogger
{
public void Log(LogLine logLine)
{
ConsoleColor oldBackgroundColor = Console.BackgroundColor;
ConsoleColor oldForegroundColor = Console.ForegroundColor;
foreach (string line in logLine.Message.Split('\n'))
{
// The following is scuffed. Beware~
// Write the level! [Success]
Console.BackgroundColor = logLine.Level.ToColor().ToDark();
Console.ForegroundColor = ConsoleColor.White;
Console.Write('[');
Console.ForegroundColor = logLine.Level.ToColor();
Console.Write(logLine.Level);
Console.ForegroundColor = ConsoleColor.White;
Console.Write(']');
Console.ForegroundColor = oldForegroundColor;
Console.BackgroundColor = oldBackgroundColor;
Console.Write(' ');
Console.ForegroundColor = ConsoleColor.White;
Console.Write('<');
Console.ForegroundColor = logLine.Level.ToColor();
Console.Write(logLine.Trace.Name);
Console.ForegroundColor = ConsoleColor.White;
Console.Write(':');
Console.ForegroundColor = logLine.Level.ToColor();
Console.Write(logLine.Trace.Line);
Console.ForegroundColor = ConsoleColor.White;
Console.Write("> ");
Console.ForegroundColor = oldForegroundColor;
Console.WriteLine(line);
}
}
}

View file

@ -1,21 +1,18 @@
using InfluxDB.Client; using InfluxDB.Client;
using InfluxDB.Client.Writes; using InfluxDB.Client.Writes;
using Kettu;
using LBPUnion.ProjectLighthouse.Helpers; using LBPUnion.ProjectLighthouse.Helpers;
using LBPUnion.ProjectLighthouse.Types.Settings; using LBPUnion.ProjectLighthouse.Types.Settings;
namespace LBPUnion.ProjectLighthouse.Logging; namespace LBPUnion.ProjectLighthouse.Logging.Loggers;
public class InfluxLogger : LoggerBase public class InfluxLogger : ILogger
{ {
public override bool AllowMultiple => false; public void Log(LogLine line)
public override void Send(LoggerLine line)
{ {
string channel = string.IsNullOrEmpty(line.LoggerLevel.Channel) ? "" : $"[{line.LoggerLevel.Channel}] "; string channel = string.IsNullOrEmpty(line.Area) ? "" : $"[{line.Area}] ";
string level = $"{$"{line.LoggerLevel.Name} {channel}".TrimEnd()}"; string level = $"{$"{channel} {line}".TrimEnd()}";
string content = line.LineData; string content = line.Message;
using WriteApi writeApi = InfluxHelper.Client.GetWriteApi(); using WriteApi writeApi = InfluxHelper.Client.GetWriteApi();

View file

@ -0,0 +1,28 @@
using System;
using System.IO;
using LBPUnion.ProjectLighthouse.Helpers;
namespace LBPUnion.ProjectLighthouse.Logging.Loggers;
public class LighthouseFileLogger : ILogger
{
private static readonly string logsDirectory = Path.Combine(Environment.CurrentDirectory, "logs");
public void Log(LogLine line)
{
FileHelper.EnsureDirectoryCreated(logsDirectory);
string channel = string.IsNullOrEmpty(line.Area) ? "" : $"[{line.Area}] ";
string contentFile = $"{channel}{line.Message}\n";
string contentAll = $"[{$"{line.Level} {channel}".TrimEnd()}] {line.Message}\n";
try
{
File.AppendAllText(Path.Combine(logsDirectory, line.Level + ".log"), contentFile);
File.AppendAllText(Path.Combine(logsDirectory, "all.log"), contentAll);
}
catch(IOException) {} // windows, ya goofed
}
}

View file

@ -1,7 +1,6 @@
#nullable enable #nullable enable
using System.Threading.Tasks; using System.Threading.Tasks;
using JetBrains.Annotations; using JetBrains.Annotations;
using Kettu;
using LBPUnion.ProjectLighthouse.Helpers; using LBPUnion.ProjectLighthouse.Helpers;
using LBPUnion.ProjectLighthouse.Logging; using LBPUnion.ProjectLighthouse.Logging;
using LBPUnion.ProjectLighthouse.Types; using LBPUnion.ProjectLighthouse.Types;
@ -25,17 +24,17 @@ public class CreateUserCommand : ICommand
if (user == null) if (user == null)
{ {
user = await this._database.CreateUser(onlineId, CryptoHelper.BCryptHash(password)); user = await this._database.CreateUser(onlineId, CryptoHelper.BCryptHash(password));
Logger.Log($"Created user {user.UserId} with online ID (username) {user.Username} and the specified password.", LoggerLevelLogin.Instance); Logger.LogSuccess($"Created user {user.UserId} with online ID (username) {user.Username} and the specified password.", "Login");
user.PasswordResetRequired = true; user.PasswordResetRequired = true;
Logger.Log("This user will need to reset their password when they log in.", LoggerLevelLogin.Instance); Logger.LogInfo("This user will need to reset their password when they log in.", "Login");
await this._database.SaveChangesAsync(); await this._database.SaveChangesAsync();
Logger.Log("Database changes saved.", LoggerLevelDatabase.Instance); Logger.LogInfo("Database changes saved.", "Database");
} }
else else
{ {
Logger.Log("A user with this username already exists.", LoggerLevelLogin.Instance); Logger.LogError("A user with this username already exists.", "Login");
} }
} }

View file

@ -2,7 +2,6 @@
using System; using System;
using System.Threading.Tasks; using System.Threading.Tasks;
using JetBrains.Annotations; using JetBrains.Annotations;
using Kettu;
using LBPUnion.ProjectLighthouse.Helpers; using LBPUnion.ProjectLighthouse.Helpers;
using LBPUnion.ProjectLighthouse.Helpers.Extensions; using LBPUnion.ProjectLighthouse.Helpers.Extensions;
using LBPUnion.ProjectLighthouse.Logging; using LBPUnion.ProjectLighthouse.Logging;
@ -47,28 +46,28 @@ public class LoginForm : BaseLayout
User? user = await this.Database.Users.FirstOrDefaultAsync(u => u.Username == username); User? user = await this.Database.Users.FirstOrDefaultAsync(u => u.Username == username);
if (user == null) if (user == null)
{ {
Logger.Log($"User {username} failed to login on web due to invalid username", LoggerLevelLogin.Instance); Logger.LogWarn($"User {username} failed to login on web due to invalid username", "Login");
this.Error = "The username or password you entered is invalid."; this.Error = "The username or password you entered is invalid.";
return this.Page(); return this.Page();
} }
if (!BCrypt.Net.BCrypt.Verify(password, user.Password)) if (!BCrypt.Net.BCrypt.Verify(password, user.Password))
{ {
Logger.Log($"User {user.Username} (id: {user.UserId}) failed to login on web due to invalid password", LoggerLevelLogin.Instance); Logger.LogWarn($"User {user.Username} (id: {user.UserId}) failed to login on web due to invalid password", "Login");
this.Error = "The username or password you entered is invalid."; this.Error = "The username or password you entered is invalid.";
return this.Page(); return this.Page();
} }
if (user.Banned) if (user.Banned)
{ {
Logger.Log($"User {user.Username} (id: {user.UserId}) failed to login on web due to being banned", LoggerLevelLogin.Instance); Logger.LogWarn($"User {user.Username} (id: {user.UserId}) failed to login on web due to being banned", "Login");
this.Error = "You have been banned. Please contact an administrator for more information.\nReason: " + user.BannedReason; this.Error = "You have been banned. Please contact an administrator for more information.\nReason: " + user.BannedReason;
return this.Page(); return this.Page();
} }
if (user.EmailAddress == null && ServerSettings.Instance.SMTPEnabled) if (user.EmailAddress == null && ServerSettings.Instance.SMTPEnabled)
{ {
Logger.Log($"User {user.Username} (id: {user.UserId}) failed to login; email not set", LoggerLevelLogin.Instance); Logger.LogWarn($"User {user.Username} (id: {user.UserId}) failed to login; email not set", "Login");
EmailSetToken emailSetToken = new() EmailSetToken emailSetToken = new()
{ {
@ -102,7 +101,7 @@ public class LoginForm : BaseLayout
} }
); );
Logger.Log($"User {user.Username} (id: {user.UserId}) successfully logged in on web", LoggerLevelLogin.Instance); Logger.LogSuccess($"User {user.Username} (id: {user.UserId}) successfully logged in on web", "Login");
if (user.PasswordResetRequired) return this.Redirect("~/passwordResetRequired"); if (user.PasswordResetRequired) return this.Redirect("~/passwordResetRequired");
if (ServerSettings.Instance.SMTPEnabled && !user.EmailAddressVerified) return this.Redirect("~/login/sendVerificationEmail"); if (ServerSettings.Instance.SMTPEnabled && !user.EmailAddressVerified) return this.Redirect("~/login/sendVerificationEmail");

View file

@ -1,7 +1,6 @@
#nullable enable #nullable enable
using System; using System;
using System.Threading.Tasks; using System.Threading.Tasks;
using Kettu;
using LBPUnion.ProjectLighthouse.Helpers; using LBPUnion.ProjectLighthouse.Helpers;
using LBPUnion.ProjectLighthouse.Logging; using LBPUnion.ProjectLighthouse.Logging;
using LBPUnion.ProjectLighthouse.Pages.Layouts; using LBPUnion.ProjectLighthouse.Pages.Layouts;
@ -72,7 +71,7 @@ public class SetEmailForm : BaseLayout
} }
); );
Logger.Log($"User {user.Username} (id: {user.UserId}) successfully logged in on web after setting an email address", LoggerLevelLogin.Instance); Logger.LogSuccess($"User {user.Username} (id: {user.UserId}) successfully logged in on web after setting an email address", "Login");
this.Database.WebTokens.Add(webToken); this.Database.WebTokens.Add(webToken);
await this.Database.SaveChangesAsync(); await this.Database.SaveChangesAsync();

View file

@ -1,9 +1,10 @@
#nullable enable #nullable enable
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using Kettu;
using LBPUnion.ProjectLighthouse.Helpers; using LBPUnion.ProjectLighthouse.Helpers;
using LBPUnion.ProjectLighthouse.Logging; using LBPUnion.ProjectLighthouse.Logging;
using LBPUnion.ProjectLighthouse.Logging.Loggers;
using LBPUnion.ProjectLighthouse.Logging.Loggers.AspNet;
using LBPUnion.ProjectLighthouse.Types.Settings; using LBPUnion.ProjectLighthouse.Types.Settings;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
@ -23,46 +24,47 @@ public static class Program
stopwatch.Start(); stopwatch.Start();
// Setup logging // Setup logging
Logger.StartLogging();
Logger.UpdateRate /= 2;
LoggerLine.LogFormat = "[{0}] {1}";
Logger.AddLogger(new ConsoleLogger()); Logger.AddLogger(new ConsoleLogger());
Logger.AddLogger(new LighthouseFileLogger()); Logger.AddLogger(new LighthouseFileLogger());
Logger.Log("Welcome to Project Lighthouse!", LoggerLevelStartup.Instance); Logger.LogInfo("Welcome to Project Lighthouse!", "Startup");
Logger.Log($"You are running version {VersionHelper.FullVersion}", LoggerLevelStartup.Instance); Logger.LogInfo($"You are running version {VersionHelper.FullVersion}", "Startup");
// Referencing ServerSettings.Instance here loads the config, see ServerSettings.cs for more information // Referencing ServerSettings.Instance here loads the config, see ServerSettings.cs for more information
Logger.Log("Loaded config file version " + ServerSettings.Instance.ConfigVersion, LoggerLevelStartup.Instance); Logger.LogSuccess("Loaded config file version " + ServerSettings.Instance.ConfigVersion, "Startup");
Logger.Log("Determining if the database is available...", LoggerLevelStartup.Instance); Logger.LogInfo("Determining if the database is available...", "Startup");
bool dbConnected = ServerStatics.DbConnected; bool dbConnected = ServerStatics.DbConnected;
Logger.Log(dbConnected ? "Connected to the database." : "Database unavailable! Exiting.", LoggerLevelStartup.Instance); if (!dbConnected)
{
Logger.LogError("Database unavailable! Exiting.", "Startup");
}
else
{
Logger.LogSuccess("Connected to the database.", "Startup");
}
if (!dbConnected) Environment.Exit(1); if (!dbConnected) Environment.Exit(1);
using Database database = new(); using Database database = new();
Logger.Log("Migrating database...", LoggerLevelDatabase.Instance); Logger.LogInfo("Migrating database...", "Database");
MigrateDatabase(database); MigrateDatabase(database);
if (ServerSettings.Instance.InfluxEnabled) if (ServerSettings.Instance.InfluxEnabled)
{ {
Logger.Log("Influx logging is enabled. Starting influx logging...", LoggerLevelStartup.Instance); Logger.LogInfo("Influx logging is enabled. Starting influx logging...", "Startup");
InfluxHelper.StartLogging().Wait(); InfluxHelper.StartLogging().Wait();
if (ServerSettings.Instance.InfluxLoggingEnabled) Logger.AddLogger(new InfluxLogger()); if (ServerSettings.Instance.InfluxLoggingEnabled) Logger.AddLogger(new InfluxLogger());
} }
#if DEBUG Logger.LogDebug
Logger.Log
( (
"This is a debug build, so performance may suffer! " + "This is a debug build, so performance may suffer! " +
"If you are running Lighthouse in a production environment, " + "If you are running Lighthouse in a production environment, " +
"it is highly recommended to run a release build. ", "it is highly recommended to run a release build. ",
LoggerLevelStartup.Instance "Startup"
); );
Logger.Log("You can do so by running any dotnet command with the flag: \"-c Release\". ", LoggerLevelStartup.Instance); Logger.LogDebug("You can do so by running any dotnet command with the flag: \"-c Release\". ", "Startup");
#endif
if (args.Length != 0) if (args.Length != 0)
{ {
@ -72,11 +74,11 @@ public static class Program
if (ServerSettings.Instance.ConvertAssetsOnStartup) FileHelper.ConvertAllTexturesToPng(); if (ServerSettings.Instance.ConvertAssetsOnStartup) FileHelper.ConvertAllTexturesToPng();
Logger.Log("Starting room cleanup thread...", LoggerLevelStartup.Instance); Logger.LogInfo("Starting room cleanup thread...", "Startup");
RoomHelper.StartCleanupThread(); RoomHelper.StartCleanupThread();
stopwatch.Stop(); stopwatch.Stop();
Logger.Log($"Ready! Startup took {stopwatch.ElapsedMilliseconds}ms. Passing off control to ASP.NET...", LoggerLevelStartup.Instance); Logger.LogSuccess($"Ready! Startup took {stopwatch.ElapsedMilliseconds}ms. Passing off control to ASP.NET...", "Startup");
CreateHostBuilder(args).Build().Run(); CreateHostBuilder(args).Build().Run();
} }
@ -89,7 +91,7 @@ public static class Program
database.Database.MigrateAsync().Wait(); database.Database.MigrateAsync().Wait();
stopwatch.Stop(); stopwatch.Stop();
Logger.Log($"Migration took {stopwatch.ElapsedMilliseconds}ms.", LoggerLevelDatabase.Instance); Logger.LogSuccess($"Migration took {stopwatch.ElapsedMilliseconds}ms.", "Database");
} }
public static IHostBuilder CreateHostBuilder(string[] args) public static IHostBuilder CreateHostBuilder(string[] args)
@ -108,7 +110,7 @@ public static class Program
logging => logging =>
{ {
logging.ClearProviders(); logging.ClearProviders();
logging.Services.TryAddEnumerable(ServiceDescriptor.Singleton<ILoggerProvider, AspNetToKettuLoggerProvider>()); logging.Services.TryAddEnumerable(ServiceDescriptor.Singleton<ILoggerProvider, AspNetToLighthouseLoggerProvider>());
} }
); );
} }

View file

@ -17,7 +17,6 @@
<PackageReference Include="Discord.Net.Webhook" Version="3.6.1"/> <PackageReference Include="Discord.Net.Webhook" Version="3.6.1"/>
<PackageReference Include="InfluxDB.Client" Version="4.1.0"/> <PackageReference Include="InfluxDB.Client" Version="4.1.0"/>
<PackageReference Include="JetBrains.Annotations" Version="2022.1.0"/> <PackageReference Include="JetBrains.Annotations" Version="2022.1.0"/>
<PackageReference Include="Kettu" Version="1.2.4"/>
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="6.0.4"/> <PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="6.0.4"/>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="6.0.4"/> <PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="6.0.4"/>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.4"/> <PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.4"/>

View file

@ -2,7 +2,7 @@ using System;
using System.Net.Http; using System.Net.Http;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Kettu; using LBPUnion.ProjectLighthouse.Helpers.Extensions;
using LBPUnion.ProjectLighthouse.Logging; using LBPUnion.ProjectLighthouse.Logging;
using LBPUnion.ProjectLighthouse.Types.Settings; using LBPUnion.ProjectLighthouse.Types.Settings;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
@ -40,18 +40,18 @@ public class DebugWarmupLifetime : IHostLifetime
string url = ServerSettings.Instance.ServerListenUrl; string url = ServerSettings.Instance.ServerListenUrl;
url = url.Replace("0.0.0.0", "127.0.0.1"); url = url.Replace("0.0.0.0", "127.0.0.1");
Logger.Log("Warming up Hot Reload...", LoggerLevelStartup.Instance); Logger.LogDebug("Warming up Hot Reload...", "Startup");
try try
{ {
client.GetAsync(url).Wait(); client.GetAsync(url).Wait();
} }
catch(Exception e) catch(Exception e)
{ {
Logger.Log("An error occurred while attempting to warm up hot reload. Initial page load will be delayed.", LoggerLevelStartup.Instance); Logger.LogDebug("An error occurred while attempting to warm up hot reload. Initial page load will be delayed.", "Startup");
Logger.Log(e.Message, LoggerLevelStartup.Instance); Logger.LogDebug(e.ToDetailedException(), "Startup");
return; return;
} }
Logger.Log("Hot Reload is ready to go!", LoggerLevelStartup.Instance); Logger.LogSuccess("Hot Reload is ready to go!", "Startup");
} }
public Task StopAsync(CancellationToken cancellationToken) => this.consoleLifetime.StopAsync(cancellationToken); public Task StopAsync(CancellationToken cancellationToken) => this.consoleLifetime.StopAsync(cancellationToken);

View file

@ -2,7 +2,6 @@ using System;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Reflection; using System.Reflection;
using Kettu;
using LBPUnion.ProjectLighthouse.Helpers; using LBPUnion.ProjectLighthouse.Helpers;
using LBPUnion.ProjectLighthouse.Logging; using LBPUnion.ProjectLighthouse.Logging;
using LBPUnion.ProjectLighthouse.Serialization; using LBPUnion.ProjectLighthouse.Serialization;
@ -99,11 +98,11 @@ public class Startup
if (string.IsNullOrEmpty(ServerSettings.Instance.ServerDigestKey)) if (string.IsNullOrEmpty(ServerSettings.Instance.ServerDigestKey))
{ {
Logger.Log Logger.LogWarn
( (
"The serverDigestKey configuration option wasn't set, so digest headers won't be set or verified. This will also prevent LBP 1, LBP 2, and LBP Vita from working. " + "The serverDigestKey configuration option wasn't set, so digest headers won't be set or verified. This will also prevent LBP 1, LBP 2, and LBP Vita from working. " +
"To increase security, it is recommended that you find and set this variable.", "To increase security, it is recommended that you find and set this variable.",
LoggerLevelStartup.Instance "Startup"
); );
computeDigests = false; computeDigests = false;
} }
@ -142,10 +141,10 @@ public class Startup
requestStopwatch.Stop(); requestStopwatch.Stop();
Logger.Log Logger.LogInfo
( (
$"{context.Response.StatusCode}, {requestStopwatch.ElapsedMilliseconds}ms: {context.Request.Method} {context.Request.Path}{context.Request.QueryString}", $"{context.Response.StatusCode}, {requestStopwatch.ElapsedMilliseconds}ms: {context.Request.Method} {context.Request.Path}{context.Request.QueryString}",
LoggerLevelHttp.Instance "HTTP"
); );
#if DEBUG #if DEBUG
@ -153,7 +152,7 @@ public class Startup
if (context.Request.Method == "POST") if (context.Request.Method == "POST")
{ {
context.Request.Body.Position = 0; context.Request.Body.Position = 0;
Logger.Log(await new StreamReader(context.Request.Body).ReadToEndAsync(), LoggerLevelHttp.Instance); Logger.LogDebug(await new StreamReader(context.Request.Body).ReadToEndAsync(), "HTTP");
} }
#endif #endif
} }

View file

@ -1,7 +1,6 @@
#nullable enable #nullable enable
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using Kettu;
using LBPUnion.ProjectLighthouse.Logging; using LBPUnion.ProjectLighthouse.Logging;
using LBPUnion.ProjectLighthouse.Serialization; using LBPUnion.ProjectLighthouse.Serialization;
using LBPUnion.ProjectLighthouse.Types.Levels; using LBPUnion.ProjectLighthouse.Types.Levels;
@ -14,7 +13,7 @@ public abstract class CategoryWithUser : Category
public override Slot? GetPreviewSlot(Database database) public override Slot? GetPreviewSlot(Database database)
{ {
#if DEBUG #if DEBUG
Logger.Log("tried to get preview slot without user on CategoryWithUser", LoggerLevelCategory.Instance); Logger.LogError("tried to get preview slot without user on CategoryWithUser", "Category");
if (Debugger.IsAttached) Debugger.Break(); if (Debugger.IsAttached) Debugger.Break();
#endif #endif
return null; return null;
@ -24,7 +23,7 @@ public abstract class CategoryWithUser : Category
public override int GetTotalSlots(Database database) public override int GetTotalSlots(Database database)
{ {
#if DEBUG #if DEBUG
Logger.Log("tried to get total slots without user on CategoryWithUser", LoggerLevelCategory.Instance); Logger.LogError("tried to get total slots without user on CategoryWithUser", "Category");
if (Debugger.IsAttached) Debugger.Break(); if (Debugger.IsAttached) Debugger.Break();
#endif #endif
return -1; return -1;
@ -34,7 +33,7 @@ public abstract class CategoryWithUser : Category
public override IEnumerable<Slot> GetSlots(Database database, int pageStart, int pageSize) public override IEnumerable<Slot> GetSlots(Database database, int pageStart, int pageSize)
{ {
#if DEBUG #if DEBUG
Logger.Log("tried to get slots without user on CategoryWithUser", LoggerLevelCategory.Instance); Logger.LogError("tried to get slots without user on CategoryWithUser", "Category");
if (Debugger.IsAttached) Debugger.Break(); if (Debugger.IsAttached) Debugger.Break();
#endif #endif
return new List<Slot>(); return new List<Slot>();
@ -42,7 +41,7 @@ public abstract class CategoryWithUser : Category
public new string Serialize(Database database) public new string Serialize(Database database)
{ {
Logger.Log("tried to serialize without user on CategoryWithUser", LoggerLevelCategory.Instance); Logger.LogError("tried to serialize without user on CategoryWithUser", "Category");
return string.Empty; return string.Empty;
} }

View file

@ -4,7 +4,6 @@ using System.IO;
using System.Text.Json; using System.Text.Json;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using JetBrains.Annotations; using JetBrains.Annotations;
using Kettu;
using LBPUnion.ProjectLighthouse.Logging; using LBPUnion.ProjectLighthouse.Logging;
namespace LBPUnion.ProjectLighthouse.Types.Settings; namespace LBPUnion.ProjectLighthouse.Types.Settings;
@ -20,7 +19,7 @@ public class ServerSettings
{ {
if (ServerStatics.IsUnitTesting) return; // Unit testing, we don't want to read configurations here since the tests will provide their own if (ServerStatics.IsUnitTesting) return; // Unit testing, we don't want to read configurations here since the tests will provide their own
Logger.Log("Loading config...", LoggerLevelConfig.Instance); Logger.LogInfo("Loading config...", "Config");
if (File.Exists(ConfigFileName)) if (File.Exists(ConfigFileName))
{ {
@ -30,7 +29,7 @@ public class ServerSettings
if (Instance.ConfigVersion < CurrentConfigVersion) if (Instance.ConfigVersion < CurrentConfigVersion)
{ {
Logger.Log($"Upgrading config file from version {Instance.ConfigVersion} to version {CurrentConfigVersion}", LoggerLevelConfig.Instance); Logger.LogInfo($"Upgrading config file from version {Instance.ConfigVersion} to version {CurrentConfigVersion}", "Config");
Instance.ConfigVersion = CurrentConfigVersion; Instance.ConfigVersion = CurrentConfigVersion;
configFile = JsonSerializer.Serialize configFile = JsonSerializer.Serialize
( (
@ -59,12 +58,12 @@ public class ServerSettings
File.WriteAllText(ConfigFileName, configFile); File.WriteAllText(ConfigFileName, configFile);
Logger.Log Logger.LogWarn
( (
"The configuration file was not found. " + "The configuration file was not found. " +
"A blank configuration file has been created for you at " + "A blank configuration file has been created for you at " +
$"{Path.Combine(Environment.CurrentDirectory, ConfigFileName)}", $"{Path.Combine(Environment.CurrentDirectory, ConfigFileName)}",
LoggerLevelConfig.Instance "Config"
); );
Environment.Exit(1); Environment.Exit(1);
@ -73,7 +72,7 @@ public class ServerSettings
// Set up reloading // Set up reloading
if (Instance.ConfigReloading) if (Instance.ConfigReloading)
{ {
Logger.Log("Setting up config reloading...", LoggerLevelConfig.Instance); Logger.LogInfo("Setting up config reloading...", "Config");
fileWatcher = new FileSystemWatcher fileWatcher = new FileSystemWatcher
{ {
Path = Environment.CurrentDirectory, Path = Environment.CurrentDirectory,
@ -90,8 +89,8 @@ public class ServerSettings
private static void onConfigChanged(object sender, FileSystemEventArgs e) private static void onConfigChanged(object sender, FileSystemEventArgs e)
{ {
Debug.Assert(e.Name == ConfigFileName); Debug.Assert(e.Name == ConfigFileName);
Logger.Log("Configuration file modified, reloading config.", LoggerLevelConfig.Instance); Logger.LogInfo("Configuration file modified, reloading config.", "Config");
Logger.Log("Some changes may not apply, in which case may require a restart of Project Lighthouse.", LoggerLevelConfig.Instance); Logger.LogWarn("Some changes may not apply, in which case may require a restart of Project Lighthouse.", "Config");
string configFile = File.ReadAllText(ConfigFileName); string configFile = File.ReadAllText(ConfigFileName);
Instance = JsonSerializer.Deserialize<ServerSettings>(configFile) ?? throw new ArgumentNullException(nameof(ConfigFileName)); Instance = JsonSerializer.Deserialize<ServerSettings>(configFile) ?? throw new ArgumentNullException(nameof(ConfigFileName));

View file

@ -1,7 +1,6 @@
#nullable enable #nullable enable
using System; using System;
using System.Linq; using System.Linq;
using Kettu;
using LBPUnion.ProjectLighthouse.Logging; using LBPUnion.ProjectLighthouse.Logging;
namespace LBPUnion.ProjectLighthouse.Types.Settings; namespace LBPUnion.ProjectLighthouse.Types.Settings;
@ -20,7 +19,7 @@ public static class ServerStatics
} }
catch(Exception e) catch(Exception e)
{ {
Logger.Log(e.ToString(), LoggerLevelDatabase.Instance); Logger.LogError(e.ToString(), "Database");
return false; return false;
} }
} }

View file

@ -3,7 +3,6 @@ using System;
using System.IO; using System.IO;
using System.Text; using System.Text;
using System.Text.Json; using System.Text.Json;
using Kettu;
using LBPUnion.ProjectLighthouse.Helpers; using LBPUnion.ProjectLighthouse.Helpers;
using LBPUnion.ProjectLighthouse.Helpers.Extensions; using LBPUnion.ProjectLighthouse.Helpers.Extensions;
using LBPUnion.ProjectLighthouse.Logging; using LBPUnion.ProjectLighthouse.Logging;
@ -93,12 +92,8 @@ public class NPTicket
reader.ReadUInt16BE(); // Ticket length, we don't care about this reader.ReadUInt16BE(); // Ticket length, we don't care about this
#if DEBUG
SectionHeader bodyHeader = reader.ReadSectionHeader(); SectionHeader bodyHeader = reader.ReadSectionHeader();
Logger.Log($"bodyHeader.Type is {bodyHeader.Type}", LoggerLevelLogin.Instance); Logger.LogDebug($"bodyHeader.Type is {bodyHeader.Type}", "Login");
#else
reader.ReadSectionHeader();
#endif
switch (npTicket.ticketVersion) switch (npTicket.ticketVersion)
{ {
@ -120,15 +115,13 @@ public class NPTicket
npTicket.titleId = npTicket.titleId.Substring(0, npTicket.titleId.Length - 3); // Trim _00 at the end npTicket.titleId = npTicket.titleId.Substring(0, npTicket.titleId.Length - 3); // Trim _00 at the end
// Data now (hopefully): BCUS98245 // Data now (hopefully): BCUS98245
#if DEBUG Logger.LogDebug($"titleId is {npTicket.titleId}", "Login");
Logger.Log($"titleId is {npTicket.titleId}", LoggerLevelLogin.Instance);
#endif
npTicket.GameVersion = GameVersionHelper.FromTitleId(npTicket.titleId); // Finally, convert it to GameVersion npTicket.GameVersion = GameVersionHelper.FromTitleId(npTicket.titleId); // Finally, convert it to GameVersion
if (npTicket.GameVersion == GameVersion.Unknown) if (npTicket.GameVersion == GameVersion.Unknown)
{ {
Logger.Log($"Could not determine game version from title id {npTicket.titleId}", LoggerLevelLogin.Instance); Logger.LogWarn($"Could not determine game version from title id {npTicket.titleId}", "Login");
return null; return null;
} }
@ -145,45 +138,34 @@ public class NPTicket
if (npTicket.Platform == Platform.Unknown) if (npTicket.Platform == Platform.Unknown)
{ {
Logger.Log($"Could not determine platform from IssuerId {npTicket.IssuerId} decimal", LoggerLevelLogin.Instance); Logger.LogWarn($"Could not determine platform from IssuerId {npTicket.IssuerId} decimal", "Login");
return null; return null;
} }
#if DEBUG #if DEBUG
Logger.Log("npTicket data:", LoggerLevelLogin.Instance); Logger.LogDebug("npTicket data:", "Login");
foreach (string line in JsonSerializer.Serialize(npTicket).Split('\n')) Logger.LogDebug(JsonSerializer.Serialize(npTicket), "Login");
{
Logger.Log(line, LoggerLevelLogin.Instance);
}
#endif #endif
return npTicket; return npTicket;
} }
catch(NotImplementedException) catch(NotImplementedException)
{ {
Logger.Log($"The ticket version {npTicket.ticketVersion} is not implemented yet.", LoggerLevelLogin.Instance); Logger.LogError($"The ticket version {npTicket.ticketVersion} is not implemented yet.", "Login");
Logger.Log Logger.LogError
( (
"Please let us know that this is a ticket version that is actually used on our issue tracker at https://github.com/LBPUnion/project-lighthouse/issues !", "Please let us know that this is a ticket version that is actually used on our issue tracker at https://github.com/LBPUnion/project-lighthouse/issues !",
LoggerLevelLogin.Instance "Login"
); );
return null; return null;
} }
catch(Exception e) catch(Exception e)
{ {
Logger.Log("Failed to read npTicket!", LoggerLevelLogin.Instance); Logger.LogError("Failed to read npTicket!", "Login");
Logger.Log("Either this is spam data, or the more likely that this is a bug.", LoggerLevelLogin.Instance); Logger.LogError("Either this is spam data, or the more likely that this is a bug.", "Login");
Logger.Log Logger.LogError("Please report the following exception to our issue tracker at https://github.com/LBPUnion/project-lighthouse/issues!", "Login");
( Logger.LogError(e.ToDetailedException(), "Login");
"Please report the following exception to our issue tracker at https://github.com/LBPUnion/project-lighthouse/issues!",
LoggerLevelLogin.Instance
);
foreach (string line in e.ToDetailedException().Split('\n'))
{
Logger.Log(line, LoggerLevelLogin.Instance);
}
return null; return null;
} }
} }